Coverage for /root/GitHubProjects/impacket/impacket/dpapi.py: 86%

# Coverage for /root/GitHubProjects/impacket/impacket/dpapi.py : 86%

## 530 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# 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:

8# Alberto Solino (@agsolino)

9#

10# Description:

11# DPAPI and Windows Vault parsing structures and manipulation

12#

13# References: All of the work done by these guys. I just adapted their work to my needs.

14# https://www.passcape.com/index.php?section=docsys&cmd=details&id=28

15# https://github.com/jordanbtucker/dpapick

16# https://github.com/gentilkiwi/mimikatz/wiki/howto-~-credential-manager-saved-credentials (and everything else Ben did )

17# http://blog.digital-forensics.it/2016/01/windows-revaulting.html

18# https://www.passcape.com/windows_password_recovery_vault_explorer

19# https://www.passcape.com/windows_password_recovery_dpapi_master_key

20#

21 from __future__ import division

22 from __future__ import print_function

23 import sys

24

25 from struct import unpack

26 from datetime import datetime

27 from binascii import unhexlify, hexlify

28 from struct import pack

29 from Cryptodome.Hash import HMAC, SHA512, SHA1

30 from Cryptodome.Cipher import AES, DES3

31 from Cryptodome.Util.Padding import unpad

32 from Cryptodome.PublicKey import RSA

33 from Cryptodome.Util.number import bytes_to_long

34 from six import PY3

35

36 from impacket.ese import getUnixTime

37 from impacket.structure import Structure, hexdump

38 from impacket.uuid import bin_to_string

39 from impacket.dcerpc.v5.enum import Enum

40 from impacket.dcerpc.v5.dtypes import RPC_SID

41

42# Algorithm classes

43 ALG_CLASS_ANY = (0)

44 ALG_CLASS_SIGNATURE = (1 << 13)

45 ALG_CLASS_MSG_ENCRYPT = (2 << 13)

46 ALG_CLASS_DATA_ENCRYPT = (3 << 13)

47 ALG_CLASS_HASH = (4 << 13)

48 ALG_CLASS_KEY_EXCHANGE = (5 << 13)

49 ALG_CLASS_ALL = (7 << 13)

50

51# Algorithm types

52 ALG_TYPE_ANY = (0)

53 ALG_TYPE_DSS = (1 << 9)

54 ALG_TYPE_RSA = (2 << 9)

55 ALG_TYPE_BLOCK = (3 << 9)

56 ALG_TYPE_STREAM = (4 << 9)

57 ALG_TYPE_DH = (5 << 9)

58 ALG_TYPE_SECURECHANNEL = (6 << 9)

59 ALG_SID_ANY = (0)

60 ALG_SID_RSA_ANY = 0

61 ALG_SID_RSA_PKCS = 1

62 ALG_SID_RSA_MSATWORK = 2

63 ALG_SID_RSA_ENTRUST = 3

64 ALG_SID_RSA_PGP = 4

65 ALG_SID_DSS_ANY = 0

66 ALG_SID_DSS_PKCS = 1

67 ALG_SID_DSS_DMS = 2

68 ALG_SID_ECDSA = 3

69

70# Block cipher sub ids

71 ALG_SID_DES = 1

72 ALG_SID_3DES = 3

73 ALG_SID_DESX = 4

74 ALG_SID_IDEA = 5

75 ALG_SID_CAST = 6

76 ALG_SID_SAFERSK64 = 7

77 ALG_SID_SAFERSK128 = 8

78 ALG_SID_3DES_112 = 9

79 ALG_SID_CYLINK_MEK = 12

80 ALG_SID_RC5 = 13

81 ALG_SID_AES_128 = 14

82 ALG_SID_AES_192 = 15

83 ALG_SID_AES_256 = 16

84 ALG_SID_AES = 17

85 ALG_SID_SKIPJACK = 10

86 ALG_SID_TEK = 11

87

88 CRYPT_MODE_CBCI = 6 # ANSI CBC Interleaved

89 CRYPT_MODE_CFBP = 7 # ANSI CFB Pipelined

90 CRYPT_MODE_OFBP = 8 # ANSI OFB Pipelined

91 CRYPT_MODE_CBCOFM = 9 # ANSI CBC + OF Masking

92 CRYPT_MODE_CBCOFMI = 10 # ANSI CBC + OFM Interleaved

93

94 ALG_SID_RC2 = 2

95 ALG_SID_RC4 = 1

96 ALG_SID_SEAL = 2

97

98# Diffie - Hellman sub - ids

99 ALG_SID_DH_SANDF = 1

100 ALG_SID_DH_EPHEM = 2

101 ALG_SID_AGREED_KEY_ANY = 3

102 ALG_SID_KEA = 4

103 ALG_SID_ECDH = 5

104

105# Hash sub ids

106 ALG_SID_MD2 = 1

107 ALG_SID_MD4 = 2

108 ALG_SID_MD5 = 3

109 ALG_SID_SHA = 4

110 ALG_SID_SHA1 = 4

111 ALG_SID_MAC = 5

112 ALG_SID_RIPEMD = 6

113 ALG_SID_RIPEMD160 = 7

114 ALG_SID_SSL3SHAMD5 = 8

115 ALG_SID_HMAC = 9

116 ALG_SID_TLS1PRF = 10

117 ALG_SID_HASH_REPLACE_OWF = 11

118 ALG_SID_SHA_256 = 12

119 ALG_SID_SHA_384 = 13

120 ALG_SID_SHA_512 = 14

121

122# secure channel sub ids

123 ALG_SID_SSL3_MASTER = 1

124 ALG_SID_SCHANNEL_MASTER_HASH = 2

125 ALG_SID_SCHANNEL_MAC_KEY = 3

126 ALG_SID_PCT1_MASTER = 4

127 ALG_SID_SSL2_MASTER = 5

128 ALG_SID_TLS1_MASTER = 6

129 ALG_SID_SCHANNEL_ENC_KEY = 7

130 ALG_SID_ECMQV = 1

131

132 def getFlags(myenum, flags):

133 return '|'.join([name for name, member in myenum.__members__.items() if member.value & flags])

134

135 class FLAGS(Enum):

136 CRYPTPROTECT_UI_FORBIDDEN = 0x1

137 CRYPTPROTECT_LOCAL_MACHINE = 0x4

138 CRYPTPROTECT_CRED_SYNC = 0x8

139 CRYPTPROTECT_AUDIT = 0x10

140 CRYPTPROTECT_VERIFY_PROTECTION = 0x40

141 CRYPTPROTECT_CRED_REGENERATE = 0x80

142 CRYPTPROTECT_SYSTEM = 0x20000000

143

144# algorithm identifier definitions

145 class ALGORITHMS(Enum):

146 CALG_MD2 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD2)

147 CALG_MD4 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD4)

148 CALG_MD5 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5)

149 CALG_SHA = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA)

150 CALG_SHA1 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1)

151 CALG_RSA_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | ALG_SID_RSA_ANY)

152 CALG_DSS_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY)

153 CALG_NO_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_ANY | ALG_SID_ANY)

154 CALG_RSA_KEYX = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_RSA|ALG_SID_RSA_ANY)

155 CALG_DES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_DES)

156 CALG_3DES_112 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_3DES_112)

157 CALG_3DES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_3DES)

158 CALG_DESX = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_DESX)

159 CALG_RC2 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_RC2)

160 CALG_RC4 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_STREAM|ALG_SID_RC4)

161 CALG_SEAL = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_STREAM|ALG_SID_SEAL)

162 CALG_DH_SF = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_DH_SANDF)

163 CALG_DH_EPHEM = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_DH_EPHEM)

164 CALG_AGREEDKEY_ANY = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_AGREED_KEY_ANY)

165 CALG_KEA_KEYX = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_KEA)

166 CALG_HUGHES_MD5 = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_ANY|ALG_SID_MD5)

167 CALG_SKIPJACK = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_SKIPJACK)

168 CALG_TEK = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_TEK)

169 CALG_SSL3_SHAMD5 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5)

170 CALG_SSL3_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SSL3_MASTER)

171 CALG_SCHANNEL_MASTER_HASH = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_MASTER_HASH)

172 CALG_SCHANNEL_MAC_KEY = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_MAC_KEY)

173 CALG_SCHANNEL_ENC_KEY = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_ENC_KEY)

174 CALG_PCT1_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_PCT1_MASTER)

175 CALG_SSL2_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SSL2_MASTER)

176 CALG_TLS1_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_TLS1_MASTER)

177 CALG_RC5 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_RC5)

178 CALG_HMAC = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)

179 CALG_TLS1PRF = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_TLS1PRF)

180 CALG_HASH_REPLACE_OWF = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HASH_REPLACE_OWF)

181 CALG_AES_128 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_128)

182 CALG_AES_192 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_192)

183 CALG_AES_256 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_256)

184 CALG_AES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES)

185 CALG_SHA_256 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)

186 CALG_SHA_384 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384)

187 CALG_SHA_512 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512)

188 CALG_ECDH = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_ECDH)

189 CALG_ECMQV = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_ECMQV)

190 CALG_ECDSA = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA)

191

192 class CREDENTIAL_FLAGS(Enum):

193 CRED_FLAGS_PASSWORD_FOR_CERT = 0x1

194 CRED_FLAGS_PROMPT_NOW = 0x2

195 CRED_FLAGS_USERNAME_TARGET = 0x4

196 CRED_FLAGS_OWF_CRED_BLOB = 0x8

197 CRED_FLAGS_REQUIRE_CONFIRMATION = 0x10

198 CRED_FLAGS_WILDCARD_MATCH = 0x20

199 CRED_FLAGS_VSM_PROTECTED = 0x40

200 CRED_FLAGS_NGC_CERT = 0x80

201

202 class CREDENTIAL_TYPE(Enum):

203 CRED_TYPE_GENERIC = 0x1

204 CRED_TYPE_DOMAIN_PASSWORD = 0x2

205 CRED_TYPE_DOMAIN_CERTIFICATE = 0x3

206 CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 0x4

207 CRED_TYPE_GENERIC_CERTIFICATE = 0x5

208 CRED_TYPE_DOMAIN_EXTENDED = 0x6

209 CRED_TYPE_MAXIMUM = 0x7

210 CRED_TYPE_MAXIMUM_EX = 0x8

211

212 class CREDENTIAL_PERSIST(Enum):

213 CRED_PERSIST_NONE = 0x0

214 CRED_PERSIST_SESSION = 0x1

215 CRED_PERSIST_LOCAL_MACHINE = 0x2

216 CRED_PERSIST_ENTERPRISE = 0x3

217

218 ALGORITHMS_DATA = {

219 # Algorithm: key/SaltLen, CryptHashModule, Mode, IVLen, BlockSize

220 ALGORITHMS.CALG_SHA.value: (160//8, SHA1, None, None, 512//8),

221 ALGORITHMS.CALG_HMAC.value: (160//8, SHA512, None, None, 512//8),

222 ALGORITHMS.CALG_3DES.value: (192//8, DES3, DES3.MODE_CBC, 64//8),

223 ALGORITHMS.CALG_SHA_512.value: (128//8, SHA512, None, None, 1024//8),

224 ALGORITHMS.CALG_AES_256.value: (256//8, AES, AES.MODE_CBC, 128//8),

225}

226

227 class MasterKeyFile(Structure):

228 structure = (

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

230 ('unk1', '<L=0'),

231 ('unk2', '<L=0'),

232 ('Guid', "72s=b''"),

233 ('Unkown', '<L=0'),

234 ('Policy', '<L=0'),

235 ('Flags', '<L=0'),

236 ('MasterKeyLen', '<Q=0'),

237 ('BackupKeyLen', '<Q=0'),

238 ('CredHistLen', '<Q=0'),

239 ('DomainKeyLen', '<Q=0'),

240 )

241

242 def dump(self):

243 print("[MASTERKEYFILE]")

244 print("Version : %8x (%d)" % (self['Version'], self['Version']))

245 print("Guid : %s" % self['Guid'].decode('utf-16le'))

246 print("Flags : %8x (%d)" % (self['Flags'], self['Flags']))

247 print("Policy : %8x (%d)" % (self['Policy'], self['Policy']))

248 print("MasterKeyLen: %.8x (%d)" % (self['MasterKeyLen'], self['MasterKeyLen']))

249 print("BackupKeyLen: %.8x (%d)" % (self['BackupKeyLen'], self['BackupKeyLen']))

250 print("CredHistLen : %.8x (%d)" % (self['CredHistLen'], self['CredHistLen']))

251 print("DomainKeyLen: %.8x (%d)" % (self['DomainKeyLen'], self['DomainKeyLen']))

252 print()

253

254 class MasterKey(Structure):

255 structure = (

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

257 ('Salt', '16s=b""'),

258 ('MasterKeyIterationCount', '<L=0'),

259 ('HashAlgo', "<L=0"),

260 ('CryptAlgo', '<L=0'),

261 ('data', ':'),

262 )

263

264 def __init__(self, data = None, alignment = 0):

265 Structure.__init__(self, data, alignment)

266 self.decryptedKey = None

267

268 def dump(self):

269 print("[MASTERKEY]")

270 print("Version : %8x (%d)" % (self['Version'], self['Version']))

271 print("Salt : %s" % hexlify(self['Salt']))

272 print("Rounds : %8x (%d)" % (self['MasterKeyIterationCount'], self['MasterKeyIterationCount']))

273 print("HashAlgo : %.8x (%d) (%s)" % (self['HashAlgo'], self['HashAlgo'], ALGORITHMS(self['HashAlgo']).name))

274 print("CryptAlgo : %.8x (%d) (%s)" % (self['CryptAlgo'], self['CryptAlgo'], ALGORITHMS(self['CryptAlgo']).name))

275 print("data : %s" % (hexlify(self['data'])))

276 print()

277

278 def deriveKey(self, passphrase, salt, keylen, count, hashFunction):

279 keyMaterial = b""

280 i = 1

281 while len(keyMaterial) < keylen:

282 U = salt + pack("!L", i)

283 i += 1

284 derived = bytearray(hashFunction(passphrase, U))

285 for r in range(count - 1):

286 actual = bytearray(hashFunction(passphrase, derived))

287 if PY3: 287 ↛ 290line 287 didn't jump to line 290, because the condition on line 287 was never false

288 derived = (int.from_bytes(derived, sys.byteorder) ^ int.from_bytes(actual, sys.byteorder)).to_bytes(len(actual), sys.byteorder)

289 else:

290 derived = bytearray([ chr((a) ^ (b)) for (a,b) in zip(derived, actual) ])

291 keyMaterial += derived

292

293 return keyMaterial[:keylen]

294

295 def decrypt(self, key):

296 if self['HashAlgo'] == ALGORITHMS.CALG_HMAC.value: 296 ↛ 297line 296 didn't jump to line 297, because the condition on line 296 was never true

297 hashModule = SHA1

298 else:

299 hashModule = ALGORITHMS_DATA[self['HashAlgo']][1]

300

301 prf = lambda p, s: HMAC.new(p, s, hashModule).digest()

302 derivedBlob = self.deriveKey(key, self['Salt'],

303 ALGORITHMS_DATA[self['CryptAlgo']][0] + ALGORITHMS_DATA[self['CryptAlgo']][3],

304 count=self['MasterKeyIterationCount'], hashFunction=prf)

305

306 cryptKey = derivedBlob[:ALGORITHMS_DATA[self['CryptAlgo']][0]]

307 iv = derivedBlob[ALGORITHMS_DATA[self['CryptAlgo']][0]:][:ALGORITHMS_DATA[self['CryptAlgo']][3]]

308

309 cipher = ALGORITHMS_DATA[self['CryptAlgo']][1].new(cryptKey, mode = ALGORITHMS_DATA[self['CryptAlgo']][2], iv = iv)

310 cleartext = cipher.decrypt(self['data'])

311

312 decryptedKey = cleartext[-64:]

313 hmacSalt = cleartext[:16]

314 hmac = cleartext[16:][:ALGORITHMS_DATA[self['HashAlgo']][0]]

315

316 hmacKey = HMAC.new(key, hmacSalt, hashModule).digest()

317

318 hmacCalculated = HMAC.new(hmacKey, decryptedKey, hashModule ).digest()

319

320 if hmacCalculated[:ALGORITHMS_DATA[self['HashAlgo']][0]] == hmac: 320 ↛ 324line 320 didn't jump to line 324, because the condition on line 320 was never false

321 self.decryptedKey = decryptedKey

322 return decryptedKey

323 else:

324 return None

325

326 class CredHist(Structure):

327 structure = (

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

329 ('Guid', "16s=b''"),

330 )

331 def dump(self):

332 print("[CREDHIST]")

333 print("Version : %8x (%d)" % (self['Version'], self['Version']))

334 print("Guid : %s" % bin_to_string(self['Guid']))

335 print()

336

337 class DomainKey(Structure):

338 structure = (

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

340 ('SecretLen', '<L=0'),

341 ('AccessCheckLen', '<L=0'),

342 ('Guid', "16s=b"""),

343 ('_SecretData', '_-SecretData', 'self["SecretLen"]'),

344 ('SecretData', ':'),

345 ('_AccessCheck', '_-AccessCheck', 'self["AccessCheckLen"]'),

346 ('AccessCheck', ':'),

347 )

348 def dump(self):

349 print("[DOMAINKEY]")

350 print("Version : %8x (%d)" % (self['Version'], self['Version']))

351 print("Guid : %s" % bin_to_string(self['Guid']))

352 print("SecretLen : %8x (%d)" % (self['SecretLen'], self['SecretLen']))

353 print("AccessCheckLen: %.8x (%d)" % (self['AccessCheckLen'], self['AccessCheckLen']))

354 print("SecretData : %s" % (hexlify(self['SecretData'])))

355 print("AccessCheck : %s" % (hexlify(self['AccessCheck'])))

356 print()

357

358 class DPAPI_SYSTEM(Structure):

359 structure = (

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

361 ('MachineKey', '20s=b""'),

362 ('UserKey', '20s=b""'),

363 )

364

365 def dump(self):

366 print("[DPAPI_SYSTEM]")

367 print("Version : %8x (%d)" % (self['Version'], self['Version']))

368 print("MachineKey : 0x%s" % hexlify(self['MachineKey']).decode('latin-1'))

369 print("UserKey : 0x%s" % hexlify(self['UserKey']).decode('latin-1'))

370 print()

371

372 class CredentialFile(Structure):

373 structure = (

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

375 ('Size', '<L=0'),

376 ('Unknown', '<L=0'),

377 ('_Data', '_-Data', 'self["Size"]'),

378 ('Data', ':'),

379 )

380 #def dump(self):

381 # print("[CREDENTIAL FILE]")

382 # print("Version : %8x (%d)" % (self['Version'], self['Version']))

383 # print("MachineKey : %s" % hexlify(self['MachineKey']))

384 # print("UserKey : %s" % hexlify(self['UserKey']))

385 # print("CryptAlgo : %.8x (%d) (%s)" % (self['CryptAlgo'], self['CryptAlgo'], ALGORITHMS(self['CryptAlgo']).name))

386 # print()

387

388

389 class DPAPI_BLOB(Structure):

390 structure = (

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

392 ('GuidCredential', "16s=b"""),

393 ('MasterKeyVersion', '<L=0'),

394 ('GuidMasterKey', "16s=b"""),

395 ('Flags', '<L=0'),

396

397 ('DescriptionLen', '<L=0'),

398 ('_Description', '_-Description', 'self["DescriptionLen"]'),

399 ('Description', ':'),

400

401 ('CryptAlgo', '<L=0'),

402 ('CryptAlgoLen', '<L=0'),

403

404 ('SaltLen', '<L=0'),

405 ('_Salt', '_-Salt', 'self["SaltLen"]'),

406 ('Salt', ':'),

407

408 ('HMacKeyLen', '<L=0'),

409 ('_HMacKey', '_-HMacKey', 'self["HMacKeyLen"]'),

410 ('HMacKey', ':'),

411

412 ('HashAlgo', '<L=0'),

413 ('HashAlgoLen', '<L=0'),

414

415 ('HMac', '<L=0'),

416 ('_HMac', '_-HMac', 'self["HMac"]'),

417 ('HMac', ':'),

418

419 ('DataLen', '<L=0'),

420 ('_Data', '_-Data', 'self["DataLen"]'),

421 ('Data', ':'),

422

423 ('SignLen', '<L=0'),

424 ('_Sign', '_-Sign', 'self["SignLen"]'),

425 ('Sign', ':'),

426

427 )

428

429 def dump(self):

430 print("[BLOB]")

431 print("Version : %8x (%d)" % (self['Version'], self['Version']))

432 print("Guid Credential : %s" % bin_to_string(self['GuidCredential']))

433 print("MasterKeyVersion : %8x (%d)" % (self['MasterKeyVersion'], self['MasterKeyVersion']))

434 print("Guid MasterKey : %s" % bin_to_string(self['GuidMasterKey']))

435 print("Flags : %8x (%s)" % (self['Flags'], getFlags(FLAGS, self['Flags'])))

436 print("Description : %s" % (self['Description'].decode('utf-16le')))

437 print("CryptAlgo : %.8x (%d) (%s)" % (self['CryptAlgo'], self['CryptAlgo'], ALGORITHMS(self['CryptAlgo']).name))

438 print("Salt : %s" % (hexlify(self['Salt'])))

439 print("HMacKey : %s" % (hexlify(self['HMacKey'])))

440 print("HashAlgo : %.8x (%d) (%s)" % (self['HashAlgo'], self['HashAlgo'], ALGORITHMS(self['HashAlgo']).name))

441 print("HMac : %s" % (hexlify(self['HMac'])))

442 print("Data : %s" % (hexlify(self['Data'])))

443 print("Sign : %s" % (hexlify(self['Sign'])))

444 print()

445

446

447 def deriveKey(self, sessionKey):

448 def fixparity(deskey):

449 from six import indexbytes, b

450 temp = b''

451 for i in range(len(deskey)):

452 t = (bin(indexbytes(deskey,i))[2:]).rjust(8,'0')

453 if t[:7].count('1') %2 == 0:

454 temp+= b(chr(int(t[:7]+'1',2)))

455 else:

456 temp+= b(chr(int(t[:7]+'0',2)))

457 return temp

458

459 if len(sessionKey) > ALGORITHMS_DATA[self['HashAlgo']][4]: 459 ↛ 460line 459 didn't jump to line 460, because the condition on line 459 was never true

460 derivedKey = HMAC.new(sessionKey, digestmod = ALGORITHMS_DATA[self['HashAlgo']][1]).digest()

461 else:

462 derivedKey = sessionKey

463

464

465 if len(derivedKey) < ALGORITHMS_DATA[self['CryptAlgo']][0]:

466 # Extend the key

467 derivedKey += b'\x00'*ALGORITHMS_DATA[self['HashAlgo']][4]

468 ipad = bytearray([ i ^ 0x36 for i in bytearray(derivedKey)][:ALGORITHMS_DATA[self['HashAlgo']][4]])

469 opad = bytearray([ i ^ 0x5c for i in bytearray(derivedKey)][:ALGORITHMS_DATA[self['HashAlgo']][4]])

470 derivedKey = ALGORITHMS_DATA[self['HashAlgo']][1].new(ipad).digest() + \

471 ALGORITHMS_DATA[self['HashAlgo']][1].new(opad).digest()

472 derivedKey = fixparity(derivedKey)

473

474 return derivedKey

475

476 def decrypt(self, key, entropy = None):

477 keyHash = SHA1.new(key).digest()

478 sessionKey = HMAC.new(keyHash, self['Salt'], ALGORITHMS_DATA[self['HashAlgo']][1])

479 if entropy is not None: 479 ↛ 480line 479 didn't jump to line 480, because the condition on line 479 was never true

480 sessionKey.update(entropy)

481

482 sessionKey = sessionKey.digest()

483

484 # Derive the key

485 derivedKey = self.deriveKey(sessionKey)

486

487 cipher = ALGORITHMS_DATA[self['CryptAlgo']][1].new(derivedKey[:ALGORITHMS_DATA[self['CryptAlgo']][0]],

488 mode=ALGORITHMS_DATA[self['CryptAlgo']][2], iv=b'\x00'*ALGORITHMS_DATA[self['CryptAlgo']][3])

489 cleartext = unpad(cipher.decrypt(self['Data']), ALGORITHMS_DATA[self['CryptAlgo']][1].block_size)

490

491 # Now check the signature

492

493 # ToDo Fix this, it's just ugly, more testing so we can remove one

494 toSign = (self.rawData[20:][:len(self.rawData)-20-len(self['Sign'])-4])

495

496 # Calculate the different HMACKeys

497 keyHash2 = keyHash + b"\x00"*ALGORITHMS_DATA[self['HashAlgo']][1].block_size

498 ipad = bytearray([i ^ 0x36 for i in bytearray(keyHash2)][:ALGORITHMS_DATA[self['HashAlgo']][1].block_size])

499 opad = bytearray([i ^ 0x5c for i in bytearray(keyHash2)][:ALGORITHMS_DATA[self['HashAlgo']][1].block_size])

500 a = ALGORITHMS_DATA[self['HashAlgo']][1].new(ipad)

501 a.update(self['HMac'])

502

503 hmacCalculated1 = ALGORITHMS_DATA[self['HashAlgo']][1].new(opad)

504 hmacCalculated1.update(a.digest())

505

506 if entropy is not None: 506 ↛ 507line 506 didn't jump to line 507, because the condition on line 506 was never true

507 hmacCalculated1.update(entropy)

508

509 hmacCalculated1.update(toSign)

510

511 hmacCalculated3 = HMAC.new(keyHash, self['HMac'], ALGORITHMS_DATA[self['HashAlgo']][1])

512 if entropy is not None: 512 ↛ 513line 512 didn't jump to line 513, because the condition on line 512 was never true

513 hmacCalculated3.update(entropy)

514

515 hmacCalculated3.update(toSign)

516

517 if hmacCalculated1.digest() == self['Sign'] or hmacCalculated3.digest() == self['Sign']: 517 ↛ 520line 517 didn't jump to line 520, because the condition on line 517 was never false

518 return cleartext

519 else:

520 return None

521

522 class VAULT_ATTRIBUTE(Structure):

523 structure = (

524 ('Id', '<L=0'),

525 ('Unknown1', '<L=0'),

526 ('Unknown2', '<L=0'),

527 ('Unknown3', '<L=0'),

528 )

529

530 padding = (

531 ('Pad', '6s=b""'),

532 )

533

534 id100 = (

535 ('Unknown5', '<L=0'),

536 )

537

538 extended = (

539 ('Size','<L=0'),

540 ('IVPresent', '<B=?&IVSize'),

541 ('IVSize', '<L=0'),

542 ('_IV', '_-IV', 'self["IVSize"] if self["IVSize"] is not None else 0'),

543 ('IV', ':'),

544 ('_Data','_-Data', 'self["Size"]-self["IVSize"]-5 if self["IVPresent"] else self["Size"]-1'),

545 ('Data',':'),

546 )

547 def __init__(self, data = None, alignment = 0):

548 if len(data) > 20: 548 ↛ 555line 548 didn't jump to line 555, because the condition on line 548 was never false

549 if data[16:][:6] == b'\x00'*6: 549 ↛ 550line 549 didn't jump to line 550, because the condition on line 549 was never true

550 self.structure += self.padding

551 if unpack('<L',data[:4])[0] >= 100:

552 self.structure += self.id100

553 if len(data[16:]) >= 9:

554 self.structure += self.extended

555 Structure.__init__(self, data, alignment)

556

557

558 def dump(self):

559 print("[ATTRIBUTE %d]" % self['Id'])

560 if len(self.rawData) > 28:

561 print("Size : 0x%x" % self['Size'])

562 if self['IVPresent'] > 0:

563 print("IVSize : 0x%x" % self['IVSize'])

564 print("IV : %s" % hexlify(self['IV']))

565 print("Data : %s" % hexlify(self['Data']))

566

567 class VAULT_ATTRIBUTE_MAP_ENTRY(Structure):

568 structure = (

569 ('Id', '<L=0'),

570 ('Offset', '<L=0'),

571 ('Unknown1', '<L=0'),

572 )

573 def dump(self):

574 print("[MAP ENTRY %d @ 0x%.8x]" % (self['Id'], self['Offset']))

575

576 class VAULT_VCRD(Structure):

577 structure = (

578 ('SchemaGuid', "16s=b"""),

579 ('Unknown0', '<L=0'),

580 ('LastWritten', '<Q=0'),

581 ('Unknown1', '<L=0'),

582 ('Unknown2', '<L=0'),

583 ('FriendlyNameLen', '<L=0'),

584 ('FriendlyNameL', '_-FriendlyName', 'self["FriendlyNameLen"]'),

585 ('FriendlyName', ':'),

586 ('AttributesMapsSize', '<L=0'),

587 ('AttributeL', '_-AttributeMaps', 'self["AttributesMapsSize"]'),

588 ('AttributeMaps', ':'),

589 ('Data', ':'),

590 )

591

592 def __init__(self, data = None, alignment = 0):

593 Structure.__init__(self, data, alignment)

594 if data is not None: 594 ↛ exitline 594 didn't return from function '__init__', because the condition on line 594 was never false

595 # Process the MAP entries

596 self.mapEntries = list()

597 data = self['AttributeMaps']

598 for i in range(self['AttributesMapsSize']//len(VAULT_ATTRIBUTE_MAP_ENTRY())):

599 entry = VAULT_ATTRIBUTE_MAP_ENTRY(data)

600 self.mapEntries.append(entry)

601 data = data[len(VAULT_ATTRIBUTE_MAP_ENTRY()):]

602

603 self.attributesLen = list()

604

605 for i in range(len(self.mapEntries)):

606 if i > 0:

607 self.attributesLen.append(self.mapEntries[i]['Offset']-self.mapEntries[i-1]['Offset'])

608

609 self.attributesLen.append(len(self.rawData) - self.mapEntries[i]['Offset'] )

610

611 self.attributes = list()

612 for i, entry in enumerate(self.mapEntries):

613 attribute = VAULT_ATTRIBUTE(self.rawData[entry['Offset']:][:self.attributesLen[i]])

614 self.attributes.append(attribute)

615

616 # Do we have remaining data?

617 self['Data'] = self.rawData[self.mapEntries[-1]['Offset']+len(self.attributes[-1].getData()):]

618

619 def dump(self):

620 print("[VCRD]")

621 print("SchemaGuid : %s" % bin_to_string(self['SchemaGuid']))

622 print("LastWritten : %s" % (datetime.utcfromtimestamp(getUnixTime(self['LastWritten']))))

623 print("FriendlyName: %s" % (self['FriendlyName'].decode('utf-16le')))

624 print()

625 for i,entry in enumerate(self.mapEntries):

626 entry.dump()

627 self.attributes[i].dump()

628 print()

629 print("Remaining : %s" % (hexlify(self['Data'])))

630 print()

631

632 class VAULT_VPOL(Structure):

633 structure = (

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

635 ('Guid', "16s=b"""),

636 ('DescriptionLen', '<L=0'),

637 ('_Description', '_-Description', 'self["DescriptionLen"]'),

638 ('Description', ':'),

639 ('Unknown', '12s=b""'),

640 ('Size', '<L=0'),

641 ('Guid2', "16s=b"""),

642 ('Guid3', "16s=b"""),

643 ('KeySize','<L=0'),

644 ('_Blob', '_-Blob', 'self["KeySize"]'),

645 ('Blob', ':', DPAPI_BLOB),

646 )

647

648 def dump(self):

649 print("[VAULT_VPOL]")

650 print("Version : %8x (%d)" % (self['Version'], self['Version']))

651 print("Guid : %s" % bin_to_string(self['Guid']))

652 print("Description : %s" % (self['Description'].decode('utf-16le')))

653 print("Size : 0x%.8x (%d)" % (self['Size'], self['Size']))

654 print("Guid2 : %s" % bin_to_string(self['Guid2']))

655 print("Guid3 : %s" % bin_to_string(self['Guid3']))

656 print("KeySize : 0x%.8x (%d)" % (self['KeySize'], self['KeySize']))

657 self['Blob'].dump()

658 print()

659

660# from bcrypt.h

661 class BCRYPT_KEY_DATA_BLOB_HEADER(Structure):

662 structure = (

663 ('dwMagic','<L=0'),

664 ('dwVersion','<L=0'),

665 ('cbKeyData','<L=0'),

666 ('_bKey','_-bKey', 'self["cbKeyData"]'),

667 ('bKey',':'),

668 )

669

670# from https://media.defcon.org/DEF%20CON%2024/DEF%20CON%2024%20presentations/DEFCON-24-Jkambic-Cunning-With-Cng-Soliciting-Secrets-From-Schannel-WP.pdf

671 class BCRYPT_KSSM_DATA_BLOB_HEADER(Structure):

672 structure = (

673 ('cbLength','<L=0'),

674 ('dwKeyMagic','<L=0'),

675 ('dwUnknown2','<L=0'),

676 ('dwUnknown3','<L=0'),

677 ('dwKeyBitLen','<L=0'),

678 ('cbKeyLength','<L=0'),

679 #('_bKey','_-bKey', 'self["cbKeyData"]'),

680 #('AesKey','32s=""'),

681 #('dwUnknown4','<L=0'),

682 #('KeySchedule','448s=""'),

683 #('dwUnknown5','<L=0'),

684 #('cbScheduleLen','<L=0'),

685 #('Unknown6','16s=""'),

686 )

687

688 class BCRYPT_KEY_WRAP(Structure):

689 structureKDBM = (

690 ('Size','<L=0'),

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

692 ('Unknown2','<L=0'),

693 ('_bKeyBlob','_-bKeyBlob', 'self["Size"]'),

694 ('bKeyBlob',':', BCRYPT_KEY_DATA_BLOB_HEADER),

695 )

696 structureKSSM = (

697 ('Size','<L=0'),

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

699 ('Unknown2','<L=0'),

700 ('_bKeyBlob','_-bKeyBlob', 'self["Size"]-8'),

701 ('bKeyBlob',':'),

702 )

703 def __init__(self, data = None, alignment = 0):

704 if len(data) >=16: 704 ↛ 709line 704 didn't jump to line 709, because the condition on line 704 was never false

705 if data[0:1] == b'\x24' or data[0:1] == b'\x34': 705 ↛ 708line 705 didn't jump to line 708, because the condition on line 705 was never false

706 self.structure = self.structureKDBM

707 else:

708 self.structure = self.structureKSSM

709 Structure.__init__(self, data, alignment)

710

711 class VAULT_VPOL_KEYS(Structure):

712 structure = (

713 ('Key1',':', BCRYPT_KEY_WRAP),

714 ('Key2',':', BCRYPT_KEY_WRAP),

715 )

716 def dump(self):

717 print("[VAULT_VPOL_KEYS]")

718 if self['Key1']['Size'] > 0x24: 718 ↛ 719line 718 didn't jump to line 719, because the condition on line 718 was never true

719 print('Key1:')

720 hexdump(self['Key1']['bKeyBlob'])

721 print('Key2:')

722 hexdump(self['Key2']['bKeyBlob'])

723 else:

724 print('Key1: 0x%s' % hexlify(self['Key1']['bKeyBlob']['bKey']).decode('latin-1'))

725 print('Key2: 0x%s' % hexlify(self['Key2']['bKeyBlob']['bKey']).decode('latin-1'))

726 print()

727

728 class VAULT_INTERNET_EXPLORER(Structure):

729 structure = (

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

731 ('Count','<L=0'),

732 ('Unknown','<L=0'),

733 ('Id1', '<L=0'),

734 ('UsernameLen', '<L=0'),

735 ('_Username', '_-Username','self["UsernameLen"]'),

736 ('Username', ':'),

737

738 ('Id2', '<L=0'),

739 ('ResourceLen', '<L=0'),

740 ('_Resource', '_-Resource', 'self["ResourceLen"]'),

741 ('Resource', ':'),

742

743 ('Id3', '<L=0'),

744 ('PasswordLen', '<L=0'),

745 ('_Password', '_-Password', 'self["PasswordLen"]'),

746 ('Password', ':'),

747 )

748 def fromString(self, data):

749 Structure.fromString(self, data)

750

751 def dump(self):

752 print("[Internet Explorer]")

753 print('Username : %s' % self['Username'].decode('utf-16le'))

754 print('Resource : %s' % self['Resource'].decode('utf-16le'))

755 print('Password : %s' % (hexlify(self['Password'])))

756 print()

757

758 class VAULT_WIN_BIO_KEY(Structure):

759 structure = (

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

761 ('Count','<L=0'),

762 ('Unknown','<L=0'),

763 ('Id1', '<L=0'),

764 ('SidLen', '<L=0'),

765 ('_Sid', '_-Sid','self["SidLen"]'),

766 ('Sid', ':'),

767

768 ('Id2', '<L=0'),

769 ('NameLen', '<L=0'),

770 ('_Name', '_-Name', 'self["NameLen"]'),

771 ('Name', ':'),

772

773 ('Id3', '<L=0'),

774 ('BioKeyLen', '<L=0'),

775 ('_BioKey', '_-BioKey', 'self["BioKeyLen"]'),

776 ('BioKey', ':'),

777 )

778 def fromString(self, data):

779 Structure.fromString(self, data)

780 if data is not None:

781 bioKey = BCRYPT_KEY_DATA_BLOB_HEADER(unhexlify(self['BioKey'].decode('utf-16le')[:-1]))

782 self['BioKey'] = bioKey

783

784 def dump(self):

785 print("[WINDOWS BIOMETRIC KEY]")

786 print('Sid : %s' % RPC_SID(b'\x05\x00\x00\x00'+self['Sid']).formatCanonical())

787 print('Friendly Name: %s' % self['Name'].decode('utf-16le'))

788 print('Biometric Key: 0x%s' % (hexlify(self['BioKey']['bKey'])).decode('latin-1'))

789 print()

790

791 class NGC_LOCAL_ACCOOUNT(Structure):

792 structure = (

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

794 ('UnlockKeySize','<L=0'),

795 ('IVSize','<L=0'),

796 ('CipherTextSize','<L=0'),

797 ('MustBeZeroTest','<L=0'),

798 ('_UnlockKey', '_-UnlockKey', 'self["UnlockKeySize"]'),

799 ('UnlockKey', ':'),

800 ('_IV', '_-IV', 'self["IVSize"]'),

801 ('IV', ':'),

802 ('_CipherText', '_-CipherText', 'self["CipherTextSize"]'),

803 ('CipherText', ':'),

804 )

805# def __init__(self, data=None, alignment = 0):

806# hexdump(data)

807 def dump(self):

808 print("[NGC LOCAL ACCOOUNT]")

809 print('UnlockKey : %s' % hexlify(self["UnlockKey"]))

810 print('IV : %s' % hexlify(self["IV"]))

811 print('CipherText : %s' % hexlify(self["CipherText"]))

812

813 class VAULT_NGC_ACCOOUNT(Structure):

814 structure = (

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

816 ('Count','<L=0'),

817 ('Unknown','<L=0'),

818 ('Id1', '<L=0'),

819 ('SidLen', '<L=0'),

820 ('_Sid', '_-Sid','self["SidLen"]'),

821 ('Sid', ':'),

822

823 ('Id2', '<L=0'),

824 ('NameLen', '<L=0'),

825 ('_Name', '_-Name', 'self["NameLen"]'),

826 ('Name', ':'),

827

828 ('Id3', '<L=0'),

829 ('BlobLen', '<L=0'),

830 ('Blob', '_-Blob', 'self["BlobLen"]'),

831 ('Blob', ':', NGC_LOCAL_ACCOOUNT),

832 )

833 def dump(self):

834 print("[NGC VAULT]")

835 print('Sid : %s' % RPC_SID(b'\x05\x00\x00\x00'+self['Sid']).formatCanonical())

836 print('Friendly Name: %s' % self['Name'].decode('utf-16le'))

837 self['Blob'].dump()

838 print()

839

840 VAULT_KNOWN_SCHEMAS = {

841 'WinBio Key': VAULT_WIN_BIO_KEY,

842 'NGC Local Accoount Logon Vault Credential': VAULT_NGC_ACCOOUNT,

843 'Internet Explorer': VAULT_INTERNET_EXPLORER,

844}

845

846 class CREDENTIAL_ATTRIBUTE(Structure):

847 # some info here https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credential_attributea

848 structure = (

849 ('Flags','<L=0'),

850

851 ('KeyWordSize', '<L=0'),

852 ('_KeyWord', '_-KeyWord', 'self["KeyWordSize"]'),

853 ('KeyWord', ':'),

854

855 ('DataSize', '<L=0'),

856 ('_Data', '_-Data', 'self["DataSize"]'),

857 ('Data', ':'),

858 )

859

860 def dump(self):

861 print("KeyWord : %s" % (self['KeyWord'].decode('utf-16le')))

862 #print("Flags : %8x (%s)" % (self['Flags'], getFlags(CREDENTIAL_FLAGS, self['Flags'])))

863 print("Data : ")

864 hexdump(self['Data'])

865

866 class CREDENTIAL_BLOB(Structure):

867 # some info here https://docs.microsoft.com/en-us/windows/desktop/api/wincred/ns-wincred-_credentiala

868 structure = (

869 ('Flags','<L=0'),

870 ('Size','<L=0'),

871 ('Unknown0','<L=0'),

872 ('Type','<L=0'),

873 ('Flags2','<L=0'),

874 ('LastWritten','<Q=0'),

875 ('Unknown2','<L=0'),

876 ('Persist','<L=0'),

877 ('AttrCount','<L=0'),

878 ('Unknown3','<Q=0'),

879

880 ('TargetSize','<L=0'),

881 ('_Target','_-Target','self["TargetSize"]'),

882 ('Target',':'),

883

884 ('TargetAliasSize', '<L=0'),

885 ('_TargetAliast', '_-TargetAlias', 'self["TargetAliasSize"]'),

886 ('TargetAlias', ':'),

887

888 ('DescriptionSize', '<L=0'),

889 ('_Description', '_-Description', 'self["DescriptionSize"]'),

890 ('Description', ':'),

891

892 ('UnknownSize', '<L=0'),

893 ('_Unknown', '_-Unknown', 'self["UnknownSize"]'),

894 ('Unknown', ':'),

895

896 ('UsernameSize', '<L=0'),

897 ('_Username', '_-Username', 'self["UsernameSize"]'),

898 ('Username', ':'),

899

900 ('Unknown3Size', '<L=0'),

901 ('_Unknown3', '_-Unknown3', 'self["Unknown3Size"]'),

902 ('Unknown3', ':'),

903

904 ('Remaining', ':'),

905 )

906 def __init__(self, data = None, alignment = 0):

907 Structure.__init__(self, data, alignment)

908 self.attributes = 0

909 if data is not None: 909 ↛ exitline 909 didn't return from function '__init__', because the condition on line 909 was never false

910 # Unpack the attributes

911 remaining = self['Remaining']

912 self.attributes = list()

913 for i in range(self['AttrCount']): 913 ↛ 914line 913 didn't jump to line 914, because the loop on line 913 never started

914 attr = CREDENTIAL_ATTRIBUTE(remaining)

915 self.attributes.append(attr)

916 remaining = remaining[len(attr):]

917

918 def dump(self):

919 print("[CREDENTIAL]")

920 print("LastWritten : %s" % (datetime.utcfromtimestamp(getUnixTime(self['LastWritten']))))

921 print("Flags : 0x%.8x (%s)" % (self['Flags'], getFlags(CREDENTIAL_FLAGS, self['Flags'])))

922 print("Persist : 0x%.8x (%s)" % (self['Persist'], CREDENTIAL_PERSIST(self['Persist']).name))

923 print("Type : 0x%.8x (%s)" % (self['Type'], CREDENTIAL_PERSIST(self['Type']).name))

924 print("Target : %s" % (self['Target'].decode('utf-16le')))

925 print("Description : %s" % (self['Description'].decode('utf-16le')))

926 print("Unknown : %s" % (self['Unknown'].decode('utf-16le')))

927 print("Username : %s" % (self['Username'].decode('utf-16le')))

928 try:

929 print("Unknown : %s" % (self['Unknown3'].decode('utf-16le')))

930 except UnicodeDecodeError:

931 print("Unknown : %s" % (self['Unknown3'].decode('latin-1')))

932

933 print()

934 for entry in self.attributes: 934 ↛ 935line 934 didn't jump to line 935, because the loop on line 934 never started

935 entry.dump()

936

937 ALG_ID = '<L=0'

938

939 class P_BACKUP_KEY(Structure):

940 structure = (

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

942 ('Data', ':'),

943 )

944

945 class PREFERRED_BACKUP_KEY(Structure):

946 structure = (

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

948 ('KeyLength', '<L=0'),

949 ('CertificateLength', '<L=0'),

950 ('Data', ':'),

951 )

952

953 class PVK_FILE_HDR(Structure):

954 structure = (

955 ('dwMagic', '<L=0'),

956 ('dwVersion', '<L=0'),

957 ('dwKeySpec', '<L=0'),

958 ('dwEncryptType', '<L=0'),

959 ('cbEncryptData', '<L=0'),

960 ('cbPvk', '<L=0'),

961 )

962

963 class PUBLICKEYSTRUC(Structure):

964 structure = (

965 ('bType', '<B=0'),

966 ('bVersion', '<B=0'),

967 ('reserved', '<H=0'),

968 ('aiKeyAlg', ALG_ID),

969 )

970

971 class RSAPUBKEY(Structure):

972 structure = (

973 ('magic', '<L=0'),

974 ('bitlen', '<L=0'),

975 ('pubexp', '<L=0'),

976 )

977

978 class PUBLIC_KEY_BLOB(Structure):

979 structure = (

980 ('publickeystruc', ':', PUBLICKEYSTRUC),

981 ('rsapubkey', ':', RSAPUBKEY),

982 ('_modulus', '_-modulus', 'self["rsapubkey"]["bitlen"] // 8'),

983 )

984

985 class PRIVATE_KEY_BLOB(Structure):

986 structure = (

987 ('publickeystruc', ':', PUBLICKEYSTRUC),

988 ('rsapubkey', ':', RSAPUBKEY),

989 ('_modulus', '_-modulus', 'self["rsapubkey"]["bitlen"] // 8'),

990 ('modulus', ':'),

991 ('_prime1', '_-prime1', 'self["rsapubkey"]["bitlen"] // 16'),

992 ('prime1', ':'),

993 ('_prime2', '_-prime2', 'self["rsapubkey"]["bitlen"] // 16'),

994 ('prime2', ':'),

995 ('_exponent1', '_-exponent1', 'self["rsapubkey"]["bitlen"] // 16'),

996 ('exponent1', ':'),

997 ('_exponent2', '_-exponent2', 'self["rsapubkey"]["bitlen"] // 16'),

998 ('exponent2', ':'),

999 ('_coefficient', '_-coefficient', 'self["rsapubkey"]["bitlen"] // 16'),

1000 ('coefficient', ':'),

1001 ('_privateExponent', '_-privateExponent', 'self["rsapubkey"]["bitlen"] // 8'),

1002 ('privateExponent', ':'),

1003 )

1004

1005 class SIMPLE_KEY_BLOB(Structure):

1006 structure = (

1007 ('publickeystruc', ':', PUBLICKEYSTRUC),

1008 ('algid', ALG_ID),

1009 ('encryptedkey', ':'),

1010 )

1011

1012 class DPAPI_DOMAIN_RSA_MASTER_KEY(Structure):

1013 structure = (

1014 ('cbMasterKey', '<L=0'),

1015 ('cbSuppKey', '<L=0'),

1016 ('buffer', ':'),

1017 )

1018

1019 def privatekeyblob_to_pkcs1(key):

1020 '''

1021 parse private key into pkcs#1 format

1022 :param key:

1023 :return:

1024 '''

1025 modulus = bytes_to_long(key['modulus'][::-1]) # n

1026 prime1 = bytes_to_long(key['prime1'][::-1]) # p

1027 prime2 = bytes_to_long(key['prime2'][::-1]) # q

1028 exp1 = bytes_to_long(key['exponent1'][::-1])

1029 exp2 = bytes_to_long(key['exponent2'][::-1])

1030 coefficient = bytes_to_long(key['coefficient'][::-1])

1031 privateExp = bytes_to_long(key['privateExponent'][::-1]) # d

1032 if PY3:

1033 long = int

1034 pubExp = long(key['rsapubkey']['pubexp']) # e

1035 # RSA.Integer(prime2).inverse(prime1) # u

1036

1037 r = RSA.construct((modulus, pubExp, privateExp, prime1, prime2))

1038 return r