Hide keyboard shortcuts

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# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. 

2# 

3# This software is provided under under a slightly modified version 

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

5# for more information. 

6# 

7# Author: Alberto Solino (beto@coresecurity.com) 

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 

19from __future__ import division 

20from __future__ import print_function 

21from impacket import LOG 

22try: 

23 from Cryptodome.Cipher import DES, AES 

24except Exception: 

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

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

27from struct import pack, unpack 

28from impacket.structure import Structure 

29import hmac, hashlib 

30from six import b 

31 

32def Generate_Subkey(K): 

33 

34# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

35# + Algorithm Generate_Subkey + 

36# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

37# + + 

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

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

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

41# +-------------------------------------------------------------------+ 

42# + + 

43# + Constants: const_Zero is 0x00000000000000000000000000000000 + 

44# + const_Rb is 0x00000000000000000000000000000087 + 

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

46# + + 

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

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

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

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

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

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

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

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

55# + + 

56# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

57 

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

59 

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

61 

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

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

64 

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

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

67 

68 if (LHigh >> 63): 

69 K1Low ^= 0x87 

70 

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

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

73 

74 if (K1High >> 63): 

75 K2Low ^= 0x87 

76 

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

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

79 

80 return K1, K2 

81 

82def XOR_128(N1,N2): 

83 

84 J = bytearray() 

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

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

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

88 return J 

89 

90def PAD(N): 

91 padLen = 16-len(N) 

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

93 

94def AES_CMAC(K, M, length): 

95 

96# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

97# + Algorithm AES-CMAC + 

98# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

99# + + 

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

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

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

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

104# + + 

105# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

106# + Constants: const_Zero is 0x00000000000000000000000000000000 + 

107# + const_Bsize is 16 + 

108# + + 

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

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

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

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

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

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

115# + + 

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

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

118# + Step 3. if n = 0 + 

119# + then + 

120# + n := 1; + 

121# + flag := false; + 

122# + else + 

123# + if len mod const_Bsize is 0 + 

124# + then flag := true; + 

125# + else flag := false; + 

126# + + 

127# + Step 4. if flag is true + 

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

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

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

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

132# + begin + 

133# + Y := X XOR M_i; + 

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

135# + end + 

136# + Y := M_last XOR X; + 

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

138# + Step 7. return T; + 

139# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

140 

141 const_Bsize = 16 

142 const_Zero = bytearray(16) 

143 

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

145 M = bytearray(M[:length]) 

146 K1, K2 = Generate_Subkey(K) 

147 n = len(M)//const_Bsize 

148 

149 if n == 0: 

150 n = 1 

151 flag = False 

152 else: 

153 if (length % const_Bsize) == 0: 

154 flag = True 

155 else: 

156 n += 1 

157 flag = False 

158 

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

160 if flag is True: 

161 M_last = XOR_128(M_n,K1) 

162 else: 

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

164 

165 X = const_Zero 

166 for i in range(n-1): 

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

168 Y = XOR_128(X, M_i) 

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

170 Y = XOR_128(M_last, X) 

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

172 

173 return T 

174 

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

176# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

177# + AES-CMAC-PRF-128 + 

178# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

179# + + 

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

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

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

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

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

185# + + 

186# +-------------------------------------------------------------------+ 

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

188# + + 

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

190# + Step 1a. then + 

191# + K := VK; + 

192# + Step 1b. else + 

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

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

195# + return PRV; + 

196# + + 

197# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

198 if VKlen == 16: 

199 K = VK 

200 else: 

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

202 

203 PRV = AES_CMAC(K, M, Mlen) 

204 

205 return PRV 

206 

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

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

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

210# Fixed values: 

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

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

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

214# Process: 

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

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

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

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

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

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

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

222 h = 256 

223 r = 32 

224 

225 n = L // h 

226 

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

228 n = 1 

229 

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

231 raise Exception("Error computing KDF_CounterMode") 

232 

233 result = b'' 

234 K = b'' 

235 

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

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

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

239 result = result + K 

240 

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

242 

243# [MS-LSAD] Section 5.1.2 / 5.1.3 

244class LSA_SECRET_XP(Structure): 

245 structure = ( 

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

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

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

249 ('Secret', ':'), 

250 ) 

251 

252 

253def transformKey(InputKey): 

254 # Section 5.1.3 

255 OutputKey = [] 

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

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

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

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

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

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

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

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

264 

265 for i in range(8): 

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

267 

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

269 

270def decryptSecret(key, value): 

271 # [MS-LSAD] Section 5.1.2 

272 plainText = b'' 

273 key0 = key 

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

275 cipherText = value[:8] 

276 tmpStrKey = key0[:7] 

277 tmpKey = transformKey(tmpStrKey) 

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

279 plainText += Crypt1.decrypt(cipherText) 

280 key0 = key0[7:] 

281 value = value[8:] 

282 # AdvanceKey 

283 if len(key0) < 7: 

284 key0 = key[len(key0):] 

285 

286 secret = LSA_SECRET_XP(plainText) 

287 return (secret['Secret']) 

288 

289def encryptSecret(key, value): 

290 # [MS-LSAD] Section 5.1.2 

291 cipherText = b'' 

292 key0 = key 

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

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

295 if len(value0) < 8: 

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

297 plainText = value0[:8] 

298 tmpStrKey = key0[:7] 

299 print(type(tmpStrKey)) 

300 print(tmpStrKey) 

301 tmpKey = transformKey(tmpStrKey) 

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

303 cipherText += Crypt1.encrypt(plainText) 

304 key0 = key0[7:] 

305 value0 = value0[8:] 

306 # AdvanceKey 

307 if len(key0) < 7: 

308 key0 = key[len(key0):] 

309 

310 return cipherText 

311 

312def SamDecryptNTLMHash(encryptedHash, key): 

313 # [MS-SAMR] Section 2.2.11.1.1 

314 Block1 = encryptedHash[:8] 

315 Block2 = encryptedHash[8:] 

316 

317 Key1 = key[:7] 

318 Key1 = transformKey(Key1) 

319 Key2 = key[7:14] 

320 Key2 = transformKey(Key2) 

321 

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

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

324 

325 plain1 = Crypt1.decrypt(Block1) 

326 plain2 = Crypt2.decrypt(Block2) 

327 

328 return plain1 + plain2 

329 

330def SamEncryptNTLMHash(encryptedHash, key): 

331 # [MS-SAMR] Section 2.2.11.1.1 

332 Block1 = encryptedHash[:8] 

333 Block2 = encryptedHash[8:] 

334 

335 Key1 = key[:7] 

336 Key1 = transformKey(Key1) 

337 Key2 = key[7:14] 

338 Key2 = transformKey(Key2) 

339 

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

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

342 

343 plain1 = Crypt1.encrypt(Block1) 

344 plain2 = Crypt2.encrypt(Block2) 

345 

346 return plain1 + plain2