DLMS-SPODES-client 0.19.35__py3-none-any.whl → 0.19.37__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- DLMS_SPODES_client/FCS16.py +39 -39
- DLMS_SPODES_client/__init__.py +12 -12
- DLMS_SPODES_client/client.py +2093 -2093
- DLMS_SPODES_client/gurux_common/enums/TraceLevel.py +21 -21
- DLMS_SPODES_client/gurux_dlms/AesGcmParameter.py +37 -37
- DLMS_SPODES_client/gurux_dlms/CountType.py +16 -16
- DLMS_SPODES_client/gurux_dlms/GXByteBuffer.py +545 -545
- DLMS_SPODES_client/gurux_dlms/GXCiphering.py +196 -196
- DLMS_SPODES_client/gurux_dlms/GXDLMS.py +426 -426
- DLMS_SPODES_client/gurux_dlms/GXDLMSChippering.py +237 -237
- DLMS_SPODES_client/gurux_dlms/GXDLMSChipperingStream.py +977 -977
- DLMS_SPODES_client/gurux_dlms/GXDLMSConfirmedServiceError.py +90 -90
- DLMS_SPODES_client/gurux_dlms/GXDLMSException.py +139 -139
- DLMS_SPODES_client/gurux_dlms/GXDLMSLNParameters.py +33 -33
- DLMS_SPODES_client/gurux_dlms/GXDLMSSNParameters.py +21 -21
- DLMS_SPODES_client/gurux_dlms/GXDLMSSettings.py +254 -254
- DLMS_SPODES_client/gurux_dlms/GXReplyData.py +87 -87
- DLMS_SPODES_client/gurux_dlms/HdlcControlFrame.py +9 -9
- DLMS_SPODES_client/gurux_dlms/MBusCommand.py +8 -8
- DLMS_SPODES_client/gurux_dlms/MBusEncryptionMode.py +27 -27
- DLMS_SPODES_client/gurux_dlms/ResponseType.py +8 -8
- DLMS_SPODES_client/gurux_dlms/SetResponseType.py +29 -29
- DLMS_SPODES_client/gurux_dlms/_HDLCInfo.py +9 -9
- DLMS_SPODES_client/gurux_dlms/__init__.py +75 -75
- DLMS_SPODES_client/gurux_dlms/enums/Access.py +12 -12
- DLMS_SPODES_client/gurux_dlms/enums/ApplicationReference.py +14 -14
- DLMS_SPODES_client/gurux_dlms/enums/Authentication.py +41 -41
- DLMS_SPODES_client/gurux_dlms/enums/BerType.py +35 -35
- DLMS_SPODES_client/gurux_dlms/enums/Command.py +285 -285
- DLMS_SPODES_client/gurux_dlms/enums/Definition.py +9 -9
- DLMS_SPODES_client/gurux_dlms/enums/ErrorCode.py +46 -46
- DLMS_SPODES_client/gurux_dlms/enums/ExceptionServiceError.py +12 -12
- DLMS_SPODES_client/gurux_dlms/enums/HardwareResource.py +10 -10
- DLMS_SPODES_client/gurux_dlms/enums/HdlcFrameType.py +9 -9
- DLMS_SPODES_client/gurux_dlms/enums/Initiate.py +10 -10
- DLMS_SPODES_client/gurux_dlms/enums/LoadDataSet.py +13 -13
- DLMS_SPODES_client/gurux_dlms/enums/ObjectType.py +306 -306
- DLMS_SPODES_client/gurux_dlms/enums/Priority.py +7 -7
- DLMS_SPODES_client/gurux_dlms/enums/RequestTypes.py +9 -9
- DLMS_SPODES_client/gurux_dlms/enums/Security.py +14 -14
- DLMS_SPODES_client/gurux_dlms/enums/Service.py +16 -16
- DLMS_SPODES_client/gurux_dlms/enums/ServiceClass.py +9 -9
- DLMS_SPODES_client/gurux_dlms/enums/ServiceError.py +8 -8
- DLMS_SPODES_client/gurux_dlms/enums/Standard.py +18 -18
- DLMS_SPODES_client/gurux_dlms/enums/StateError.py +7 -7
- DLMS_SPODES_client/gurux_dlms/enums/Task.py +10 -10
- DLMS_SPODES_client/gurux_dlms/enums/VdeStateError.py +10 -10
- DLMS_SPODES_client/gurux_dlms/enums/__init__.py +33 -33
- DLMS_SPODES_client/gurux_dlms/internal/_GXCommon.py +1673 -1673
- DLMS_SPODES_client/logger.py +56 -56
- DLMS_SPODES_client/services.py +90 -90
- DLMS_SPODES_client/session.py +363 -363
- DLMS_SPODES_client/settings.py +48 -48
- DLMS_SPODES_client/task.py +1884 -1884
- {dlms_spodes_client-0.19.35.dist-info → dlms_spodes_client-0.19.37.dist-info}/METADATA +29 -29
- dlms_spodes_client-0.19.37.dist-info/RECORD +61 -0
- {dlms_spodes_client-0.19.35.dist-info → dlms_spodes_client-0.19.37.dist-info}/WHEEL +1 -1
- dlms_spodes_client-0.19.35.dist-info/RECORD +0 -61
- {dlms_spodes_client-0.19.35.dist-info → dlms_spodes_client-0.19.37.dist-info}/entry_points.txt +0 -0
- {dlms_spodes_client-0.19.35.dist-info → dlms_spodes_client-0.19.37.dist-info}/top_level.txt +0 -0
|
@@ -1,237 +1,237 @@
|
|
|
1
|
-
from .enums.Security import Security
|
|
2
|
-
from .GXByteBuffer import GXByteBuffer
|
|
3
|
-
from .CountType import CountType
|
|
4
|
-
from .GXDLMSChipperingStream import GXDLMSChipperingStream
|
|
5
|
-
from .internal._GXCommon import _GXCommon
|
|
6
|
-
from .enums.Command import Command
|
|
7
|
-
from DLMS_SPODES.cosem_interface_classes.security_setup.ver1 import SecuritySuite
|
|
8
|
-
|
|
9
|
-
#pylint: disable=too-many-instance-attributes,too-many-public-methods
|
|
10
|
-
class GXDLMSChippering:
|
|
11
|
-
|
|
12
|
-
#
|
|
13
|
-
# * Get nonse from frame counter and system title.
|
|
14
|
-
# * @param invocationCounter Invocation counter.
|
|
15
|
-
# * @param systemTitle System title.
|
|
16
|
-
# * @return Generated nonse.
|
|
17
|
-
#
|
|
18
|
-
@classmethod
|
|
19
|
-
def getNonse(cls, invocationCounter, systemTitle):
|
|
20
|
-
nonce = bytearray(12)
|
|
21
|
-
nonce[0:7] = systemTitle
|
|
22
|
-
nonce[8] = ((invocationCounter >> 24) & 0xFF)
|
|
23
|
-
nonce[9] = ((invocationCounter >> 16) & 0xFF)
|
|
24
|
-
nonce[10] = ((invocationCounter >> 8) & 0xFF)
|
|
25
|
-
nonce[11] = (invocationCounter & 0xFF)
|
|
26
|
-
return nonce
|
|
27
|
-
|
|
28
|
-
@classmethod
|
|
29
|
-
def encryptAesGcm(cls, p, plainText) -> bytearray:
|
|
30
|
-
p.countTag = None
|
|
31
|
-
data = GXByteBuffer()
|
|
32
|
-
if p.type_ == CountType.PACKET:
|
|
33
|
-
data.setUInt8(p.security)
|
|
34
|
-
tmp = bytearray(4)
|
|
35
|
-
invocationCounter = 0
|
|
36
|
-
if p.securitySuite == SecuritySuite.AES_GCM_128_AUT_ENCR_AND_AES_128_KEY_WRAP:
|
|
37
|
-
invocationCounter = p.invocationCounter
|
|
38
|
-
tmp[0] = ((invocationCounter >> 24) & 0xFF)
|
|
39
|
-
tmp[1] = ((invocationCounter >> 16) & 0xFF)
|
|
40
|
-
tmp[2] = ((invocationCounter >> 8) & 0xFF)
|
|
41
|
-
tmp[3] = (invocationCounter & 0xFF)
|
|
42
|
-
aad = cls.getAuthenticatedData(p, plainText)
|
|
43
|
-
iv = cls.getNonse(invocationCounter, p.systemTitle)
|
|
44
|
-
gcm = GXDLMSChipperingStream(p.security, True, p.blockCipherKey, aad, iv, None)
|
|
45
|
-
# Encrypt the secret message
|
|
46
|
-
if p.security != Security.AUTHENTICATION:
|
|
47
|
-
gcm.write(plainText)
|
|
48
|
-
ciphertext = gcm.flushFinalBlock()
|
|
49
|
-
if p.security == Security.AUTHENTICATION:
|
|
50
|
-
if p.type_ == CountType.PACKET:
|
|
51
|
-
data.set(tmp)
|
|
52
|
-
if (p.type_ & CountType.DATA) != 0:
|
|
53
|
-
data.set(plainText)
|
|
54
|
-
if (p.type_ & CountType.TAG) != 0:
|
|
55
|
-
p.countTag = gcm.tag
|
|
56
|
-
data.set(p.countTag)
|
|
57
|
-
elif p.security == Security.ENCRYPTION:
|
|
58
|
-
if p.type_ == CountType.PACKET:
|
|
59
|
-
data.set(tmp)
|
|
60
|
-
data.set(ciphertext)
|
|
61
|
-
elif p.security == Security.AUTHENTICATION_ENCRYPTION:
|
|
62
|
-
if p.type_ == CountType.PACKET:
|
|
63
|
-
data.set(tmp)
|
|
64
|
-
if (p.type_ & CountType.DATA) != 0:
|
|
65
|
-
data.set(ciphertext)
|
|
66
|
-
if (p.type_ & CountType.TAG) != 0:
|
|
67
|
-
p.countTag = gcm.tag
|
|
68
|
-
data.set(p.countTag)
|
|
69
|
-
else:
|
|
70
|
-
raise ValueError("security")
|
|
71
|
-
if p.type_ == CountType.PACKET:
|
|
72
|
-
tmp2 = GXByteBuffer(10 + len(data))
|
|
73
|
-
tmp2.setUInt8(p.tag)
|
|
74
|
-
if p.tag == Command.GENERAL_GLO_CIPHERING or p.tag == Command.GENERAL_DED_CIPHERING or p.tag == Command.DATA_NOTIFICATION:
|
|
75
|
-
if not p.ignoreSystemTitle:
|
|
76
|
-
_GXCommon.setObjectCount(len(p.systemTitle), tmp2)
|
|
77
|
-
tmp2.set(p.systemTitle)
|
|
78
|
-
else:
|
|
79
|
-
tmp2.SetUInt8(0)
|
|
80
|
-
_GXCommon.setObjectCount(len(data), tmp2)
|
|
81
|
-
tmp2.set(data, 0, len(data))
|
|
82
|
-
data = tmp2
|
|
83
|
-
crypted = data.array()
|
|
84
|
-
return crypted
|
|
85
|
-
|
|
86
|
-
@classmethod
|
|
87
|
-
def getAuthenticatedData(cls, p, plainText):
|
|
88
|
-
data = GXByteBuffer()
|
|
89
|
-
sc = p.security | p.securitySuite
|
|
90
|
-
if p.security == Security.AUTHENTICATION:
|
|
91
|
-
data.setUInt8(sc)
|
|
92
|
-
data.set(p.authenticationKey)
|
|
93
|
-
data.set(plainText)
|
|
94
|
-
elif p.security == Security.AUTHENTICATION_ENCRYPTION:
|
|
95
|
-
data.setUInt8(sc)
|
|
96
|
-
data.set(p.authenticationKey)
|
|
97
|
-
if p.securitySuite != SecuritySuite.AES_GCM_128_AUT_ENCR_AND_AES_128_KEY_WRAP:
|
|
98
|
-
# transaction-id
|
|
99
|
-
transactionId = GXByteBuffer()
|
|
100
|
-
transactionId.setUInt64(p.invocationCounter)
|
|
101
|
-
data.setUInt8(8)
|
|
102
|
-
data.set(transactionId)
|
|
103
|
-
# originator-system-title
|
|
104
|
-
_GXCommon.setObjectCount(len(p.systemTitle), data)
|
|
105
|
-
data.set(p.systemTitle)
|
|
106
|
-
# recipient-system-title
|
|
107
|
-
_GXCommon.setObjectCount(len(p.recipientSystemTitle), data)
|
|
108
|
-
data.set(p.recipientSystemTitle)
|
|
109
|
-
# date-time not present
|
|
110
|
-
data.setUInt8(0)
|
|
111
|
-
# other-information not present
|
|
112
|
-
data.setUInt8(0)
|
|
113
|
-
elif p.security == Security.ENCRYPTION:
|
|
114
|
-
data.set(p.authenticationKey)
|
|
115
|
-
return data.array()
|
|
116
|
-
|
|
117
|
-
#
|
|
118
|
-
# * Decrypt data.
|
|
119
|
-
# *
|
|
120
|
-
# * @param c
|
|
121
|
-
# * Cipher settings.
|
|
122
|
-
# * @param p
|
|
123
|
-
# * GMAC Parameter.
|
|
124
|
-
# * @return Encrypted data.
|
|
125
|
-
#
|
|
126
|
-
@classmethod
|
|
127
|
-
def decryptAesGcm(cls, p, data):
|
|
128
|
-
# pylint: disable=too-many-locals
|
|
129
|
-
if not data or len(data) - data.position < 2:
|
|
130
|
-
raise ValueError("cryptedData")
|
|
131
|
-
tmp = []
|
|
132
|
-
len_ = 0
|
|
133
|
-
cmd = data.getUInt8()
|
|
134
|
-
if cmd in (Command.GENERAL_GLO_CIPHERING, Command.GENERAL_DED_CIPHERING):
|
|
135
|
-
len_ = _GXCommon.getObjectCount(data)
|
|
136
|
-
title = bytearray(len_)
|
|
137
|
-
data.get(title)
|
|
138
|
-
p.systemTitle = title
|
|
139
|
-
elif cmd in (Command.GENERAL_CIPHERING, Command.GLO_INITIATE_REQUEST, Command.GLO_INITIATE_RESPONSE, Command.GLO_READ_REQUEST, Command.GLO_READ_RESPONSE,
|
|
140
|
-
Command.GLO_WRITE_REQUEST, Command.GLO_WRITE_RESPONSE, Command.GLO_GET_REQUEST, Command.GLO_GET_RESPONSE, Command.GLO_SET_REQUEST,
|
|
141
|
-
Command.GLO_SET_RESPONSE, Command.GLO_METHOD_REQUEST, Command.GLO_METHOD_RESPONSE, Command.GLO_EVENT_NOTIFICATION,
|
|
142
|
-
Command.DED_GET_REQUEST, Command.DED_GET_RESPONSE, Command.DED_SET_REQUEST, Command.DED_SET_RESPONSE, Command.DED_METHOD_REQUEST,
|
|
143
|
-
Command.DED_METHOD_RESPONSE, Command.DED_EVENT_NOTIFICATION):
|
|
144
|
-
pass
|
|
145
|
-
else:
|
|
146
|
-
raise ValueError("cryptedData")
|
|
147
|
-
value = 0
|
|
148
|
-
transactionId = 0
|
|
149
|
-
if cmd == Command.GENERAL_CIPHERING:
|
|
150
|
-
len_ = _GXCommon.getObjectCount(data)
|
|
151
|
-
tmp = bytearray(len_)
|
|
152
|
-
data.get(tmp)
|
|
153
|
-
t = GXByteBuffer(tmp)
|
|
154
|
-
transactionId = t.getInt64()
|
|
155
|
-
len_ = _GXCommon.getObjectCount(data)
|
|
156
|
-
tmp = bytearray(len_)
|
|
157
|
-
data.get(tmp)
|
|
158
|
-
p.setSystemTitle(tmp)
|
|
159
|
-
len_ = _GXCommon.getObjectCount(data)
|
|
160
|
-
tmp = bytearray(len_)
|
|
161
|
-
data.get(tmp)
|
|
162
|
-
p.setRecipientSystemTitle(tmp)
|
|
163
|
-
# Get date time.
|
|
164
|
-
len_ = _GXCommon.getObjectCount(data)
|
|
165
|
-
if len_ != 0:
|
|
166
|
-
tmp = bytearray(len_)
|
|
167
|
-
data.get(tmp)
|
|
168
|
-
p.dateTime = tmp
|
|
169
|
-
# other-information
|
|
170
|
-
len_ = data.getUInt8()
|
|
171
|
-
if len_ != 0:
|
|
172
|
-
tmp = bytearray(len_)
|
|
173
|
-
data.get(tmp)
|
|
174
|
-
p.otherInformation = tmp
|
|
175
|
-
# KeyInfo OPTIONAL
|
|
176
|
-
len_ = data.getUInt8()
|
|
177
|
-
# AgreedKey CHOICE tag.
|
|
178
|
-
data.getUInt8()
|
|
179
|
-
# key-parameters
|
|
180
|
-
len_ = data.getUInt8()
|
|
181
|
-
value = data.getUInt8()
|
|
182
|
-
p.setKeyParameters(value)
|
|
183
|
-
if value == 1:
|
|
184
|
-
# KeyAgreement.ONE_PASS_DIFFIE_HELLMAN
|
|
185
|
-
# key-ciphered-data
|
|
186
|
-
len_ = _GXCommon.getObjectCount(data)
|
|
187
|
-
tmp = bytearray(len_)
|
|
188
|
-
data.get(tmp)
|
|
189
|
-
p.keyCipheredData = tmp
|
|
190
|
-
elif value == 2:
|
|
191
|
-
# KeyAgreement.STATIC_UNIFIED_MODEL
|
|
192
|
-
len_ = _GXCommon.getObjectCount(data)
|
|
193
|
-
if len_ != 0:
|
|
194
|
-
raise ValueError("Invalid key parameters")
|
|
195
|
-
else:
|
|
196
|
-
raise ValueError("key-parameters")
|
|
197
|
-
len_ = _GXCommon.getObjectCount(data)
|
|
198
|
-
p.cipheredContent = data.remaining()
|
|
199
|
-
sc = data.getUInt8()
|
|
200
|
-
security = sc & 0x30
|
|
201
|
-
ss = sc & 0x3
|
|
202
|
-
if ss != SecuritySuite.AES_GCM_128_AUT_ENCR_AND_AES_128_KEY_WRAP:
|
|
203
|
-
raise ValueError("Decrypt failed. Invalid security suite.")
|
|
204
|
-
p.security = security
|
|
205
|
-
invocationCounter = data.getUInt32()
|
|
206
|
-
p.invocationCounter = invocationCounter
|
|
207
|
-
tag = bytearray(12)
|
|
208
|
-
encryptedData = None
|
|
209
|
-
if security == Security.AUTHENTICATION:
|
|
210
|
-
len_ = len(data) - data.position() - 12
|
|
211
|
-
encryptedData = bytearray(len_)
|
|
212
|
-
data.get(encryptedData)
|
|
213
|
-
data.get(tag)
|
|
214
|
-
# Check tag.
|
|
215
|
-
cls.encryptAesGcm(p, encryptedData)
|
|
216
|
-
if not GXDLMSChipperingStream.tagsEquals(tag, p.countTag):
|
|
217
|
-
if transactionId != 0:
|
|
218
|
-
p.setInvocationCounter(transactionId)
|
|
219
|
-
raise ValueError("Decrypt failed. Invalid tag.")
|
|
220
|
-
return encryptedData
|
|
221
|
-
ciphertext = None
|
|
222
|
-
if security == Security.ENCRYPTION:
|
|
223
|
-
len_ = len(data) - data.position
|
|
224
|
-
ciphertext = bytearray(len_)
|
|
225
|
-
data.get(ciphertext)
|
|
226
|
-
elif security == Security.AUTHENTICATION_ENCRYPTION:
|
|
227
|
-
len_ = len(data) - data.position - 12
|
|
228
|
-
ciphertext = bytearray(len_)
|
|
229
|
-
data.get(ciphertext)
|
|
230
|
-
data.get(tag)
|
|
231
|
-
aad = cls.getAuthenticatedData(p, ciphertext)
|
|
232
|
-
iv = cls.getNonse(invocationCounter, p.systemTitle)
|
|
233
|
-
gcm = GXDLMSChipperingStream(security, True, p.blockCipherKey, aad, iv, tag)
|
|
234
|
-
gcm.write(ciphertext)
|
|
235
|
-
if transactionId != 0:
|
|
236
|
-
p.setInvocationCounter(transactionId)
|
|
237
|
-
return gcm.flushFinalBlock()
|
|
1
|
+
from .enums.Security import Security
|
|
2
|
+
from .GXByteBuffer import GXByteBuffer
|
|
3
|
+
from .CountType import CountType
|
|
4
|
+
from .GXDLMSChipperingStream import GXDLMSChipperingStream
|
|
5
|
+
from .internal._GXCommon import _GXCommon
|
|
6
|
+
from .enums.Command import Command
|
|
7
|
+
from DLMS_SPODES.cosem_interface_classes.security_setup.ver1 import SecuritySuite
|
|
8
|
+
|
|
9
|
+
#pylint: disable=too-many-instance-attributes,too-many-public-methods
|
|
10
|
+
class GXDLMSChippering:
|
|
11
|
+
|
|
12
|
+
#
|
|
13
|
+
# * Get nonse from frame counter and system title.
|
|
14
|
+
# * @param invocationCounter Invocation counter.
|
|
15
|
+
# * @param systemTitle System title.
|
|
16
|
+
# * @return Generated nonse.
|
|
17
|
+
#
|
|
18
|
+
@classmethod
|
|
19
|
+
def getNonse(cls, invocationCounter, systemTitle):
|
|
20
|
+
nonce = bytearray(12)
|
|
21
|
+
nonce[0:7] = systemTitle
|
|
22
|
+
nonce[8] = ((invocationCounter >> 24) & 0xFF)
|
|
23
|
+
nonce[9] = ((invocationCounter >> 16) & 0xFF)
|
|
24
|
+
nonce[10] = ((invocationCounter >> 8) & 0xFF)
|
|
25
|
+
nonce[11] = (invocationCounter & 0xFF)
|
|
26
|
+
return nonce
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def encryptAesGcm(cls, p, plainText) -> bytearray:
|
|
30
|
+
p.countTag = None
|
|
31
|
+
data = GXByteBuffer()
|
|
32
|
+
if p.type_ == CountType.PACKET:
|
|
33
|
+
data.setUInt8(p.security)
|
|
34
|
+
tmp = bytearray(4)
|
|
35
|
+
invocationCounter = 0
|
|
36
|
+
if p.securitySuite == SecuritySuite.AES_GCM_128_AUT_ENCR_AND_AES_128_KEY_WRAP:
|
|
37
|
+
invocationCounter = p.invocationCounter
|
|
38
|
+
tmp[0] = ((invocationCounter >> 24) & 0xFF)
|
|
39
|
+
tmp[1] = ((invocationCounter >> 16) & 0xFF)
|
|
40
|
+
tmp[2] = ((invocationCounter >> 8) & 0xFF)
|
|
41
|
+
tmp[3] = (invocationCounter & 0xFF)
|
|
42
|
+
aad = cls.getAuthenticatedData(p, plainText)
|
|
43
|
+
iv = cls.getNonse(invocationCounter, p.systemTitle)
|
|
44
|
+
gcm = GXDLMSChipperingStream(p.security, True, p.blockCipherKey, aad, iv, None)
|
|
45
|
+
# Encrypt the secret message
|
|
46
|
+
if p.security != Security.AUTHENTICATION:
|
|
47
|
+
gcm.write(plainText)
|
|
48
|
+
ciphertext = gcm.flushFinalBlock()
|
|
49
|
+
if p.security == Security.AUTHENTICATION:
|
|
50
|
+
if p.type_ == CountType.PACKET:
|
|
51
|
+
data.set(tmp)
|
|
52
|
+
if (p.type_ & CountType.DATA) != 0:
|
|
53
|
+
data.set(plainText)
|
|
54
|
+
if (p.type_ & CountType.TAG) != 0:
|
|
55
|
+
p.countTag = gcm.tag
|
|
56
|
+
data.set(p.countTag)
|
|
57
|
+
elif p.security == Security.ENCRYPTION:
|
|
58
|
+
if p.type_ == CountType.PACKET:
|
|
59
|
+
data.set(tmp)
|
|
60
|
+
data.set(ciphertext)
|
|
61
|
+
elif p.security == Security.AUTHENTICATION_ENCRYPTION:
|
|
62
|
+
if p.type_ == CountType.PACKET:
|
|
63
|
+
data.set(tmp)
|
|
64
|
+
if (p.type_ & CountType.DATA) != 0:
|
|
65
|
+
data.set(ciphertext)
|
|
66
|
+
if (p.type_ & CountType.TAG) != 0:
|
|
67
|
+
p.countTag = gcm.tag
|
|
68
|
+
data.set(p.countTag)
|
|
69
|
+
else:
|
|
70
|
+
raise ValueError("security")
|
|
71
|
+
if p.type_ == CountType.PACKET:
|
|
72
|
+
tmp2 = GXByteBuffer(10 + len(data))
|
|
73
|
+
tmp2.setUInt8(p.tag)
|
|
74
|
+
if p.tag == Command.GENERAL_GLO_CIPHERING or p.tag == Command.GENERAL_DED_CIPHERING or p.tag == Command.DATA_NOTIFICATION:
|
|
75
|
+
if not p.ignoreSystemTitle:
|
|
76
|
+
_GXCommon.setObjectCount(len(p.systemTitle), tmp2)
|
|
77
|
+
tmp2.set(p.systemTitle)
|
|
78
|
+
else:
|
|
79
|
+
tmp2.SetUInt8(0)
|
|
80
|
+
_GXCommon.setObjectCount(len(data), tmp2)
|
|
81
|
+
tmp2.set(data, 0, len(data))
|
|
82
|
+
data = tmp2
|
|
83
|
+
crypted = data.array()
|
|
84
|
+
return crypted
|
|
85
|
+
|
|
86
|
+
@classmethod
|
|
87
|
+
def getAuthenticatedData(cls, p, plainText):
|
|
88
|
+
data = GXByteBuffer()
|
|
89
|
+
sc = p.security | p.securitySuite
|
|
90
|
+
if p.security == Security.AUTHENTICATION:
|
|
91
|
+
data.setUInt8(sc)
|
|
92
|
+
data.set(p.authenticationKey)
|
|
93
|
+
data.set(plainText)
|
|
94
|
+
elif p.security == Security.AUTHENTICATION_ENCRYPTION:
|
|
95
|
+
data.setUInt8(sc)
|
|
96
|
+
data.set(p.authenticationKey)
|
|
97
|
+
if p.securitySuite != SecuritySuite.AES_GCM_128_AUT_ENCR_AND_AES_128_KEY_WRAP:
|
|
98
|
+
# transaction-id
|
|
99
|
+
transactionId = GXByteBuffer()
|
|
100
|
+
transactionId.setUInt64(p.invocationCounter)
|
|
101
|
+
data.setUInt8(8)
|
|
102
|
+
data.set(transactionId)
|
|
103
|
+
# originator-system-title
|
|
104
|
+
_GXCommon.setObjectCount(len(p.systemTitle), data)
|
|
105
|
+
data.set(p.systemTitle)
|
|
106
|
+
# recipient-system-title
|
|
107
|
+
_GXCommon.setObjectCount(len(p.recipientSystemTitle), data)
|
|
108
|
+
data.set(p.recipientSystemTitle)
|
|
109
|
+
# date-time not present
|
|
110
|
+
data.setUInt8(0)
|
|
111
|
+
# other-information not present
|
|
112
|
+
data.setUInt8(0)
|
|
113
|
+
elif p.security == Security.ENCRYPTION:
|
|
114
|
+
data.set(p.authenticationKey)
|
|
115
|
+
return data.array()
|
|
116
|
+
|
|
117
|
+
#
|
|
118
|
+
# * Decrypt data.
|
|
119
|
+
# *
|
|
120
|
+
# * @param c
|
|
121
|
+
# * Cipher settings.
|
|
122
|
+
# * @param p
|
|
123
|
+
# * GMAC Parameter.
|
|
124
|
+
# * @return Encrypted data.
|
|
125
|
+
#
|
|
126
|
+
@classmethod
|
|
127
|
+
def decryptAesGcm(cls, p, data):
|
|
128
|
+
# pylint: disable=too-many-locals
|
|
129
|
+
if not data or len(data) - data.position < 2:
|
|
130
|
+
raise ValueError("cryptedData")
|
|
131
|
+
tmp = []
|
|
132
|
+
len_ = 0
|
|
133
|
+
cmd = data.getUInt8()
|
|
134
|
+
if cmd in (Command.GENERAL_GLO_CIPHERING, Command.GENERAL_DED_CIPHERING):
|
|
135
|
+
len_ = _GXCommon.getObjectCount(data)
|
|
136
|
+
title = bytearray(len_)
|
|
137
|
+
data.get(title)
|
|
138
|
+
p.systemTitle = title
|
|
139
|
+
elif cmd in (Command.GENERAL_CIPHERING, Command.GLO_INITIATE_REQUEST, Command.GLO_INITIATE_RESPONSE, Command.GLO_READ_REQUEST, Command.GLO_READ_RESPONSE,
|
|
140
|
+
Command.GLO_WRITE_REQUEST, Command.GLO_WRITE_RESPONSE, Command.GLO_GET_REQUEST, Command.GLO_GET_RESPONSE, Command.GLO_SET_REQUEST,
|
|
141
|
+
Command.GLO_SET_RESPONSE, Command.GLO_METHOD_REQUEST, Command.GLO_METHOD_RESPONSE, Command.GLO_EVENT_NOTIFICATION,
|
|
142
|
+
Command.DED_GET_REQUEST, Command.DED_GET_RESPONSE, Command.DED_SET_REQUEST, Command.DED_SET_RESPONSE, Command.DED_METHOD_REQUEST,
|
|
143
|
+
Command.DED_METHOD_RESPONSE, Command.DED_EVENT_NOTIFICATION):
|
|
144
|
+
pass
|
|
145
|
+
else:
|
|
146
|
+
raise ValueError("cryptedData")
|
|
147
|
+
value = 0
|
|
148
|
+
transactionId = 0
|
|
149
|
+
if cmd == Command.GENERAL_CIPHERING:
|
|
150
|
+
len_ = _GXCommon.getObjectCount(data)
|
|
151
|
+
tmp = bytearray(len_)
|
|
152
|
+
data.get(tmp)
|
|
153
|
+
t = GXByteBuffer(tmp)
|
|
154
|
+
transactionId = t.getInt64()
|
|
155
|
+
len_ = _GXCommon.getObjectCount(data)
|
|
156
|
+
tmp = bytearray(len_)
|
|
157
|
+
data.get(tmp)
|
|
158
|
+
p.setSystemTitle(tmp)
|
|
159
|
+
len_ = _GXCommon.getObjectCount(data)
|
|
160
|
+
tmp = bytearray(len_)
|
|
161
|
+
data.get(tmp)
|
|
162
|
+
p.setRecipientSystemTitle(tmp)
|
|
163
|
+
# Get date time.
|
|
164
|
+
len_ = _GXCommon.getObjectCount(data)
|
|
165
|
+
if len_ != 0:
|
|
166
|
+
tmp = bytearray(len_)
|
|
167
|
+
data.get(tmp)
|
|
168
|
+
p.dateTime = tmp
|
|
169
|
+
# other-information
|
|
170
|
+
len_ = data.getUInt8()
|
|
171
|
+
if len_ != 0:
|
|
172
|
+
tmp = bytearray(len_)
|
|
173
|
+
data.get(tmp)
|
|
174
|
+
p.otherInformation = tmp
|
|
175
|
+
# KeyInfo OPTIONAL
|
|
176
|
+
len_ = data.getUInt8()
|
|
177
|
+
# AgreedKey CHOICE tag.
|
|
178
|
+
data.getUInt8()
|
|
179
|
+
# key-parameters
|
|
180
|
+
len_ = data.getUInt8()
|
|
181
|
+
value = data.getUInt8()
|
|
182
|
+
p.setKeyParameters(value)
|
|
183
|
+
if value == 1:
|
|
184
|
+
# KeyAgreement.ONE_PASS_DIFFIE_HELLMAN
|
|
185
|
+
# key-ciphered-data
|
|
186
|
+
len_ = _GXCommon.getObjectCount(data)
|
|
187
|
+
tmp = bytearray(len_)
|
|
188
|
+
data.get(tmp)
|
|
189
|
+
p.keyCipheredData = tmp
|
|
190
|
+
elif value == 2:
|
|
191
|
+
# KeyAgreement.STATIC_UNIFIED_MODEL
|
|
192
|
+
len_ = _GXCommon.getObjectCount(data)
|
|
193
|
+
if len_ != 0:
|
|
194
|
+
raise ValueError("Invalid key parameters")
|
|
195
|
+
else:
|
|
196
|
+
raise ValueError("key-parameters")
|
|
197
|
+
len_ = _GXCommon.getObjectCount(data)
|
|
198
|
+
p.cipheredContent = data.remaining()
|
|
199
|
+
sc = data.getUInt8()
|
|
200
|
+
security = sc & 0x30
|
|
201
|
+
ss = sc & 0x3
|
|
202
|
+
if ss != SecuritySuite.AES_GCM_128_AUT_ENCR_AND_AES_128_KEY_WRAP:
|
|
203
|
+
raise ValueError("Decrypt failed. Invalid security suite.")
|
|
204
|
+
p.security = security
|
|
205
|
+
invocationCounter = data.getUInt32()
|
|
206
|
+
p.invocationCounter = invocationCounter
|
|
207
|
+
tag = bytearray(12)
|
|
208
|
+
encryptedData = None
|
|
209
|
+
if security == Security.AUTHENTICATION:
|
|
210
|
+
len_ = len(data) - data.position() - 12
|
|
211
|
+
encryptedData = bytearray(len_)
|
|
212
|
+
data.get(encryptedData)
|
|
213
|
+
data.get(tag)
|
|
214
|
+
# Check tag.
|
|
215
|
+
cls.encryptAesGcm(p, encryptedData)
|
|
216
|
+
if not GXDLMSChipperingStream.tagsEquals(tag, p.countTag):
|
|
217
|
+
if transactionId != 0:
|
|
218
|
+
p.setInvocationCounter(transactionId)
|
|
219
|
+
raise ValueError("Decrypt failed. Invalid tag.")
|
|
220
|
+
return encryptedData
|
|
221
|
+
ciphertext = None
|
|
222
|
+
if security == Security.ENCRYPTION:
|
|
223
|
+
len_ = len(data) - data.position
|
|
224
|
+
ciphertext = bytearray(len_)
|
|
225
|
+
data.get(ciphertext)
|
|
226
|
+
elif security == Security.AUTHENTICATION_ENCRYPTION:
|
|
227
|
+
len_ = len(data) - data.position - 12
|
|
228
|
+
ciphertext = bytearray(len_)
|
|
229
|
+
data.get(ciphertext)
|
|
230
|
+
data.get(tag)
|
|
231
|
+
aad = cls.getAuthenticatedData(p, ciphertext)
|
|
232
|
+
iv = cls.getNonse(invocationCounter, p.systemTitle)
|
|
233
|
+
gcm = GXDLMSChipperingStream(security, True, p.blockCipherKey, aad, iv, tag)
|
|
234
|
+
gcm.write(ciphertext)
|
|
235
|
+
if transactionId != 0:
|
|
236
|
+
p.setInvocationCounter(transactionId)
|
|
237
|
+
return gcm.flushFinalBlock()
|