Генерация пары ключей SSH с помощью paramiko в Python

#python #python-2.7 #paramiko

#python #python-2.7 #paramiko

Вопрос:

Я пытаюсь сгенерировать пару ключей SSH с помощью модуля python paramiko. Похоже, что информации о генерации ключей не так много. Я прочитал документы 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())
 

трассировка

Трассировка (последний последний вызов):
 Файл "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Documents/test.py ", строка 14, в
ключевом файле k.write_private_key_file(имя файла, пароль = 'cleverpassword')
 Файл "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/paramiko/rsakey.py" , строка 127, в файле
write_private_key_file self._write_private_key_file('RSA', имя файла, self._encode_key(), пароль)
 Файл "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/paramiko/pkey.py" , строка 323, в _write_private_key_file
self._write_private_key(тег, f, данные, пароль)
 Файл "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/paramiko/pkey.py" , строка 341, в _write_private_key
data = cipher.new(ключ, режим, соль).шифрование (данных)
 Файл "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/Crypto/Cipher/DES3.py" , строка 114, в новом
возвращаемом DES3Cipher(ключ, * аргументы, **kwargs)
 Файл "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/Crypto/Cipher/DES3.py" , строка 76, в __init__
 блокировка.Блокировка.__init__(self, _DES3, key, * аргументы, ** kwargs)
 Файл "/var/mobile/Applications/149E4C21-2F92-4712-BAC6-151A171C6687/Pythonista.app/pylib/site-packages/Crypto/Cipher/blockalgo.py" , строка 141, в __init__
 self._cipher = factory.new(ключ, * аргументы, ** kwargs)
Ошибка ValueError: IV должен иметь длину 8 байт

Комментарии:

1. Можете ли вы показать полную обратную трассировку исключения?

Ответ №1:

Проблема

Это похоже на ошибку внутри paramiko .

Если вы посмотрите на строку , в которой была вызвана ошибка pkey.py , это будет следующая строка:

         data = cipher.new(key, mode, salt).encrypt(data)
 

Давайте теперь посмотрим на строки перед ним, которые устанавливают значение mode , сначала выбрав a cipher_name .

         # 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 мы видим, что no IV передается, и, следовательно, ошибка, которую мы видели.

Обходной путь

Измените следующую строку, pkey.py чтобы 'AES-128-CBC' вместо этого жестко закодировать шифр.

    # cipher_name = list(self._CIPHER_TABLE.keys())[1]
   cipher_name = 'AES-128-CBC'
 

Комментарии:

1. Большое вам спасибо. Прогулка по вашему мыслительному процессу была очень полезной!