Coverage for /root/GitHubProjects/impacket/impacket/crypto.py: 69%

# Coverage for /root/GitHubProjects/impacket/impacket/crypto.py : 69%

## 156 statements

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1# Impacket - Collection of Python classes for working with network protocols.

2#

3# SECUREAUTH LABS. Copyright (C) 2018 SecureAuth Corporation. All rights reserved.

4#

5# This software is provided under a slightly modified version

6# of the Apache Software License. See the accompanying LICENSE file

7# for more information.

8#

9# Description:

10# RFC 4493 implementation (https://www.ietf.org/rfc/rfc4493.txt)

11# RFC 4615 implementation (https://www.ietf.org/rfc/rfc4615.txt)

12#

13# NIST SP 800-108 Section 5.1, with PRF HMAC-SHA256 implementation

14# (https://tools.ietf.org/html/draft-irtf-cfrg-kdf-uses-00#ref-SP800-108)

15#

16# [MS-LSAD] Section 5.1.2

17# [MS-SAMR] Section 2.2.11.1.1

18#

19# Author:

20# Alberto Solino (@agsolino)

21#

22

23 from __future__ import division

24 from __future__ import print_function

25 from impacket import LOG

26 try:

27 from Cryptodome.Cipher import DES, AES

28 except Exception:

29 LOG.error("Warning: You don't have any crypto installed. You need pycryptodomex")

30 LOG.error("See https://pypi.org/project/pycryptodomex/")

31 from struct import pack, unpack

32 from impacket.structure import Structure

33 import hmac, hashlib

34 from six import b

35

36 def Generate_Subkey(K):

37

38# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

39# + Algorithm Generate_Subkey +

40# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

41# + +

42# + Input : K (128-bit key) +

43# + Output : K1 (128-bit first subkey) +

44# + K2 (128-bit second subkey) +

45# +-------------------------------------------------------------------+

46# + +

47# + Constants: const_Zero is 0x00000000000000000000000000000000 +

48# + const_Rb is 0x00000000000000000000000000000087 +

49# + Variables: L for output of AES-128 applied to 0^128 +

50# + +

51# + Step 1. L := AES-128(K, const_Zero); +

52# + Step 2. if MSB(L) is equal to 0 +

53# + then K1 := L << 1; +

54# + else K1 := (L << 1) XOR const_Rb; +

55# + Step 3. if MSB(K1) is equal to 0 +

56# + then K2 := K1 << 1; +

57# + else K2 := (K1 << 1) XOR const_Rb; +

58# + Step 4. return K1, K2; +

59# + +

60# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

61

62 AES_128 = AES.new(K, AES.MODE_ECB)

63

64 L = AES_128.encrypt(bytes(bytearray(16)))

65

66 LHigh = unpack('>Q',L[:8])[0]

67 LLow = unpack('>Q',L[8:])[0]

68

69 K1High = ((LHigh << 1) | ( LLow >> 63 )) & 0xFFFFFFFFFFFFFFFF

70 K1Low = (LLow << 1) & 0xFFFFFFFFFFFFFFFF

71

72 if (LHigh >> 63):

73 K1Low ^= 0x87

74

75 K2High = ((K1High << 1) | (K1Low >> 63)) & 0xFFFFFFFFFFFFFFFF

76 K2Low = ((K1Low << 1)) & 0xFFFFFFFFFFFFFFFF

77

78 if (K1High >> 63):

79 K2Low ^= 0x87

80

81 K1 = bytearray(pack('>QQ', K1High, K1Low))

82 K2 = bytearray(pack('>QQ', K2High, K2Low))

83

84 return K1, K2

85

86 def XOR_128(N1,N2):

87

88 J = bytearray()

89 for i in range(len(N1)):

90 #J.append(indexbytes(N1,i) ^ indexbytes(N2,i))

91 J.append(N1[i] ^ N2[i])

92 return J

93

94 def PAD(N):

95 padLen = 16-len(N)

96 return N + b'\x80' + b'\x00'*(padLen-1)

97

98 def AES_CMAC(K, M, length):

99

100# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

101# + Algorithm AES-CMAC +

102# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

103# + +

104# + Input : K ( 128-bit key ) +

105# + : M ( message to be authenticated ) +

106# + : len ( length of the message in octets ) +

107# + Output : T ( message authentication code ) +

108# + +

109# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

110# + Constants: const_Zero is 0x00000000000000000000000000000000 +

111# + const_Bsize is 16 +

112# + +

113# + Variables: K1, K2 for 128-bit subkeys +

114# + M_i is the i-th block (i=1..ceil(len/const_Bsize)) +

115# + M_last is the last block xor-ed with K1 or K2 +

116# + n for number of blocks to be processed +

117# + r for number of octets of last block +

118# + flag for denoting if last block is complete or not +

119# + +

120# + Step 1. (K1,K2) := Generate_Subkey(K); +

121# + Step 2. n := ceil(len/const_Bsize); +

122# + Step 3. if n = 0 +

123# + then +

124# + n := 1; +

125# + flag := false; +

126# + else +

127# + if len mod const_Bsize is 0 +

128# + then flag := true; +

129# + else flag := false; +

130# + +

131# + Step 4. if flag is true +

132# + then M_last := M_n XOR K1; +

133# + else M_last := padding(M_n) XOR K2; +

134# + Step 5. X := const_Zero; +

135# + Step 6. for i := 1 to n-1 do +

136# + begin +

137# + Y := X XOR M_i; +

138# + X := AES-128(K,Y); +

139# + end +

140# + Y := M_last XOR X; +

141# + T := AES-128(K,Y); +

142# + Step 7. return T; +

143# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

144

145 const_Bsize = 16

146 const_Zero = bytearray(16)

147

148 AES_128= AES.new(K, AES.MODE_ECB)

149 M = bytearray(M[:length])

150 K1, K2 = Generate_Subkey(K)

151 n = len(M)//const_Bsize

152

153 if n == 0:

154 n = 1

155 flag = False

156 else:

157 if (length % const_Bsize) == 0:

158 flag = True

159 else:

160 n += 1

161 flag = False

162

163 M_n = M[(n-1)*const_Bsize:]

164 if flag is True:

165 M_last = XOR_128(M_n,K1)

166 else:

167 M_last = XOR_128(PAD(M_n),K2)

168

169 X = const_Zero

170 for i in range(n-1):

171 M_i = M[(i)*const_Bsize:][:16]

172 Y = XOR_128(X, M_i)

173 X = bytearray(AES_128.encrypt(bytes(Y)))

174 Y = XOR_128(M_last, X)

175 T = AES_128.encrypt(bytes(Y))

176

177 return T

178

179 def AES_CMAC_PRF_128(VK, M, VKlen, Mlen):

180# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

181# + AES-CMAC-PRF-128 +

182# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

183# + +

184# + Input : VK (Variable-length key) +

185# + : M (Message, i.e., the input data of the PRF) +

186# + : VKlen (length of VK in octets) +

187# + : len (length of M in octets) +

188# + Output : PRV (128-bit Pseudo-Random Variable) +

189# + +

190# +-------------------------------------------------------------------+

191# + Variable: K (128-bit key for AES-CMAC) +

192# + +

193# + Step 1. If VKlen is equal to 16 +

194# + Step 1a. then +

195# + K := VK; +

196# + Step 1b. else +

197# + K := AES-CMAC(0^128, VK, VKlen); +

198# + Step 2. PRV := AES-CMAC(K, M, len); +

199# + return PRV; +

200# + +

201# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

202 if VKlen == 16:

203 K = VK

204 else:

205 K = AES_CMAC(bytes(bytearray(16)), VK, VKlen)

206

207 PRV = AES_CMAC(K, M, Mlen)

208

209 return PRV

210

211 def KDF_CounterMode(KI, Label, Context, L):

212# Implements NIST SP 800-108 Section 5.1, with PRF HMAC-SHA256

213# https://tools.ietf.org/html/draft-irtf-cfrg-kdf-uses-00#ref-SP800-108

214# Fixed values:

215# 1. h - The length of the output of the PRF in bits, and

216# 2. r - The length of the binary representation of the counter i.

217# Input: KI, Label, Context, and L.

218# Process:

219# 1. n := [L/h]

220# 2. If n > 2r-1, then indicate an error and stop.

221# 3. result(0):= empty .

222# 4. For i = 1 to n, do

223# a. K(i) := PRF (KI, [i]2 || Label || 0x00 || Context || [L]2)

224# b. result(i) := result(i-1) || K(i).

225# 5. Return: KO := the leftmost L bits of result(n).

226 h = 256

227 r = 32

228

229 n = L // h

230

231 if n == 0: 231 ↛ 234line 231 didn't jump to line 234, because the condition on line 231 was never false

232 n = 1

233

234 if n > (pow(2,r)-1): 234 ↛ 235line 234 didn't jump to line 235, because the condition on line 234 was never true

235 raise Exception("Error computing KDF_CounterMode")

236

237 result = b''

238 K = b''

239

240 for i in range(1,n+1):

241 input = pack('>L', i) + Label + b'\x00' + Context + pack('>L',L)

242 K = hmac.new(KI, input, hashlib.sha256).digest()

243 result = result + K

244

245 return result[:(L//8)]

246

247# [MS-LSAD] Section 5.1.2 / 5.1.3

248 class LSA_SECRET_XP(Structure):

249 structure = (

250 ('Length','<L=0'),

251 ('Version','<L=0'),

252 ('_Secret','_-Secret', 'self["Length"]'),

253 ('Secret', ':'),

254 )

255

256

257 def transformKey(InputKey):

258 # Section 5.1.3

259 OutputKey = []

260 OutputKey.append( chr(ord(InputKey[0:1]) >> 0x01) )

261 OutputKey.append( chr(((ord(InputKey[0:1])&0x01)<<6) | (ord(InputKey[1:2])>>2)) )

262 OutputKey.append( chr(((ord(InputKey[1:2])&0x03)<<5) | (ord(InputKey[2:3])>>3)) )

263 OutputKey.append( chr(((ord(InputKey[2:3])&0x07)<<4) | (ord(InputKey[3:4])>>4)) )

264 OutputKey.append( chr(((ord(InputKey[3:4])&0x0F)<<3) | (ord(InputKey[4:5])>>5)) )

265 OutputKey.append( chr(((ord(InputKey[4:5])&0x1F)<<2) | (ord(InputKey[5:6])>>6)) )

266 OutputKey.append( chr(((ord(InputKey[5:6])&0x3F)<<1) | (ord(InputKey[6:7])>>7)) )

267 OutputKey.append( chr(ord(InputKey[6:7]) & 0x7F) )

268

269 for i in range(8):

270 OutputKey[i] = chr((ord(OutputKey[i]) << 1) & 0xfe)

271

272 return b("".join(OutputKey))

273

274 def decryptSecret(key, value):

275 # [MS-LSAD] Section 5.1.2

276 plainText = b''

277 key0 = key

278 for i in range(0, len(value), 8):

279 cipherText = value[:8]

280 tmpStrKey = key0[:7]

281 tmpKey = transformKey(tmpStrKey)

282 Crypt1 = DES.new(tmpKey, DES.MODE_ECB)

283 plainText += Crypt1.decrypt(cipherText)

284 key0 = key0[7:]

285 value = value[8:]

286 # AdvanceKey

287 if len(key0) < 7:

288 key0 = key[len(key0):]

289

290 secret = LSA_SECRET_XP(plainText)

291 return (secret['Secret'])

292

293 def encryptSecret(key, value):

294 # [MS-LSAD] Section 5.1.2

295 cipherText = b''

296 key0 = key

297 value0 = pack('<LL', len(value), 1) + value

298 for i in range(0, len(value0), 8):

299 if len(value0) < 8:

300 value0 = value0 + b'\x00'*(8-len(value0))

301 plainText = value0[:8]

302 tmpStrKey = key0[:7]

303 print(type(tmpStrKey))

304 print(tmpStrKey)

305 tmpKey = transformKey(tmpStrKey)

306 Crypt1 = DES.new(tmpKey, DES.MODE_ECB)

307 cipherText += Crypt1.encrypt(plainText)

308 key0 = key0[7:]

309 value0 = value0[8:]

310 # AdvanceKey

311 if len(key0) < 7:

312 key0 = key[len(key0):]

313

314 return cipherText

315

316 def SamDecryptNTLMHash(encryptedHash, key):

317 # [MS-SAMR] Section 2.2.11.1.1

318 Block1 = encryptedHash[:8]

319 Block2 = encryptedHash[8:]

320

321 Key1 = key[:7]

322 Key1 = transformKey(Key1)

323 Key2 = key[7:14]

324 Key2 = transformKey(Key2)

325

326 Crypt1 = DES.new(Key1, DES.MODE_ECB)

327 Crypt2 = DES.new(Key2, DES.MODE_ECB)

328

329 plain1 = Crypt1.decrypt(Block1)

330 plain2 = Crypt2.decrypt(Block2)

331

332 return plain1 + plain2

333

334 def SamEncryptNTLMHash(encryptedHash, key):

335 # [MS-SAMR] Section 2.2.11.1.1

336 Block1 = encryptedHash[:8]

337 Block2 = encryptedHash[8:]

338

339 Key1 = key[:7]

340 Key1 = transformKey(Key1)

341 Key2 = key[7:14]

342 Key2 = transformKey(Key2)

343

344 Crypt1 = DES.new(Key1, DES.MODE_ECB)

345 Crypt2 = DES.new(Key2, DES.MODE_ECB)

346

347 plain1 = Crypt1.encrypt(Block1)

348 plain2 = Crypt2.encrypt(Block2)

349

350 return plain1 + plain2