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
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'
Related
Can someone help me with this problem:
I am encrypting a JSON in NiFi with AES_GCM algorithm and using a KDF PBKDF2. The idea is to decrypt this JSON with a python script using PyCryptodome.
The following code is an attempt to see if the NiFi encrypted message can be decrypted:
import base64
from Crypto.Protocol.KDF import PBKDF2
from Crypto.Cipher import AES
# Key used in NiFi to encrypt the JSON
key = '-JaNcRfUjXn2r5u8'
# Result value after the EncryptContent processor encrypts
# the JSON: {"id":"123", "name":"Ronald"}
value = 'nTJuV9l9uQJrWv2HXD37PE5pRmlTQUxUg7ir0oDxuxSnmuqZpbUfVk5pRmlJVn1yT10SdXKjobe9o/QHybJqwhPgCifGz2yiY9JICGehICb/zEsYUivERcMKhg=='
decodeValue = base64.b64decode(value)
salt = decodeValue[:16]
IV = decodeValue[24:40]
dataToDecrypt = decodeValue[46:-16]
tag = decodeValue[-16:]
mainKey = PBKDF2(key, salt)
cipher = AES.new(mainKey, AES.MODE_GCM, IV)
cipher.update(salt)
decryptedData = cipher.decrypt_and_verify(dataToDecrypt, tag)
print(decryptedData)
I understand that in NiFi with NIFI_PBKDF2_AES_GCM_128 encryption the cipher text output consists of the salt (16-byte length), followed by the salt delimiter, UTF-8 string “NiFiSALT” (0x4E 69 46 69 53 41 4C 54) and then the IV, followed by the IV delimiter, UTF-8 string “NiFiIV” (0x4E 69 46 69 49 56), followed by the cipher text, followed by the autehnticaion tag (16-byte length), but when trying to run the above script using this structure, I get the following error:
Traceback (most recent call last):
File "/home/ronald/anaconda3/envs/Quind/lib/python3.10/code.py", line 90, in runcode
exec(code, self.locals)
File "<input>", line 4, in <module>
File "/home/ronald/anaconda3/envs/Quind/lib/python3.10/site-packages/Crypto/Cipher/_mode_gcm.py", line 567, in decrypt_and_verify
self.verify(received_mac_tag)
File "/home/ronald/anaconda3/envs/Quind/lib/python3.10/site-packages/Crypto/Cipher/_mode_gcm.py", line 508, in verify
raise ValueError("MAC check failed")
ValueError: MAC check failed
I don't understand why the authentication tag check fails.
Decryption fails for two reasons:
For PBKDF2 neither the iteration count nor the digest are explicitly specified, so the default values 1000 and SHA1 are used. However, the values to be applied are 160000 and SHA512 according to the documentation:
from Crypto.Hash import SHA512
...
mainKey = PBKDF2(key, salt, count=160000, hmac_hash_module=SHA512)
The salt is not authenticated, i.e. the line cipher.update(salt) must be removed.
With these changes, authentication and decryption is successful and decryptedData is b'{"id": "123", "name": "Ronald"}'.
Note that for GCM the length 16 bytes is allowed for the nonce/IV, but the recommended length is 12 bytes. But maybe a change is beyond your control.
I'm new to python and I'm trying to loop through all 255 addresses to locate a specific bit of hardware over RS485. The hardware is attached, and it's address is supposed to be 0x25, but this is not the case, so I need to find what its address is.
So far I've got:
def Init_Sync_4 ():
GPIO.output(18,GPIO.HIGH)
ser.write([CID,0x17,0x20,0x01,0x14,0x1c,0x04,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x01,0x00,0x00,0x00,0x32,0x00,0x02,0x00,0x00,0$
time.sleep(0.007)
GPIO.output(18,GPIO.LOW)
and
ser=serial.Serial(port='/dev/serial0',baudrate=38400,stopbits=2,timeout=1)
GPIO.setmode(GPIO.BCM)
GPIO.setup(18,GPIO.OUT)
GPIO.output(18,GPIO.LOW)
for i in range(0xff):
CID = '0x{:02x}'.format(i).encode('ascii')
print "at address %s" % CID
Init_Sync_4()
time.sleep(0.05)
Init_2()
time.sleep(0.05)
Here CID is the address being built, which Init_Sync_4() uses in it's byte array in ser.write, but I keep getting the error:
at address 0x00
Traceback (most recent call last):
File "rs485_test_2.py", line 97, in <module>
Init_4()
File "rs485_test_2.py", line 40, in Init_4
ser.write([CID,0x17,0x20,0x01,0x14,0x1c,0x04,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x01,0x00,0x00,0x00,0x32,0x00,0x02,0x00,0x00,0x00,0x00])
File "/usr/lib/python2.7/dist-packages/serial/serialposix.py", line 518, in write
d = to_bytes(data)
File "/usr/lib/python2.7/dist-packages/serial/serialutil.py", line 66, in to_bytes
return bytes(bytearray(seq))
ValueError: string must be of size 1
I'm assuming that it's still being passed as a string, when it needs to be a single byte, but I'm lost at how the conversion would work. I've checked out some SO pages, that specify using .encode with or without params, but I'm either using it incorrectly, or it's not quite what I'm after. Any help is greatly appreciated! Thanks.
ser.write([CID,0x17,0x20,0x01, ...
CID is going into a list with a bunch of integers. But itself is a string.
You want to leave CID as an integer.
# CID = '0x{:02x}'.format(i).encode('ascii')
CID = i
I am working on an encryption program with Pycryptodome in Python 3. I am trying to encrypt a (byte) string and then decrypt it and verify the MAC tag. When I get to verify it, an error is thrown.
This is the code:
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
aes_key = get_random_bytes(24)
aes_cipher = AES.new(aes_key, AES.MODE_GCM)
encrypted, MACtag = aes_cipher.encrypt_and_digest(b"A random thirty two byte string.")
# Imagine this is happening somewhere else
new_aes_cipher = AES.new(aes_key, AES.MODE_GCM, nonce=aes_cipher.nonce)
new_aes_cipher.verify(MACtag)
decrypted = new_aes_cipher.decrypt(encrypted)
And this is the error:
Traceback (most recent call last):
File "aespractice.py", line 10, in <module>
new_aes_cipher.verify(tag)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-
packages/Crypto/Cipher/_mode_gcm.py", line 441, in verify
raise ValueError("MAC check failed")
ValueError: MAC check failed
I've looked at the documentation, and I it looks to me like everything is all right. Why do you think the program is acting this way? Any help would be appreciated.
If you look at the state diagram for authenticated modes:
You see that verify() should be called at the very end, after any decrypt() has taken place.
So, either you invert the calls or you replace them with a combined decrypt_and_verify().
I managed to read generic module value with cocotb without problem. But if I can't manage to write it.
My VHDL generic is :
...
generic (
...
C_M00_AXI_BURST_LEN : integer := 16;
...
)
I can read it in cocotb:
self.dut.log.info("C_M00_AXI_BURST_LEN 0x{:x}".format(
int(self.dut.c_m00_axi_burst_len)))
But if I try to change it :
self.dut.c_m00_axi_burst_len = 32
I get this python error :
Send raised exception: Not permissible to set values on object c_m00_axi_burst_len
File "/opt/cocotb/cocotb/decorators.py", line 197, in send
return self._coro.send(value)
File "/usr/local/projects/axi_pattern_tester/vivado_ip/axi_pattern_tester_1.0/cocotb/test_axi_pattern_tester_v1_0.py", line 165, in axi4_master_test
dutest.print_master_generics()
File "/usr/local/projects/axi_pattern_tester/vivado_ip/axi_pattern_tester_1.0/cocotb/test_axi_pattern_tester_v1_0.py", line 86, in print_master_generics
self.dut.c_m00_axi_burst_len = 32
File "/opt/cocotb/cocotb/handle.py", line 239, in __setattr__
return getattr(self, name)._setcachedvalue(value)
File "/opt/cocotb/cocotb/handle.py", line 378, in _setcachedvalue
raise TypeError("Not permissible to set values on object %s" % (self._name))
Is there a way to do it using GHDL as simulator ?
In fact, user1155120, Paebbels and scary_jeff respond to the question : It's not possible.
But it's possible to use configuration differently to solve this problem. VHDL Generic value can be configured in Makefile adding "-g" option to SIM_ARGS parameter :
SIM_ARGS+=-gC_M00_AXI_BURST_LEN=16
This value can then be read under cocotb "dut" object like any others signal and used as simulation parameter :
C_M00_AXI_BURST_LEN = int(dut.C_M00_AXI_BURST_LEN.value)
I'm trying to make a simple program to check and show unread messages, but I have problem while trying to get subject and sender adress.
For sender I've tried this method:
import email
m = server.fetch([a], ['RFC822'])
#a is variable with email id
msg = email.message_from_string(m[a], ['RFC822'])
print msg['from']
from email.utils import parseaddr
print parseaddr(msg['from'])
But it didn't work. I was getting this error:
Traceback (most recent call last):
File "C:/Users/ExampleUser/AppData/Local/Programs/Python/Python35-32/myprogram.py", line 20, in <module>
msg = email.message_from_string(m[a], ['RFC822'])
File "C:\Users\ExampleUser\AppData\Local\Programs\Python\Python35-32\lib\email\__init__.py", line 38, in message_from_string
return Parser(*args, **kws).parsestr(s)
File "C:\Users\ExampleUser\AppData\Local\Programs\Python\Python35-32\lib\email\parser.py", line 68, in parsestr
return self.parse(StringIO(text), headersonly=headersonly)
TypeError: initial_value must be str or None, not dict
I also used this:
print(server.fetch([a], ['BODY[HEADER.FIELDS (FROM)]']))
but the result was like:
defaultdict(<class 'dict'>, {410: {b'BODY[HEADER.FIELDS ("FROM")]': b'From: "=?utf-8?q?senderexample?=" <sender#example.com>\r\n\r\n', b'SEQ': 357}, 357: {b'SEQ': 357, b'FLAGS': (b'\\Seen',)}})
Is there a way to repair the first method, or make the result of second look like:
Sender Example <sender#example.com>
?
And I also don't know how to get email subject. But I guess it's the same as sender, but with other arguments. So the only thing I need are these arguments.
You should start by reviewing various IMAP libraries which are available for Python and use one which fits your needs. There are multiple ways of fetching the data you need in IMAP (the protocol), and by extension also in Python (and its libraries).
For example, the most straightforward way of getting the data you need in IMAP the protocol is through fetching the ENVELOPE object. You will still have to perform decoding of RFC2047 encoding of the non-ASCII data (that's that =?utf-8?q?... bit that you're seeing), but at least it would save you from parsing RFC5322 header structure with multiple decades of compatibility syntax rules.