在Python中使用paramiko生成SSH密钥对
我正在尝试使用Python的paramiko模块生成SSH密钥对。关于密钥生成的信息似乎不多。我看过paramiko的文档,但还是搞不清楚哪里出了问题。我可以生成没有密码加密的私钥和公钥。但是,当我尝试加密私钥时,出现了以下错误。
ValueError: IV必须是8个字节长
我认为这个错误是来自pycrypto。我查看了paramiko.pkey和pycrypto中的相关代码,但没有找到解决办法。
这里有一个小例子。
import paramiko
def keygen(filename,passwd=None,bits=1024):
k = paramiko.RSAKey.generate(bits)
#This line throws the error.
k.write_private_key_file(filename,password = 'cleverpassword')
o = open(fil+'.pub' ,"w").write(k.get_base64())
错误追踪信息
Traceback (most recent call last): File "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Documents/test.py", line 14, in keygen k.write_private_key_file(filename,password = 'cleverpassword') File "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/paramiko/rsakey.py", line 127, in write_private_key_file self._write_private_key_file('RSA', filename, self._encode_key(), password) File "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/paramiko/pkey.py", line 323, in _write_private_key_file self._write_private_key(tag, f, data, password) File "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/paramiko/pkey.py", line 341, in _write_private_key data = cipher.new(key, mode, salt).encrypt(data) File "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/Crypto/Cipher/DES3.py", line 114, in new return DES3Cipher(key, *args, **kwargs) File "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/Crypto/Cipher/DES3.py", line 76, in __init__ blockalgo.BlockAlgo.__init__(self, _DES3, key, *args, **kwargs) File "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/Crypto/Cipher/blockalgo.py", line 141, in __init__ self._cipher = factory.new(key, *args, **kwargs) ValueError: IV must be 8 bytes long
1 个回答
4
问题
这看起来是 paramiko
里的一个错误。
如果你查看 pkey.py
中引发错误的那一行,它是下面这一行:
data = cipher.new(key, mode, salt).encrypt(data)
现在我们来看它之前的几行,这些行通过先选择一个 cipher_name
来设置 mode
。
# since we only support one cipher here, use it
cipher_name = list(self._CIPHER_TABLE.keys())[0]
cipher = self._CIPHER_TABLE[cipher_name]['cipher']
keysize = self._CIPHER_TABLE[cipher_name]['keysize']
blocksize = self._CIPHER_TABLE[cipher_name]['blocksize']
mode = self._CIPHER_TABLE[cipher_name]['mode']
这里是 _CIPHER_TABLE
的内容。
_CIPHER_TABLE = {
'AES-128-CBC': {'cipher': AES, 'keysize': 16, 'blocksize': 16, 'mode': AES.MODE_CBC},
'DES-EDE3-CBC': {'cipher': DES3, 'keysize': 24, 'blocksize': 8, 'mode': DES3.MODE_CBC},
}
注意一下,注释和代码之间存在矛盾。可用的加密方式有两个,而上面选择 cipher_name
的那一行假设只有一个。
根据错误信息,似乎选择的是 'DES-EDE3-CBC'
。如果我们查看 DES3.py
中的注释,会看到对 IV 的要求。
IV : byte string
The initialization vector to use for encryption or decryption.
It is ignored for `MODE_ECB` and `MODE_CTR`.
For `MODE_OPENPGP`, IV must be `block_size` bytes long for encryption
and `block_size` +2 bytes for decryption (in the latter case, it is
actually the *encrypted* IV which was prefixed to the ciphertext).
It is mandatory.
从 paramiko 的源代码中,我们发现没有传递 IV
,因此出现了我们看到的错误。
解决方法
将 pkey.py
中的以下一行修改为硬编码 'AES-128-CBC'
加密方式。
# cipher_name = list(self._CIPHER_TABLE.keys())[1]
cipher_name = 'AES-128-CBC'