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# Impacket - Collection of Python classes for working with network protocols.

2#

3# SECUREAUTH LABS. Copyright (C) 2021 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# DPAPI and Windows Vault parsing structures and manipulation

11#

12# Author:

13# Alberto Solino (@agsolino)

14#

15# References:

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

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

18# - https://github.com/jordanbtucker/dpapick

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

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

21# - https://www.passcape.com/windows_password_recovery_vault_explorer

22# - https://www.passcape.com/windows_password_recovery_dpapi_master_key

23#

24

25 from __future__ import division

26 from __future__ import print_function

27 import sys

28

29 from struct import unpack

30 from datetime import datetime

31 from binascii import unhexlify, hexlify

32 from struct import pack

33 from Cryptodome.Hash import HMAC, SHA512, SHA1

34 from Cryptodome.Cipher import AES, DES3

35 from Cryptodome.Util.Padding import unpad

36 from Cryptodome.PublicKey import RSA

37 from Cryptodome.Util.number import bytes_to_long

38 from six import PY3

39

40 from impacket.ese import getUnixTime

41 from impacket.structure import Structure, hexdump

42 from impacket.uuid import bin_to_string

43 from impacket.dcerpc.v5.enum import Enum

44 from impacket.dcerpc.v5.dtypes import RPC_SID

45

46# Algorithm classes

47 ALG_CLASS_ANY = (0)

48 ALG_CLASS_SIGNATURE = (1 << 13)

49 ALG_CLASS_MSG_ENCRYPT = (2 << 13)

50 ALG_CLASS_DATA_ENCRYPT = (3 << 13)

51 ALG_CLASS_HASH = (4 << 13)

52 ALG_CLASS_KEY_EXCHANGE = (5 << 13)

53 ALG_CLASS_ALL = (7 << 13)

54

55# Algorithm types

56 ALG_TYPE_ANY = (0)

57 ALG_TYPE_DSS = (1 << 9)

58 ALG_TYPE_RSA = (2 << 9)

59 ALG_TYPE_BLOCK = (3 << 9)

60 ALG_TYPE_STREAM = (4 << 9)

61 ALG_TYPE_DH = (5 << 9)

62 ALG_TYPE_SECURECHANNEL = (6 << 9)

63 ALG_SID_ANY = (0)

64 ALG_SID_RSA_ANY = 0

65 ALG_SID_RSA_PKCS = 1

66 ALG_SID_RSA_MSATWORK = 2

67 ALG_SID_RSA_ENTRUST = 3

68 ALG_SID_RSA_PGP = 4

69 ALG_SID_DSS_ANY = 0

70 ALG_SID_DSS_PKCS = 1

71 ALG_SID_DSS_DMS = 2

72 ALG_SID_ECDSA = 3

73

74# Block cipher sub ids

75 ALG_SID_DES = 1

76 ALG_SID_3DES = 3

77 ALG_SID_DESX = 4

78 ALG_SID_IDEA = 5

79 ALG_SID_CAST = 6

80 ALG_SID_SAFERSK64 = 7

81 ALG_SID_SAFERSK128 = 8

82 ALG_SID_3DES_112 = 9

83 ALG_SID_CYLINK_MEK = 12

84 ALG_SID_RC5 = 13

85 ALG_SID_AES_128 = 14

86 ALG_SID_AES_192 = 15

87 ALG_SID_AES_256 = 16

88 ALG_SID_AES = 17

89 ALG_SID_SKIPJACK = 10

90 ALG_SID_TEK = 11

91

92 CRYPT_MODE_CBCI = 6 # ANSI CBC Interleaved

93 CRYPT_MODE_CFBP = 7 # ANSI CFB Pipelined

94 CRYPT_MODE_OFBP = 8 # ANSI OFB Pipelined

95 CRYPT_MODE_CBCOFM = 9 # ANSI CBC + OF Masking

96 CRYPT_MODE_CBCOFMI = 10 # ANSI CBC + OFM Interleaved

97

98 ALG_SID_RC2 = 2

99 ALG_SID_RC4 = 1

100 ALG_SID_SEAL = 2

101

102# Diffie - Hellman sub - ids

103 ALG_SID_DH_SANDF = 1

104 ALG_SID_DH_EPHEM = 2

105 ALG_SID_AGREED_KEY_ANY = 3

106 ALG_SID_KEA = 4

107 ALG_SID_ECDH = 5

108

109# Hash sub ids

110 ALG_SID_MD2 = 1

111 ALG_SID_MD4 = 2

112 ALG_SID_MD5 = 3

113 ALG_SID_SHA = 4

114 ALG_SID_SHA1 = 4

115 ALG_SID_MAC = 5

116 ALG_SID_RIPEMD = 6

117 ALG_SID_RIPEMD160 = 7

118 ALG_SID_SSL3SHAMD5 = 8

119 ALG_SID_HMAC = 9

120 ALG_SID_TLS1PRF = 10

121 ALG_SID_HASH_REPLACE_OWF = 11

122 ALG_SID_SHA_256 = 12

123 ALG_SID_SHA_384 = 13

124 ALG_SID_SHA_512 = 14

125

126# secure channel sub ids

127 ALG_SID_SSL3_MASTER = 1

128 ALG_SID_SCHANNEL_MASTER_HASH = 2

129 ALG_SID_SCHANNEL_MAC_KEY = 3

130 ALG_SID_PCT1_MASTER = 4

131 ALG_SID_SSL2_MASTER = 5

132 ALG_SID_TLS1_MASTER = 6

133 ALG_SID_SCHANNEL_ENC_KEY = 7

134 ALG_SID_ECMQV = 1

135

136 def getFlags(myenum, flags):

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

138

139 class FLAGS(Enum):

140 CRYPTPROTECT_UI_FORBIDDEN = 0x1

141 CRYPTPROTECT_LOCAL_MACHINE = 0x4

142 CRYPTPROTECT_CRED_SYNC = 0x8

143 CRYPTPROTECT_AUDIT = 0x10

144 CRYPTPROTECT_VERIFY_PROTECTION = 0x40

145 CRYPTPROTECT_CRED_REGENERATE = 0x80

146 CRYPTPROTECT_SYSTEM = 0x20000000

147

148# algorithm identifier definitions

149 class ALGORITHMS(Enum):

150 CALG_MD2 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD2)

151 CALG_MD4 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD4)

152 CALG_MD5 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5)

153 CALG_SHA = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA)

154 CALG_SHA1 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1)

155 CALG_RSA_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | ALG_SID_RSA_ANY)

156 CALG_DSS_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY)

157 CALG_NO_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_ANY | ALG_SID_ANY)

158 CALG_RSA_KEYX = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_RSA|ALG_SID_RSA_ANY)

159 CALG_DES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_DES)

160 CALG_3DES_112 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_3DES_112)

161 CALG_3DES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_3DES)

162 CALG_DESX = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_DESX)

163 CALG_RC2 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_RC2)

164 CALG_RC4 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_STREAM|ALG_SID_RC4)

165 CALG_SEAL = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_STREAM|ALG_SID_SEAL)

166 CALG_DH_SF = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_DH_SANDF)

167 CALG_DH_EPHEM = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_DH_EPHEM)

168 CALG_AGREEDKEY_ANY = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_AGREED_KEY_ANY)

169 CALG_KEA_KEYX = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_DH|ALG_SID_KEA)

170 CALG_HUGHES_MD5 = (ALG_CLASS_KEY_EXCHANGE|ALG_TYPE_ANY|ALG_SID_MD5)

171 CALG_SKIPJACK = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_SKIPJACK)

172 CALG_TEK = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_TEK)

173 CALG_SSL3_SHAMD5 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5)

174 CALG_SSL3_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SSL3_MASTER)

175 CALG_SCHANNEL_MASTER_HASH = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_MASTER_HASH)

176 CALG_SCHANNEL_MAC_KEY = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_MAC_KEY)

177 CALG_SCHANNEL_ENC_KEY = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SCHANNEL_ENC_KEY)

178 CALG_PCT1_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_PCT1_MASTER)

179 CALG_SSL2_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_SSL2_MASTER)

180 CALG_TLS1_MASTER = (ALG_CLASS_MSG_ENCRYPT|ALG_TYPE_SECURECHANNEL|ALG_SID_TLS1_MASTER)

181 CALG_RC5 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_RC5)

182 CALG_HMAC = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)

183 CALG_TLS1PRF = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_TLS1PRF)

184 CALG_HASH_REPLACE_OWF = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HASH_REPLACE_OWF)

185 CALG_AES_128 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_128)

186 CALG_AES_192 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_192)

187 CALG_AES_256 = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES_256)

188 CALG_AES = (ALG_CLASS_DATA_ENCRYPT|ALG_TYPE_BLOCK|ALG_SID_AES)

189 CALG_SHA_256 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)

190 CALG_SHA_384 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384)

191 CALG_SHA_512 = (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512)

192 CALG_ECDH = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_ECDH)

193 CALG_ECMQV = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_ECMQV)

194 CALG_ECDSA = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA)

195

196 class CREDENTIAL_FLAGS(Enum):

197 CRED_FLAGS_PASSWORD_FOR_CERT = 0x1

198 CRED_FLAGS_PROMPT_NOW = 0x2

199 CRED_FLAGS_USERNAME_TARGET = 0x4

200 CRED_FLAGS_OWF_CRED_BLOB = 0x8

201 CRED_FLAGS_REQUIRE_CONFIRMATION = 0x10

202 CRED_FLAGS_WILDCARD_MATCH = 0x20

203 CRED_FLAGS_VSM_PROTECTED = 0x40

204 CRED_FLAGS_NGC_CERT = 0x80

205

206 class CREDENTIAL_TYPE(Enum):

207 CRED_TYPE_GENERIC = 0x1

208 CRED_TYPE_DOMAIN_PASSWORD = 0x2

209 CRED_TYPE_DOMAIN_CERTIFICATE = 0x3

210 CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 0x4

211 CRED_TYPE_GENERIC_CERTIFICATE = 0x5

212 CRED_TYPE_DOMAIN_EXTENDED = 0x6

213 CRED_TYPE_MAXIMUM = 0x7

214 CRED_TYPE_MAXIMUM_EX = 0x8

215

216 class CREDENTIAL_PERSIST(Enum):

217 CRED_PERSIST_NONE = 0x0

218 CRED_PERSIST_SESSION = 0x1

219 CRED_PERSIST_LOCAL_MACHINE = 0x2

220 CRED_PERSIST_ENTERPRISE = 0x3

221

222 ALGORITHMS_DATA = {

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

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

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

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

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

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

229}

230

231 class MasterKeyFile(Structure):

232 structure = (

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

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

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

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

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

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

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

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

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

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

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

244 )

245

246 def dump(self):

247 print("[MASTERKEYFILE]")

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

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

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

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

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

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

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

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

256 print()

257

258 class MasterKey(Structure):

259 structure = (

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

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

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

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

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

265 ('data', ':'),

266 )

267

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

269 Structure.__init__(self, data, alignment)

270 self.decryptedKey = None

271

272 def dump(self):

273 print("[MASTERKEY]")

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

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

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

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

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

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

280 print()

281

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

283 keyMaterial = b""

284 i = 1

285 while len(keyMaterial) < keylen:

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

287 i += 1

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

289 for r in range(count - 1):

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

291 if PY3: 291 ↛ 292line 291 didn't jump to line 292, because the condition on line 291 was never true

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

293 else:

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

295 keyMaterial += derived

296

297 return keyMaterial[:keylen]

298

299 def decrypt(self, key):

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

301 hashModule = SHA1

302 else:

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

304

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

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

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

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

309

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

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

312

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

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

315

316 decryptedKey = cleartext[-64:]

317 hmacSalt = cleartext[:16]

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

319

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

321

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

323

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

325 self.decryptedKey = decryptedKey

326 return decryptedKey

327 else:

328 return None

329

330 class CredHist(Structure):

331 structure = (

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

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

334 )

335 def dump(self):

336 print("[CREDHIST]")

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

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

339 print()

340

341 class DomainKey(Structure):

342 structure = (

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

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

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

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

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

348 ('SecretData', ':'),

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

350 ('AccessCheck', ':'),

351 )

352 def dump(self):

353 print("[DOMAINKEY]")

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

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

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

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

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

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

360 print()

361

362 class DPAPI_SYSTEM(Structure):

363 structure = (

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

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

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

367 )

368

369 def dump(self):

370 print("[DPAPI_SYSTEM]")

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

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

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

374 print()

375

376 class CredentialFile(Structure):

377 structure = (

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

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

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

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

382 ('Data', ':'),

383 )

384 #def dump(self):

385 # print("[CREDENTIAL FILE]")

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

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

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

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

390 # print()

391

392

393 class DPAPI_BLOB(Structure):

394 structure = (

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

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

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

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

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

400

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

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

403 ('Description', ':'),

404

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

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

407

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

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

410 ('Salt', ':'),

411

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

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

414 ('HMacKey', ':'),

415

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

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

418

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

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

421 ('HMac', ':'),

422

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

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

425 ('Data', ':'),

426

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

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

429 ('Sign', ':'),

430

431 )

432

433 def dump(self):

434 print("[BLOB]")

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

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

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

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

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

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

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

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

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

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

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

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

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

448 print()

449

450

451 def deriveKey(self, sessionKey):

452 def fixparity(deskey):

453 from six import indexbytes, b

454 temp = b''

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

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

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

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

459 else:

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

461 return temp

462

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

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

465 else:

466 derivedKey = sessionKey

467

468

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

470 # Extend the key

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

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

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

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

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

476 derivedKey = fixparity(derivedKey)

477

478 return derivedKey

479

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

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

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

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

484 sessionKey.update(entropy)

485

486 sessionKey = sessionKey.digest()

487

488 # Derive the key

489 derivedKey = self.deriveKey(sessionKey)

490

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

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

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

494

495 # Now check the signature

496

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

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

499

500 # Calculate the different HMACKeys

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

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

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

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

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

506

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

508 hmacCalculated1.update(a.digest())

509

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

511 hmacCalculated1.update(entropy)

512

513 hmacCalculated1.update(toSign)

514

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

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

517 hmacCalculated3.update(entropy)

518

519 hmacCalculated3.update(toSign)

520

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

522 return cleartext

523 else:

524 return None

525

526 class VAULT_ATTRIBUTE(Structure):

527 structure = (

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

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

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

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

532 )

533

534 padding = (

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

536 )

537

538 id100 = (

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

540 )

541

542 extended = (

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

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

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

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

547 ('IV', ':'),

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

549 ('Data',':'),

550 )

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

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

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

554 self.structure += self.padding

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

556 self.structure += self.id100

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

558 self.structure += self.extended

559 Structure.__init__(self, data, alignment)

560

561

562 def dump(self):

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

564 if len(self.rawData) > 28:

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

566 if self['IVPresent'] > 0:

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

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

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

570

571 class VAULT_ATTRIBUTE_MAP_ENTRY(Structure):

572 structure = (

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

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

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

576 )

577 def dump(self):

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

579

580 class VAULT_VCRD(Structure):

581 structure = (

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

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

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

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

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

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

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

589 ('FriendlyName', ':'),

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

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

592 ('AttributeMaps', ':'),

593 ('Data', ':'),

594 )

595

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

597 Structure.__init__(self, data, alignment)

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

599 # Process the MAP entries

600 self.mapEntries = list()

601 data = self['AttributeMaps']

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

603 entry = VAULT_ATTRIBUTE_MAP_ENTRY(data)

604 self.mapEntries.append(entry)

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

606

607 self.attributesLen = list()

608

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

610 if i > 0:

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

612

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

614

615 self.attributes = list()

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

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

618 self.attributes.append(attribute)

619

620 # Do we have remaining data?

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

622

623 def dump(self):

624 print("[VCRD]")

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

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

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

628 print()

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

630 entry.dump()

631 self.attributes[i].dump()

632 print()

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

634 print()

635

636 class VAULT_VPOL(Structure):

637 structure = (

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

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

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

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

642 ('Description', ':'),

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

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

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

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

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

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

649 ('Blob', ':', DPAPI_BLOB),

650 )

651

652 def dump(self):

653 print("[VAULT_VPOL]")

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

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

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

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

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

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

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

661 self['Blob'].dump()

662 print()

663

664# from bcrypt.h

665 class BCRYPT_KEY_DATA_BLOB_HEADER(Structure):

666 structure = (

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

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

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

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

671 ('bKey',':'),

672 )

673

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

675 class BCRYPT_KSSM_DATA_BLOB_HEADER(Structure):

676 structure = (

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

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

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

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

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

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

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

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

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

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

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

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

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

690 )

691

692 class BCRYPT_KEY_WRAP(Structure):

693 structureKDBM = (

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

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

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

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

698 ('bKeyBlob',':', BCRYPT_KEY_DATA_BLOB_HEADER),

699 )

700 structureKSSM = (

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

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

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

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

705 ('bKeyBlob',':'),

706 )

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

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

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

710 self.structure = self.structureKDBM

711 else:

712 self.structure = self.structureKSSM

713 Structure.__init__(self, data, alignment)

714

715 class VAULT_VPOL_KEYS(Structure):

716 structure = (

717 ('Key1',':', BCRYPT_KEY_WRAP),

718 ('Key2',':', BCRYPT_KEY_WRAP),

719 )

720 def dump(self):

721 print("[VAULT_VPOL_KEYS]")

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

723 print('Key1:')

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

725 print('Key2:')

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

727 else:

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

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

730 print()

731

732 class VAULT_INTERNET_EXPLORER(Structure):

733 structure = (

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

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

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

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

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

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

740 ('Username', ':'),

741

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

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

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

745 ('Resource', ':'),

746

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

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

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

750 ('Password', ':'),

751 )

752 def fromString(self, data):

753 Structure.fromString(self, data)

754

755 def dump(self):

756 print("[Internet Explorer]")

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

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

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

760 print()

761

762 class VAULT_WIN_BIO_KEY(Structure):

763 structure = (

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

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

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

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

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

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

770 ('Sid', ':'),

771

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

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

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

775 ('Name', ':'),

776

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

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

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

780 ('BioKey', ':'),

781 )

782 def fromString(self, data):

783 Structure.fromString(self, data)

784 if data is not None:

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

786 self['BioKey'] = bioKey

787

788 def dump(self):

789 print("[WINDOWS BIOMETRIC KEY]")

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

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

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

793 print()

794

795 class NGC_LOCAL_ACCOOUNT(Structure):

796 structure = (

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

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

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

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

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

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

803 ('UnlockKey', ':'),

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

805 ('IV', ':'),

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

807 ('CipherText', ':'),

808 )

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

810# hexdump(data)

811 def dump(self):

812 print("[NGC LOCAL ACCOOUNT]")

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

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

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

816

817 class VAULT_NGC_ACCOOUNT(Structure):

818 structure = (

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

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

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

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

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

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

825 ('Sid', ':'),

826

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

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

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

830 ('Name', ':'),

831

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

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

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

835 ('Blob', ':', NGC_LOCAL_ACCOOUNT),

836 )

837 def dump(self):

838 print("[NGC VAULT]")

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

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

841 self['Blob'].dump()

842 print()

843

844 VAULT_KNOWN_SCHEMAS = {

845 'WinBio Key': VAULT_WIN_BIO_KEY,

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

847 'Internet Explorer': VAULT_INTERNET_EXPLORER,

848}

849

850 class CREDENTIAL_ATTRIBUTE(Structure):

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

852 structure = (

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

854

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

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

857 ('KeyWord', ':'),

858

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

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

861 ('Data', ':'),

862 )

863

864 def dump(self):

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

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

867 print("Data : ")

868 hexdump(self['Data'])

869

870 class CREDENTIAL_BLOB(Structure):

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

872 structure = (

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

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

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

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

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

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

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

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

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

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

883

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

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

886 ('Target',':'),

887

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

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

890 ('TargetAlias', ':'),

891

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

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

894 ('Description', ':'),

895

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

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

898 ('Unknown', ':'),

899

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

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

902 ('Username', ':'),

903

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

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

906 ('Unknown3', ':'),

907

908 ('Remaining', ':'),

909 )

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

911 Structure.__init__(self, data, alignment)

912 self.attributes = 0

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

914 # Unpack the attributes

915 remaining = self['Remaining']

916 self.attributes = list()

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

918 attr = CREDENTIAL_ATTRIBUTE(remaining)

919 self.attributes.append(attr)

920 remaining = remaining[len(attr):]

921

922 def dump(self):

923 print("[CREDENTIAL]")

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

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

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

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

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

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

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

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

932 try:

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

934 except UnicodeDecodeError:

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

936

937 print()

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

939 entry.dump()

940

941 ALG_ID = '<L=0'

942

943 class P_BACKUP_KEY(Structure):

944 structure = (

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

946 ('Data', ':'),

947 )

948

949 class PREFERRED_BACKUP_KEY(Structure):

950 structure = (

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

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

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

954 ('Data', ':'),

955 )

956

957 class PVK_FILE_HDR(Structure):

958 structure = (

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

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

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

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

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

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

965 )

966

967 class PUBLICKEYSTRUC(Structure):

968 structure = (

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

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

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

972 ('aiKeyAlg', ALG_ID),

973 )

974

975 class RSAPUBKEY(Structure):

976 structure = (

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

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

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

980 )

981

982 class PUBLIC_KEY_BLOB(Structure):

983 structure = (

984 ('publickeystruc', ':', PUBLICKEYSTRUC),

985 ('rsapubkey', ':', RSAPUBKEY),

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

987 )

988

989 class PRIVATE_KEY_BLOB(Structure):

990 structure = (

991 ('publickeystruc', ':', PUBLICKEYSTRUC),

992 ('rsapubkey', ':', RSAPUBKEY),

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

994 ('modulus', ':'),

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

996 ('prime1', ':'),

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

998 ('prime2', ':'),

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

1000 ('exponent1', ':'),

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

1002 ('exponent2', ':'),

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

1004 ('coefficient', ':'),

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

1006 ('privateExponent', ':'),

1007 )

1008

1009 class SIMPLE_KEY_BLOB(Structure):

1010 structure = (

1011 ('publickeystruc', ':', PUBLICKEYSTRUC),

1012 ('algid', ALG_ID),

1013 ('encryptedkey', ':'),

1014 )

1015

1016 class DPAPI_DOMAIN_RSA_MASTER_KEY(Structure):

1017 structure = (

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

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

1020 ('buffer', ':'),

1021 )

1022

1023 def privatekeyblob_to_pkcs1(key):

1024 '''

1025 parse private key into pkcs#1 format

1026 :param key:

1027 :return:

1028 '''

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

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

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

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

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

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

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

1036 if PY3:

1037 long = int

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

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

1040

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

1042 return r