Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating SSH keypair with paramiko in Python

I am trying to generate a SSH key pair with the python module paramiko. There doesn't seem to be much info about key generation. I've read through the paramiko docs but can't figure out whats wrong. I can generate a private and public key without password encryption. However, when I try to encrypt the private key I get the following error.

ValueError: IV must be 8 bytes long

I believe the above error is from pycrypto. I've looked through the relevant code in paramiko.pkey and pycrypto without any luck.

Here is a small example.

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

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
like image 905
briarfox Avatar asked Jun 28 '14 04:06

briarfox


People also ask

How do I generate SSH key automatically?

Generating a SSH keyNavigate to the Triton Portal and open the Account Summary. From the SSH section, select Create SSH Key. In the Create SSH Key dialog, enter a Key Name and then select Create Key. The private and public SSH key pairs generate.

How do I use Paramiko in Python?

So, we have created a client object “ssh” of “SSHClient” with the paramiko package. This object calls the automatic policy function of adding unknown keys to perform SSH to remote host servers via the paramiko package. The same object is used to connect the client machine with the host server via the host credentials.

Which command is used to generate key pairs SSH?

Run ssh-keygen to generate an SSH key-pair. Retrieve the public key file. Provide the public key file (for example, id_rsa. pub) to your server administrator so that it can be set up for your server connection.


1 Answers

The Problem

This looks like a bug in paramiko.

If you look at the line that threw the error in pkey.py, it is the following line:

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

Let us now look at the lines before it, which set the mode by first selecting 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']

Here are the contents of _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},
}

Observe how the comment contradicts the code. Two ciphers are available, and the line above which selects the cipher_name assumes there is only one.

Based on the error, it appears that 'DES-EDE3-CBC' is selected. If we look at the comment in DES3.py, we see the following requirement for an 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.

From paramiko's source, we observe that no IV is passed, and hence the error we saw.

Workaround

Change the following line in pkey.py to hardcode the 'AES-128-CBC' cipher instead.

   # cipher_name = list(self._CIPHER_TABLE.keys())[1]
   cipher_name = 'AES-128-CBC'
like image 187
merlin2011 Avatar answered Oct 17 '22 23:10

merlin2011