From 009a51d6dbf376d9c955cb4d7967dcf8d6a53306 Mon Sep 17 00:00:00 2001 From: BIBOLV <49994376+BIBOLV@users.noreply.github.com> Date: Thu, 6 Apr 2023 22:27:20 +0300 Subject: [PATCH 1/3] Update kem import script Switch pycrypto package to cryptography and add possibility to process also kem2 files --- utils/kem-import.py | 74 ++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/utils/kem-import.py b/utils/kem-import.py index 42340b5..c252fee 100644 --- a/utils/kem-import.py +++ b/utils/kem-import.py @@ -27,9 +27,12 @@ import re import errno import argparse import base64 -import Crypto.Cipher.AES as AES -from xml.dom import minidom import zipfile +from xml.dom import minidom +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.backends import default_backend + + help_prog = "Decrypts Kamstrup KEM file and imports meter information into wmbusmeters' config folder." help_epilog = "" @@ -74,7 +77,7 @@ if (zipfile.is_zipfile(args.kem_file)): with zipfile.ZipFile(args.kem_file,'r') as zipobj: file_list = zipobj.namelist() for file_name in file_list: - if file_name.endswith('.kem'): + if file_name.endswith('.kem') or file_name.endswith('.kem2'): kem_file_content = zipobj.read(file_name) break #end if @@ -109,12 +112,20 @@ key = bytes(str(args.password).encode("utf-8")) if (len(key) < 16): key += (16-len(key)) * b"\0" # content decryption -aes = AES.new(key, AES.MODE_CBC, IV=key) -decryptedtext = aes.decrypt(encrypeddata) +backend = default_backend() +cipher = Cipher(algorithms.AES(key), modes.CBC(key), backend=backend) +decryptor = cipher.decryptor() +decryptedtext = decryptor.update(encrypeddata) + decryptor.finalize() + +try: + decodedtext = decryptedtext.decode('utf-8') +except UnicodeDecodeError: + print("ERROR: Looks like password is wrong - decryption failed!") + sys.exit(1) # save decrypted XML file if requested if (args.output): - f = open(args.output, 'w') + f = open(args.output, 'wb') f.write(decryptedtext) f.close() #end if @@ -134,22 +145,7 @@ if (not args.dryrun) and (not os.path.exists(args.config)): raise #end if - -# parse the decrypted KEM file content and create corresponding meter files in -# wmbusmeters' config folder for each meter found in the XML file -trimmedText = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff]', '', decryptedtext.decode('utf-8')) -xmldoc = minidom.parseString(trimmedText) -for e in xmldoc.getElementsByTagName('Meter'): - # read information from source XML file - meterName = e.getElementsByTagName('MeterName')[0].firstChild.nodeValue - meterType = e.getElementsByTagName('ConsumptionType')[0].firstChild.nodeValue - meterNum = e.getElementsByTagName('MeterNo')[0].firstChild.nodeValue - meterSerial = e.getElementsByTagName('SerialNo')[0].firstChild.nodeValue - meterVendor = e.getElementsByTagName('VendorId')[0].firstChild.nodeValue - meterConfig = e.getElementsByTagName('ConfigNo')[0].firstChild.nodeValue - meterModel = e.getElementsByTagName('TypeNo')[0].firstChild.nodeValue - meterKey = e.getElementsByTagName('DEK')[0].firstChild.nodeValue - +def print_meter(meterName,meterType,meterNum,meterSerial,meterVendor,meterConfig,meterModel,meterKey): # meter model identification # CONTRIBUTING NOTE: additional meter types supported by wmbusmeters can be put here # if their identification in KEM file is known @@ -167,7 +163,7 @@ for e in xmldoc.getElementsByTagName('Meter'): wmbusmeters_driver = 'flowiq2200' else: wmbusmeters_driver = None - + # print info to console print('Found meter', meterName, '('+meterModel+')') print(' number :', meterNum) @@ -200,4 +196,34 @@ for e in xmldoc.getElementsByTagName('Meter'): #end if #end for - +# parse the decrypted KEM file content and create corresponding meter files in +# wmbusmeters' config folder for each meter found in the XML file +trimmedText = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\xff]', '', decryptedtext.decode('utf-8')) +xmldoc = minidom.parseString(trimmedText) +if xmldoc.documentElement.tagName == "MetersInOrder": + for e in xmldoc.getElementsByTagName('Meter'): + # read information from source XML file + meterName = e.getElementsByTagName('MeterName')[0].firstChild.nodeValue + meterType = e.getElementsByTagName('ConsumptionType')[0].firstChild.nodeValue + meterNum = e.getElementsByTagName('MeterNo')[0].firstChild.nodeValue + meterSerial = e.getElementsByTagName('SerialNo')[0].firstChild.nodeValue + meterVendor = e.getElementsByTagName('VendorId')[0].firstChild.nodeValue + meterConfig = e.getElementsByTagName('ConfigNo')[0].firstChild.nodeValue + meterModel = e.getElementsByTagName('TypeNo')[0].firstChild.nodeValue + meterKey = e.getElementsByTagName('DEK')[0].firstChild.nodeValue + print_meter(meterName,meterType,meterNum,meterSerial,meterVendor,meterConfig,meterModel,meterKey) +elif xmldoc.documentElement.tagName == "Devices": + for e in xmldoc.getElementsByTagName('Device'): + # read information from source XML file + meterName = e.getElementsByTagName('ShortName')[0].firstChild.nodeValue + meterType = e.getElementsByTagName('ConsumptionTypeName')[0].firstChild.nodeValue + meterNum = e.getElementsByTagName('CustomerDeviceNumber')[0].firstChild.nodeValue + meterSerial = e.getElementsByTagName('SerialNumber')[0].firstChild.nodeValue + meterVendor = e.getElementsByTagName('ManufacturerId')[0].firstChild.nodeValue + meterConfig = e.getElementsByTagName('ConfigNumber')[0].firstChild.nodeValue + meterModel = e.getElementsByTagName('TypeNumber')[0].firstChild.nodeValue + meterKey = e.getElementsByTagName('Value')[0].firstChild.nodeValue + print_meter(meterName,meterType,meterNum,meterSerial,meterVendor,meterConfig,meterModel,meterKey) +else: + print("ERROR: Looks like password is wrong - decryption failed!") + sys.exit(1) \ No newline at end of file From 0603de6f72ff0269c1eec757d2a342b89c2fe9ac Mon Sep 17 00:00:00 2001 From: BIBOLV <49994376+BIBOLV@users.noreply.github.com> Date: Thu, 6 Apr 2023 23:04:41 +0300 Subject: [PATCH 2/3] Update kem-import.py --- utils/kem-import.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/kem-import.py b/utils/kem-import.py index c252fee..50aaccf 100644 --- a/utils/kem-import.py +++ b/utils/kem-import.py @@ -225,5 +225,5 @@ elif xmldoc.documentElement.tagName == "Devices": meterKey = e.getElementsByTagName('Value')[0].firstChild.nodeValue print_meter(meterName,meterType,meterNum,meterSerial,meterVendor,meterConfig,meterModel,meterKey) else: - print("ERROR: Looks like password is wrong - decryption failed!") + print("ERROR: Unable to extract details from file") sys.exit(1) \ No newline at end of file From 499adec70f86f3e57639fa79cfdab01bae5e959e Mon Sep 17 00:00:00 2001 From: BIBOLV <49994376+BIBOLV@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:19:59 +0300 Subject: [PATCH 3/3] Update kem-extract.sh --- utils/kem-extract.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/kem-extract.sh b/utils/kem-extract.sh index a07ab69..e619d32 100755 --- a/utils/kem-extract.sh +++ b/utils/kem-extract.sh @@ -56,4 +56,4 @@ then else echo "Error when extracting. To debug run: bash -x kem-extract $*" echo "Collect the output and create an issue at https://github.com/wmbusmeters/wmbusmeters" -fi +fi \ No newline at end of file