pythoncryptographyaespycrypto

Decrypt Kamstrup WMBUS in Python


I have a Kamstrup WMbus water meter sending out frames like this: 21442D2C529027581B168D2814900939201F0775C6452FBBAC155B46A546035219D51AB8

I am trying to decrypt this in Python.

Breaking the frame up I have the following values:

Pasting this into http://www.cryptogrium.com/aes-ctr.html results in a valid decrypted frame: bbe57934ddc46a71004400000044000000

I have tried both PyCrypto and PyCryptodome but neither gives the same correct answer than cryptogrium.com.

from Cryptodome.Cipher import AES

# ctr = Crypto.Util.Counter.new(128, initial_value=int("0000002039099028161B582790522C2D", 16))

# cipher = Crypto.Cipher.AES.new(ecryptionKey, Crypto.Cipher.AES.MODE_CTR, counter=ctr)

# secret = Secret()
spec = AES.new(ecryptionKey, AES.MODE_CTR, iv=inputIV)
dataDec = cipher.decrypt(data)

The first commented out approach runs but gives the wrong result. The second one stops with the error:

TypeError: Invalid parameters for CTR mode: {'iv': bytearray(b"-,R\x90\'X\x1b\x16(\x90\t9 \x00\x00\x00")}

In C# we are using the following which works:

IBufferedCipher cipher = CipherUtilities.GetCipher("AES/CTR/NoPadding");
ParametersWithIV ivAndKey = new ParametersWithIV(new KeyParameter(keyBytes), inputIVBytes);
cipher.Init(false, ivAndKey);
...
int length1 = cipher.ProcessBytes(data, 0, data.Length, outBuf, 0);
int length2 = cipher.DoFinal(outBuf, length1);
...

I am confused because C# uses the parameters I have: key, data, IV But Python expects: key, data, counter

Does anyone have an example how I can decrypt this in Python3? Or maybe explain how I should use the IV to set up the counter for AES-CNT?


Solution

  • In the end one of the examples from https://www.programcreek.com/python/example/87998/Crypto.Cipher.AES.MODE_CTR put me on the right track. After fixing a couple of typos in my code it worked correctly.

    def kamstrupDecrypt(meterSerial, frame, payload):
      inputIV = getInputIV(frame)
      print("IV:", binascii.hexlify(inputIV))
      ecryptionKey = getEncryptionKey(meterSerial)
      print("Key:", binascii.hexlify(ecryptionKey))
    
      counter = Counter.new(128, initial_value = bytes_to_long(inputIV))
      cipher = AES.new(ecryptionKey, AES.MODE_CTR, counter=counter)
      payloadDec = cipher.decrypt(payload)
    
      print("Decrypted: ", binascii.hexlify(payloadDec))
    
      return payloadDec