kopia lustrzana https://github.com/weetmuts/wmbusmeters
Update kem import script
Switch pycrypto package to cryptography and add possibility to process also kem2 filespull/938/head
rodzic
c865e88ccf
commit
009a51d6db
|
@ -27,9 +27,12 @@ import re
|
||||||
import errno
|
import errno
|
||||||
import argparse
|
import argparse
|
||||||
import base64
|
import base64
|
||||||
import Crypto.Cipher.AES as AES
|
|
||||||
from xml.dom import minidom
|
|
||||||
import zipfile
|
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_prog = "Decrypts Kamstrup KEM file and imports meter information into wmbusmeters' config folder."
|
||||||
help_epilog = ""
|
help_epilog = ""
|
||||||
|
@ -74,7 +77,7 @@ if (zipfile.is_zipfile(args.kem_file)):
|
||||||
with zipfile.ZipFile(args.kem_file,'r') as zipobj:
|
with zipfile.ZipFile(args.kem_file,'r') as zipobj:
|
||||||
file_list = zipobj.namelist()
|
file_list = zipobj.namelist()
|
||||||
for file_name in file_list:
|
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)
|
kem_file_content = zipobj.read(file_name)
|
||||||
break
|
break
|
||||||
#end if
|
#end if
|
||||||
|
@ -109,12 +112,20 @@ key = bytes(str(args.password).encode("utf-8"))
|
||||||
if (len(key) < 16): key += (16-len(key)) * b"\0"
|
if (len(key) < 16): key += (16-len(key)) * b"\0"
|
||||||
|
|
||||||
# content decryption
|
# content decryption
|
||||||
aes = AES.new(key, AES.MODE_CBC, IV=key)
|
backend = default_backend()
|
||||||
decryptedtext = aes.decrypt(encrypeddata)
|
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
|
# save decrypted XML file if requested
|
||||||
if (args.output):
|
if (args.output):
|
||||||
f = open(args.output, 'w')
|
f = open(args.output, 'wb')
|
||||||
f.write(decryptedtext)
|
f.write(decryptedtext)
|
||||||
f.close()
|
f.close()
|
||||||
#end if
|
#end if
|
||||||
|
@ -134,22 +145,7 @@ if (not args.dryrun) and (not os.path.exists(args.config)):
|
||||||
raise
|
raise
|
||||||
#end if
|
#end if
|
||||||
|
|
||||||
|
def print_meter(meterName,meterType,meterNum,meterSerial,meterVendor,meterConfig,meterModel,meterKey):
|
||||||
# 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
|
|
||||||
|
|
||||||
# meter model identification
|
# meter model identification
|
||||||
# CONTRIBUTING NOTE: additional meter types supported by wmbusmeters can be put here
|
# CONTRIBUTING NOTE: additional meter types supported by wmbusmeters can be put here
|
||||||
# if their identification in KEM file is known
|
# if their identification in KEM file is known
|
||||||
|
@ -167,7 +163,7 @@ for e in xmldoc.getElementsByTagName('Meter'):
|
||||||
wmbusmeters_driver = 'flowiq2200'
|
wmbusmeters_driver = 'flowiq2200'
|
||||||
else:
|
else:
|
||||||
wmbusmeters_driver = None
|
wmbusmeters_driver = None
|
||||||
|
|
||||||
# print info to console
|
# print info to console
|
||||||
print('Found meter', meterName, '('+meterModel+')')
|
print('Found meter', meterName, '('+meterModel+')')
|
||||||
print(' number :', meterNum)
|
print(' number :', meterNum)
|
||||||
|
@ -200,4 +196,34 @@ for e in xmldoc.getElementsByTagName('Meter'):
|
||||||
#end if
|
#end if
|
||||||
#end for
|
#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)
|
Ładowanie…
Reference in New Issue