Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/asn1crypto/algos.py: 53%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

287 statements  

1# coding: utf-8 

2 

3""" 

4ASN.1 type classes for various algorithms using in various aspects of public 

5key cryptography. Exports the following items: 

6 

7 - AlgorithmIdentifier() 

8 - AnyAlgorithmIdentifier() 

9 - DigestAlgorithm() 

10 - DigestInfo() 

11 - DSASignature() 

12 - EncryptionAlgorithm() 

13 - HmacAlgorithm() 

14 - KdfAlgorithm() 

15 - Pkcs5MacAlgorithm() 

16 - SignedDigestAlgorithm() 

17 

18Other type classes are defined that help compose the types listed above. 

19""" 

20 

21from __future__ import unicode_literals, division, absolute_import, print_function 

22 

23from ._errors import unwrap 

24from ._int import fill_width 

25from .util import int_from_bytes, int_to_bytes 

26from .core import ( 

27 Any, 

28 Choice, 

29 Integer, 

30 Null, 

31 ObjectIdentifier, 

32 OctetString, 

33 Sequence, 

34 Void, 

35) 

36 

37 

38# Structures and OIDs in this file are pulled from 

39# https://tools.ietf.org/html/rfc3279, https://tools.ietf.org/html/rfc4055, 

40# https://tools.ietf.org/html/rfc5758, https://tools.ietf.org/html/rfc7292, 

41# http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf 

42 

43class AlgorithmIdentifier(Sequence): 

44 _fields = [ 

45 ('algorithm', ObjectIdentifier), 

46 ('parameters', Any, {'optional': True}), 

47 ] 

48 

49 

50class _ForceNullParameters(object): 

51 """ 

52 Various structures based on AlgorithmIdentifier require that the parameters 

53 field be core.Null() for certain OIDs. This mixin ensures that happens. 

54 """ 

55 

56 # The following attribute, plus the parameters spec callback and custom 

57 # __setitem__ are all to handle a situation where parameters should not be 

58 # optional and must be Null for certain OIDs. More info at 

59 # https://tools.ietf.org/html/rfc4055#page-15 and 

60 # https://tools.ietf.org/html/rfc4055#section-2.1 

61 _null_algos = set([ 

62 '1.2.840.113549.1.1.1', # rsassa_pkcs1v15 / rsaes_pkcs1v15 / rsa 

63 '1.2.840.113549.1.1.11', # sha256_rsa 

64 '1.2.840.113549.1.1.12', # sha384_rsa 

65 '1.2.840.113549.1.1.13', # sha512_rsa 

66 '1.2.840.113549.1.1.14', # sha224_rsa 

67 '1.3.14.3.2.26', # sha1 

68 '2.16.840.1.101.3.4.2.4', # sha224 

69 '2.16.840.1.101.3.4.2.1', # sha256 

70 '2.16.840.1.101.3.4.2.2', # sha384 

71 '2.16.840.1.101.3.4.2.3', # sha512 

72 ]) 

73 

74 def _parameters_spec(self): 

75 if self._oid_pair == ('algorithm', 'parameters'): 

76 algo = self['algorithm'].native 

77 if algo in self._oid_specs: 

78 return self._oid_specs[algo] 

79 

80 if self['algorithm'].dotted in self._null_algos: 

81 return Null 

82 

83 return None 

84 

85 _spec_callbacks = { 

86 'parameters': _parameters_spec 

87 } 

88 

89 # We have to override this since the spec callback uses the value of 

90 # algorithm to determine the parameter spec, however default values are 

91 # assigned before setting a field, so a default value can't be based on 

92 # another field value (unless it is a default also). Thus we have to 

93 # manually check to see if the algorithm was set and parameters is unset, 

94 # and then fix the value as appropriate. 

95 def __setitem__(self, key, value): 

96 res = super(_ForceNullParameters, self).__setitem__(key, value) 

97 if key != 'algorithm': 

98 return res 

99 if self['algorithm'].dotted not in self._null_algos: 

100 return res 

101 if self['parameters'].__class__ != Void: 

102 return res 

103 self['parameters'] = Null() 

104 return res 

105 

106 

107class HmacAlgorithmId(ObjectIdentifier): 

108 _map = { 

109 '1.3.14.3.2.10': 'des_mac', 

110 '1.2.840.113549.2.7': 'sha1', 

111 '1.2.840.113549.2.8': 'sha224', 

112 '1.2.840.113549.2.9': 'sha256', 

113 '1.2.840.113549.2.10': 'sha384', 

114 '1.2.840.113549.2.11': 'sha512', 

115 '1.2.840.113549.2.12': 'sha512_224', 

116 '1.2.840.113549.2.13': 'sha512_256', 

117 '2.16.840.1.101.3.4.2.13': 'sha3_224', 

118 '2.16.840.1.101.3.4.2.14': 'sha3_256', 

119 '2.16.840.1.101.3.4.2.15': 'sha3_384', 

120 '2.16.840.1.101.3.4.2.16': 'sha3_512', 

121 } 

122 

123 

124class HmacAlgorithm(Sequence): 

125 _fields = [ 

126 ('algorithm', HmacAlgorithmId), 

127 ('parameters', Any, {'optional': True}), 

128 ] 

129 

130 

131class DigestAlgorithmId(ObjectIdentifier): 

132 _map = { 

133 '1.2.840.113549.2.2': 'md2', 

134 '1.2.840.113549.2.5': 'md5', 

135 '1.3.14.3.2.26': 'sha1', 

136 '2.16.840.1.101.3.4.2.4': 'sha224', 

137 '2.16.840.1.101.3.4.2.1': 'sha256', 

138 '2.16.840.1.101.3.4.2.2': 'sha384', 

139 '2.16.840.1.101.3.4.2.3': 'sha512', 

140 '2.16.840.1.101.3.4.2.5': 'sha512_224', 

141 '2.16.840.1.101.3.4.2.6': 'sha512_256', 

142 '2.16.840.1.101.3.4.2.7': 'sha3_224', 

143 '2.16.840.1.101.3.4.2.8': 'sha3_256', 

144 '2.16.840.1.101.3.4.2.9': 'sha3_384', 

145 '2.16.840.1.101.3.4.2.10': 'sha3_512', 

146 '2.16.840.1.101.3.4.2.11': 'shake128', 

147 '2.16.840.1.101.3.4.2.12': 'shake256', 

148 '2.16.840.1.101.3.4.2.17': 'shake128_len', 

149 '2.16.840.1.101.3.4.2.18': 'shake256_len', 

150 } 

151 

152 

153class DigestAlgorithm(_ForceNullParameters, Sequence): 

154 _fields = [ 

155 ('algorithm', DigestAlgorithmId), 

156 ('parameters', Any, {'optional': True}), 

157 ] 

158 

159 

160# This structure is what is signed with a SignedDigestAlgorithm 

161class DigestInfo(Sequence): 

162 _fields = [ 

163 ('digest_algorithm', DigestAlgorithm), 

164 ('digest', OctetString), 

165 ] 

166 

167 

168class MaskGenAlgorithmId(ObjectIdentifier): 

169 _map = { 

170 '1.2.840.113549.1.1.8': 'mgf1', 

171 } 

172 

173 

174class MaskGenAlgorithm(Sequence): 

175 _fields = [ 

176 ('algorithm', MaskGenAlgorithmId), 

177 ('parameters', Any, {'optional': True}), 

178 ] 

179 

180 _oid_pair = ('algorithm', 'parameters') 

181 _oid_specs = { 

182 'mgf1': DigestAlgorithm 

183 } 

184 

185 

186class TrailerField(Integer): 

187 _map = { 

188 1: 'trailer_field_bc', 

189 } 

190 

191 

192class RSASSAPSSParams(Sequence): 

193 _fields = [ 

194 ( 

195 'hash_algorithm', 

196 DigestAlgorithm, 

197 { 

198 'explicit': 0, 

199 'default': {'algorithm': 'sha1'}, 

200 } 

201 ), 

202 ( 

203 'mask_gen_algorithm', 

204 MaskGenAlgorithm, 

205 { 

206 'explicit': 1, 

207 'default': { 

208 'algorithm': 'mgf1', 

209 'parameters': {'algorithm': 'sha1'}, 

210 }, 

211 } 

212 ), 

213 ( 

214 'salt_length', 

215 Integer, 

216 { 

217 'explicit': 2, 

218 'default': 20, 

219 } 

220 ), 

221 ( 

222 'trailer_field', 

223 TrailerField, 

224 { 

225 'explicit': 3, 

226 'default': 'trailer_field_bc', 

227 } 

228 ), 

229 ] 

230 

231 

232class SignedDigestAlgorithmId(ObjectIdentifier): 

233 _map = { 

234 '1.3.14.3.2.3': 'md5_rsa', 

235 '1.3.14.3.2.29': 'sha1_rsa', 

236 '1.3.14.7.2.3.1': 'md2_rsa', 

237 '1.2.840.113549.1.1.2': 'md2_rsa', 

238 '1.2.840.113549.1.1.4': 'md5_rsa', 

239 '1.2.840.113549.1.1.5': 'sha1_rsa', 

240 '1.2.840.113549.1.1.14': 'sha224_rsa', 

241 '1.2.840.113549.1.1.11': 'sha256_rsa', 

242 '1.2.840.113549.1.1.12': 'sha384_rsa', 

243 '1.2.840.113549.1.1.13': 'sha512_rsa', 

244 '1.2.840.113549.1.1.10': 'rsassa_pss', 

245 '1.2.840.10040.4.3': 'sha1_dsa', 

246 '1.3.14.3.2.13': 'sha1_dsa', 

247 '1.3.14.3.2.27': 'sha1_dsa', 

248 '2.16.840.1.101.3.4.3.1': 'sha224_dsa', 

249 '2.16.840.1.101.3.4.3.2': 'sha256_dsa', 

250 '1.2.840.10045.4.1': 'sha1_ecdsa', 

251 '1.2.840.10045.4.3.1': 'sha224_ecdsa', 

252 '1.2.840.10045.4.3.2': 'sha256_ecdsa', 

253 '1.2.840.10045.4.3.3': 'sha384_ecdsa', 

254 '1.2.840.10045.4.3.4': 'sha512_ecdsa', 

255 '2.16.840.1.101.3.4.3.9': 'sha3_224_ecdsa', 

256 '2.16.840.1.101.3.4.3.10': 'sha3_256_ecdsa', 

257 '2.16.840.1.101.3.4.3.11': 'sha3_384_ecdsa', 

258 '2.16.840.1.101.3.4.3.12': 'sha3_512_ecdsa', 

259 # For when the digest is specified elsewhere in a Sequence 

260 '1.2.840.113549.1.1.1': 'rsassa_pkcs1v15', 

261 '1.2.840.10040.4.1': 'dsa', 

262 '1.2.840.10045.4': 'ecdsa', 

263 # RFC 8410 -- https://tools.ietf.org/html/rfc8410 

264 '1.3.101.112': 'ed25519', 

265 '1.3.101.113': 'ed448', 

266 } 

267 

268 _reverse_map = { 

269 'dsa': '1.2.840.10040.4.1', 

270 'ecdsa': '1.2.840.10045.4', 

271 'md2_rsa': '1.2.840.113549.1.1.2', 

272 'md5_rsa': '1.2.840.113549.1.1.4', 

273 'rsassa_pkcs1v15': '1.2.840.113549.1.1.1', 

274 'rsassa_pss': '1.2.840.113549.1.1.10', 

275 'sha1_dsa': '1.2.840.10040.4.3', 

276 'sha1_ecdsa': '1.2.840.10045.4.1', 

277 'sha1_rsa': '1.2.840.113549.1.1.5', 

278 'sha224_dsa': '2.16.840.1.101.3.4.3.1', 

279 'sha224_ecdsa': '1.2.840.10045.4.3.1', 

280 'sha224_rsa': '1.2.840.113549.1.1.14', 

281 'sha256_dsa': '2.16.840.1.101.3.4.3.2', 

282 'sha256_ecdsa': '1.2.840.10045.4.3.2', 

283 'sha256_rsa': '1.2.840.113549.1.1.11', 

284 'sha384_ecdsa': '1.2.840.10045.4.3.3', 

285 'sha384_rsa': '1.2.840.113549.1.1.12', 

286 'sha512_ecdsa': '1.2.840.10045.4.3.4', 

287 'sha512_rsa': '1.2.840.113549.1.1.13', 

288 'sha3_224_ecdsa': '2.16.840.1.101.3.4.3.9', 

289 'sha3_256_ecdsa': '2.16.840.1.101.3.4.3.10', 

290 'sha3_384_ecdsa': '2.16.840.1.101.3.4.3.11', 

291 'sha3_512_ecdsa': '2.16.840.1.101.3.4.3.12', 

292 'ed25519': '1.3.101.112', 

293 'ed448': '1.3.101.113', 

294 } 

295 

296 

297class SignedDigestAlgorithm(_ForceNullParameters, Sequence): 

298 _fields = [ 

299 ('algorithm', SignedDigestAlgorithmId), 

300 ('parameters', Any, {'optional': True}), 

301 ] 

302 

303 _oid_pair = ('algorithm', 'parameters') 

304 _oid_specs = { 

305 'rsassa_pss': RSASSAPSSParams, 

306 } 

307 

308 @property 

309 def signature_algo(self): 

310 """ 

311 :return: 

312 A unicode string of "rsassa_pkcs1v15", "rsassa_pss", "dsa", 

313 "ecdsa", "ed25519" or "ed448" 

314 """ 

315 

316 algorithm = self['algorithm'].native 

317 

318 algo_map = { 

319 'md2_rsa': 'rsassa_pkcs1v15', 

320 'md5_rsa': 'rsassa_pkcs1v15', 

321 'sha1_rsa': 'rsassa_pkcs1v15', 

322 'sha224_rsa': 'rsassa_pkcs1v15', 

323 'sha256_rsa': 'rsassa_pkcs1v15', 

324 'sha384_rsa': 'rsassa_pkcs1v15', 

325 'sha512_rsa': 'rsassa_pkcs1v15', 

326 'rsassa_pkcs1v15': 'rsassa_pkcs1v15', 

327 'rsassa_pss': 'rsassa_pss', 

328 'sha1_dsa': 'dsa', 

329 'sha224_dsa': 'dsa', 

330 'sha256_dsa': 'dsa', 

331 'dsa': 'dsa', 

332 'sha1_ecdsa': 'ecdsa', 

333 'sha224_ecdsa': 'ecdsa', 

334 'sha256_ecdsa': 'ecdsa', 

335 'sha384_ecdsa': 'ecdsa', 

336 'sha512_ecdsa': 'ecdsa', 

337 'sha3_224_ecdsa': 'ecdsa', 

338 'sha3_256_ecdsa': 'ecdsa', 

339 'sha3_384_ecdsa': 'ecdsa', 

340 'sha3_512_ecdsa': 'ecdsa', 

341 'ecdsa': 'ecdsa', 

342 'ed25519': 'ed25519', 

343 'ed448': 'ed448', 

344 } 

345 if algorithm in algo_map: 

346 return algo_map[algorithm] 

347 

348 raise ValueError(unwrap( 

349 ''' 

350 Signature algorithm not known for %s 

351 ''', 

352 algorithm 

353 )) 

354 

355 @property 

356 def hash_algo(self): 

357 """ 

358 :return: 

359 A unicode string of "md2", "md5", "sha1", "sha224", "sha256", 

360 "sha384", "sha512", "sha512_224", "sha512_256" or "shake256" 

361 """ 

362 

363 algorithm = self['algorithm'].native 

364 

365 algo_map = { 

366 'md2_rsa': 'md2', 

367 'md5_rsa': 'md5', 

368 'sha1_rsa': 'sha1', 

369 'sha224_rsa': 'sha224', 

370 'sha256_rsa': 'sha256', 

371 'sha384_rsa': 'sha384', 

372 'sha512_rsa': 'sha512', 

373 'sha1_dsa': 'sha1', 

374 'sha224_dsa': 'sha224', 

375 'sha256_dsa': 'sha256', 

376 'sha1_ecdsa': 'sha1', 

377 'sha224_ecdsa': 'sha224', 

378 'sha256_ecdsa': 'sha256', 

379 'sha384_ecdsa': 'sha384', 

380 'sha512_ecdsa': 'sha512', 

381 'ed25519': 'sha512', 

382 'ed448': 'shake256', 

383 } 

384 if algorithm in algo_map: 

385 return algo_map[algorithm] 

386 

387 if algorithm == 'rsassa_pss': 

388 return self['parameters']['hash_algorithm']['algorithm'].native 

389 

390 raise ValueError(unwrap( 

391 ''' 

392 Hash algorithm not known for %s 

393 ''', 

394 algorithm 

395 )) 

396 

397 

398class Pbkdf2Salt(Choice): 

399 _alternatives = [ 

400 ('specified', OctetString), 

401 ('other_source', AlgorithmIdentifier), 

402 ] 

403 

404 

405class Pbkdf2Params(Sequence): 

406 _fields = [ 

407 ('salt', Pbkdf2Salt), 

408 ('iteration_count', Integer), 

409 ('key_length', Integer, {'optional': True}), 

410 ('prf', HmacAlgorithm, {'default': {'algorithm': 'sha1'}}), 

411 ] 

412 

413 

414class KdfAlgorithmId(ObjectIdentifier): 

415 _map = { 

416 '1.2.840.113549.1.5.12': 'pbkdf2' 

417 } 

418 

419 

420class KdfAlgorithm(Sequence): 

421 _fields = [ 

422 ('algorithm', KdfAlgorithmId), 

423 ('parameters', Any, {'optional': True}), 

424 ] 

425 _oid_pair = ('algorithm', 'parameters') 

426 _oid_specs = { 

427 'pbkdf2': Pbkdf2Params 

428 } 

429 

430 

431class DHParameters(Sequence): 

432 """ 

433 Original Name: DHParameter 

434 Source: ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-3.asc section 9 

435 """ 

436 

437 _fields = [ 

438 ('p', Integer), 

439 ('g', Integer), 

440 ('private_value_length', Integer, {'optional': True}), 

441 ] 

442 

443 

444class KeyExchangeAlgorithmId(ObjectIdentifier): 

445 _map = { 

446 '1.2.840.113549.1.3.1': 'dh', 

447 } 

448 

449 

450class KeyExchangeAlgorithm(Sequence): 

451 _fields = [ 

452 ('algorithm', KeyExchangeAlgorithmId), 

453 ('parameters', Any, {'optional': True}), 

454 ] 

455 _oid_pair = ('algorithm', 'parameters') 

456 _oid_specs = { 

457 'dh': DHParameters, 

458 } 

459 

460 

461class Rc2Params(Sequence): 

462 _fields = [ 

463 ('rc2_parameter_version', Integer, {'optional': True}), 

464 ('iv', OctetString), 

465 ] 

466 

467 

468class Rc5ParamVersion(Integer): 

469 _map = { 

470 16: 'v1-0' 

471 } 

472 

473 

474class Rc5Params(Sequence): 

475 _fields = [ 

476 ('version', Rc5ParamVersion), 

477 ('rounds', Integer), 

478 ('block_size_in_bits', Integer), 

479 ('iv', OctetString, {'optional': True}), 

480 ] 

481 

482 

483class Pbes1Params(Sequence): 

484 _fields = [ 

485 ('salt', OctetString), 

486 ('iterations', Integer), 

487 ] 

488 

489 

490class CcmParams(Sequence): 

491 # https://tools.ietf.org/html/rfc5084 

492 # aes_ICVlen: 4 | 6 | 8 | 10 | 12 | 14 | 16 

493 _fields = [ 

494 ('aes_nonce', OctetString), 

495 ('aes_icvlen', Integer), 

496 ] 

497 

498 

499class PSourceAlgorithmId(ObjectIdentifier): 

500 _map = { 

501 '1.2.840.113549.1.1.9': 'p_specified', 

502 } 

503 

504 

505class PSourceAlgorithm(Sequence): 

506 _fields = [ 

507 ('algorithm', PSourceAlgorithmId), 

508 ('parameters', Any, {'optional': True}), 

509 ] 

510 

511 _oid_pair = ('algorithm', 'parameters') 

512 _oid_specs = { 

513 'p_specified': OctetString 

514 } 

515 

516 

517class RSAESOAEPParams(Sequence): 

518 _fields = [ 

519 ( 

520 'hash_algorithm', 

521 DigestAlgorithm, 

522 { 

523 'explicit': 0, 

524 'default': {'algorithm': 'sha1'} 

525 } 

526 ), 

527 ( 

528 'mask_gen_algorithm', 

529 MaskGenAlgorithm, 

530 { 

531 'explicit': 1, 

532 'default': { 

533 'algorithm': 'mgf1', 

534 'parameters': {'algorithm': 'sha1'} 

535 } 

536 } 

537 ), 

538 ( 

539 'p_source_algorithm', 

540 PSourceAlgorithm, 

541 { 

542 'explicit': 2, 

543 'default': { 

544 'algorithm': 'p_specified', 

545 'parameters': b'' 

546 } 

547 } 

548 ), 

549 ] 

550 

551 

552class DSASignature(Sequence): 

553 """ 

554 An ASN.1 class for translating between the OS crypto library's 

555 representation of an (EC)DSA signature and the ASN.1 structure that is part 

556 of various RFCs. 

557 

558 Original Name: DSS-Sig-Value 

559 Source: https://tools.ietf.org/html/rfc3279#section-2.2.2 

560 """ 

561 

562 _fields = [ 

563 ('r', Integer), 

564 ('s', Integer), 

565 ] 

566 

567 @classmethod 

568 def from_p1363(cls, data): 

569 """ 

570 Reads a signature from a byte string encoding accordint to IEEE P1363, 

571 which is used by Microsoft's BCryptSignHash() function. 

572 

573 :param data: 

574 A byte string from BCryptSignHash() 

575 

576 :return: 

577 A DSASignature object 

578 """ 

579 

580 r = int_from_bytes(data[0:len(data) // 2]) 

581 s = int_from_bytes(data[len(data) // 2:]) 

582 return cls({'r': r, 's': s}) 

583 

584 def to_p1363(self): 

585 """ 

586 Dumps a signature to a byte string compatible with Microsoft's 

587 BCryptVerifySignature() function. 

588 

589 :return: 

590 A byte string compatible with BCryptVerifySignature() 

591 """ 

592 

593 r_bytes = int_to_bytes(self['r'].native) 

594 s_bytes = int_to_bytes(self['s'].native) 

595 

596 int_byte_length = max(len(r_bytes), len(s_bytes)) 

597 r_bytes = fill_width(r_bytes, int_byte_length) 

598 s_bytes = fill_width(s_bytes, int_byte_length) 

599 

600 return r_bytes + s_bytes 

601 

602 

603class EncryptionAlgorithmId(ObjectIdentifier): 

604 _map = { 

605 '1.3.14.3.2.7': 'des', 

606 '1.2.840.113549.3.7': 'tripledes_3key', 

607 '1.2.840.113549.3.2': 'rc2', 

608 '1.2.840.113549.3.4': 'rc4', 

609 '1.2.840.113549.3.9': 'rc5', 

610 # From http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html#AES 

611 '2.16.840.1.101.3.4.1.1': 'aes128_ecb', 

612 '2.16.840.1.101.3.4.1.2': 'aes128_cbc', 

613 '2.16.840.1.101.3.4.1.3': 'aes128_ofb', 

614 '2.16.840.1.101.3.4.1.4': 'aes128_cfb', 

615 '2.16.840.1.101.3.4.1.5': 'aes128_wrap', 

616 '2.16.840.1.101.3.4.1.6': 'aes128_gcm', 

617 '2.16.840.1.101.3.4.1.7': 'aes128_ccm', 

618 '2.16.840.1.101.3.4.1.8': 'aes128_wrap_pad', 

619 '2.16.840.1.101.3.4.1.21': 'aes192_ecb', 

620 '2.16.840.1.101.3.4.1.22': 'aes192_cbc', 

621 '2.16.840.1.101.3.4.1.23': 'aes192_ofb', 

622 '2.16.840.1.101.3.4.1.24': 'aes192_cfb', 

623 '2.16.840.1.101.3.4.1.25': 'aes192_wrap', 

624 '2.16.840.1.101.3.4.1.26': 'aes192_gcm', 

625 '2.16.840.1.101.3.4.1.27': 'aes192_ccm', 

626 '2.16.840.1.101.3.4.1.28': 'aes192_wrap_pad', 

627 '2.16.840.1.101.3.4.1.41': 'aes256_ecb', 

628 '2.16.840.1.101.3.4.1.42': 'aes256_cbc', 

629 '2.16.840.1.101.3.4.1.43': 'aes256_ofb', 

630 '2.16.840.1.101.3.4.1.44': 'aes256_cfb', 

631 '2.16.840.1.101.3.4.1.45': 'aes256_wrap', 

632 '2.16.840.1.101.3.4.1.46': 'aes256_gcm', 

633 '2.16.840.1.101.3.4.1.47': 'aes256_ccm', 

634 '2.16.840.1.101.3.4.1.48': 'aes256_wrap_pad', 

635 # From PKCS#5 

636 '1.2.840.113549.1.5.13': 'pbes2', 

637 '1.2.840.113549.1.5.1': 'pbes1_md2_des', 

638 '1.2.840.113549.1.5.3': 'pbes1_md5_des', 

639 '1.2.840.113549.1.5.4': 'pbes1_md2_rc2', 

640 '1.2.840.113549.1.5.6': 'pbes1_md5_rc2', 

641 '1.2.840.113549.1.5.10': 'pbes1_sha1_des', 

642 '1.2.840.113549.1.5.11': 'pbes1_sha1_rc2', 

643 # From PKCS#12 

644 '1.2.840.113549.1.12.1.1': 'pkcs12_sha1_rc4_128', 

645 '1.2.840.113549.1.12.1.2': 'pkcs12_sha1_rc4_40', 

646 '1.2.840.113549.1.12.1.3': 'pkcs12_sha1_tripledes_3key', 

647 '1.2.840.113549.1.12.1.4': 'pkcs12_sha1_tripledes_2key', 

648 '1.2.840.113549.1.12.1.5': 'pkcs12_sha1_rc2_128', 

649 '1.2.840.113549.1.12.1.6': 'pkcs12_sha1_rc2_40', 

650 # PKCS#1 v2.2 

651 '1.2.840.113549.1.1.1': 'rsaes_pkcs1v15', 

652 '1.2.840.113549.1.1.7': 'rsaes_oaep', 

653 } 

654 

655 

656class EncryptionAlgorithm(_ForceNullParameters, Sequence): 

657 _fields = [ 

658 ('algorithm', EncryptionAlgorithmId), 

659 ('parameters', Any, {'optional': True}), 

660 ] 

661 

662 _oid_pair = ('algorithm', 'parameters') 

663 _oid_specs = { 

664 'des': OctetString, 

665 'tripledes_3key': OctetString, 

666 'rc2': Rc2Params, 

667 'rc5': Rc5Params, 

668 'aes128_cbc': OctetString, 

669 'aes192_cbc': OctetString, 

670 'aes256_cbc': OctetString, 

671 'aes128_ofb': OctetString, 

672 'aes192_ofb': OctetString, 

673 'aes256_ofb': OctetString, 

674 # From RFC5084 

675 'aes128_ccm': CcmParams, 

676 'aes192_ccm': CcmParams, 

677 'aes256_ccm': CcmParams, 

678 # From PKCS#5 

679 'pbes1_md2_des': Pbes1Params, 

680 'pbes1_md5_des': Pbes1Params, 

681 'pbes1_md2_rc2': Pbes1Params, 

682 'pbes1_md5_rc2': Pbes1Params, 

683 'pbes1_sha1_des': Pbes1Params, 

684 'pbes1_sha1_rc2': Pbes1Params, 

685 # From PKCS#12 

686 'pkcs12_sha1_rc4_128': Pbes1Params, 

687 'pkcs12_sha1_rc4_40': Pbes1Params, 

688 'pkcs12_sha1_tripledes_3key': Pbes1Params, 

689 'pkcs12_sha1_tripledes_2key': Pbes1Params, 

690 'pkcs12_sha1_rc2_128': Pbes1Params, 

691 'pkcs12_sha1_rc2_40': Pbes1Params, 

692 # PKCS#1 v2.2 

693 'rsaes_oaep': RSAESOAEPParams, 

694 } 

695 

696 @property 

697 def kdf(self): 

698 """ 

699 Returns the name of the key derivation function to use. 

700 

701 :return: 

702 A unicode from of one of the following: "pbkdf1", "pbkdf2", 

703 "pkcs12_kdf" 

704 """ 

705 

706 encryption_algo = self['algorithm'].native 

707 

708 if encryption_algo == 'pbes2': 

709 return self['parameters']['key_derivation_func']['algorithm'].native 

710 

711 if encryption_algo.find('.') == -1: 

712 if encryption_algo.find('_') != -1: 

713 encryption_algo, _ = encryption_algo.split('_', 1) 

714 

715 if encryption_algo == 'pbes1': 

716 return 'pbkdf1' 

717 

718 if encryption_algo == 'pkcs12': 

719 return 'pkcs12_kdf' 

720 

721 raise ValueError(unwrap( 

722 ''' 

723 Encryption algorithm "%s" does not have a registered key 

724 derivation function 

725 ''', 

726 encryption_algo 

727 )) 

728 

729 raise ValueError(unwrap( 

730 ''' 

731 Unrecognized encryption algorithm "%s", can not determine key 

732 derivation function 

733 ''', 

734 encryption_algo 

735 )) 

736 

737 @property 

738 def kdf_hmac(self): 

739 """ 

740 Returns the HMAC algorithm to use with the KDF. 

741 

742 :return: 

743 A unicode string of one of the following: "md2", "md5", "sha1", 

744 "sha224", "sha256", "sha384", "sha512" 

745 """ 

746 

747 encryption_algo = self['algorithm'].native 

748 

749 if encryption_algo == 'pbes2': 

750 return self['parameters']['key_derivation_func']['parameters']['prf']['algorithm'].native 

751 

752 if encryption_algo.find('.') == -1: 

753 if encryption_algo.find('_') != -1: 

754 _, hmac_algo, _ = encryption_algo.split('_', 2) 

755 return hmac_algo 

756 

757 raise ValueError(unwrap( 

758 ''' 

759 Encryption algorithm "%s" does not have a registered key 

760 derivation function 

761 ''', 

762 encryption_algo 

763 )) 

764 

765 raise ValueError(unwrap( 

766 ''' 

767 Unrecognized encryption algorithm "%s", can not determine key 

768 derivation hmac algorithm 

769 ''', 

770 encryption_algo 

771 )) 

772 

773 @property 

774 def kdf_salt(self): 

775 """ 

776 Returns the byte string to use as the salt for the KDF. 

777 

778 :return: 

779 A byte string 

780 """ 

781 

782 encryption_algo = self['algorithm'].native 

783 

784 if encryption_algo == 'pbes2': 

785 salt = self['parameters']['key_derivation_func']['parameters']['salt'] 

786 

787 if salt.name == 'other_source': 

788 raise ValueError(unwrap( 

789 ''' 

790 Can not determine key derivation salt - the 

791 reserved-for-future-use other source salt choice was 

792 specified in the PBKDF2 params structure 

793 ''' 

794 )) 

795 

796 return salt.native 

797 

798 if encryption_algo.find('.') == -1: 

799 if encryption_algo.find('_') != -1: 

800 return self['parameters']['salt'].native 

801 

802 raise ValueError(unwrap( 

803 ''' 

804 Encryption algorithm "%s" does not have a registered key 

805 derivation function 

806 ''', 

807 encryption_algo 

808 )) 

809 

810 raise ValueError(unwrap( 

811 ''' 

812 Unrecognized encryption algorithm "%s", can not determine key 

813 derivation salt 

814 ''', 

815 encryption_algo 

816 )) 

817 

818 @property 

819 def kdf_iterations(self): 

820 """ 

821 Returns the number of iterations that should be run via the KDF. 

822 

823 :return: 

824 An integer 

825 """ 

826 

827 encryption_algo = self['algorithm'].native 

828 

829 if encryption_algo == 'pbes2': 

830 return self['parameters']['key_derivation_func']['parameters']['iteration_count'].native 

831 

832 if encryption_algo.find('.') == -1: 

833 if encryption_algo.find('_') != -1: 

834 return self['parameters']['iterations'].native 

835 

836 raise ValueError(unwrap( 

837 ''' 

838 Encryption algorithm "%s" does not have a registered key 

839 derivation function 

840 ''', 

841 encryption_algo 

842 )) 

843 

844 raise ValueError(unwrap( 

845 ''' 

846 Unrecognized encryption algorithm "%s", can not determine key 

847 derivation iterations 

848 ''', 

849 encryption_algo 

850 )) 

851 

852 @property 

853 def key_length(self): 

854 """ 

855 Returns the key length to pass to the cipher/kdf. The PKCS#5 spec does 

856 not specify a way to store the RC5 key length, however this tends not 

857 to be a problem since OpenSSL does not support RC5 in PKCS#8 and OS X 

858 does not provide an RC5 cipher for use in the Security Transforms 

859 library. 

860 

861 :raises: 

862 ValueError - when the key length can not be determined 

863 

864 :return: 

865 An integer representing the length in bytes 

866 """ 

867 

868 encryption_algo = self['algorithm'].native 

869 

870 if encryption_algo[0:3] == 'aes': 

871 return { 

872 'aes128_': 16, 

873 'aes192_': 24, 

874 'aes256_': 32, 

875 }[encryption_algo[0:7]] 

876 

877 cipher_lengths = { 

878 'des': 8, 

879 'tripledes_3key': 24, 

880 } 

881 

882 if encryption_algo in cipher_lengths: 

883 return cipher_lengths[encryption_algo] 

884 

885 if encryption_algo == 'rc2': 

886 rc2_parameter_version = self['parameters']['rc2_parameter_version'].native 

887 

888 # See page 24 of 

889 # http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf 

890 encoded_key_bits_map = { 

891 160: 5, # 40-bit 

892 120: 8, # 64-bit 

893 58: 16, # 128-bit 

894 } 

895 

896 if rc2_parameter_version in encoded_key_bits_map: 

897 return encoded_key_bits_map[rc2_parameter_version] 

898 

899 if rc2_parameter_version >= 256: 

900 return rc2_parameter_version 

901 

902 if rc2_parameter_version is None: 

903 return 4 # 32-bit default 

904 

905 raise ValueError(unwrap( 

906 ''' 

907 Invalid RC2 parameter version found in EncryptionAlgorithm 

908 parameters 

909 ''' 

910 )) 

911 

912 if encryption_algo == 'pbes2': 

913 key_length = self['parameters']['key_derivation_func']['parameters']['key_length'].native 

914 if key_length is not None: 

915 return key_length 

916 

917 # If the KDF params don't specify the key size, we can infer it from 

918 # the encryption scheme for all schemes except for RC5. However, in 

919 # practical terms, neither OpenSSL or OS X support RC5 for PKCS#8 

920 # so it is unlikely to be an issue that is run into. 

921 

922 return self['parameters']['encryption_scheme'].key_length 

923 

924 if encryption_algo.find('.') == -1: 

925 return { 

926 'pbes1_md2_des': 8, 

927 'pbes1_md5_des': 8, 

928 'pbes1_md2_rc2': 8, 

929 'pbes1_md5_rc2': 8, 

930 'pbes1_sha1_des': 8, 

931 'pbes1_sha1_rc2': 8, 

932 'pkcs12_sha1_rc4_128': 16, 

933 'pkcs12_sha1_rc4_40': 5, 

934 'pkcs12_sha1_tripledes_3key': 24, 

935 'pkcs12_sha1_tripledes_2key': 16, 

936 'pkcs12_sha1_rc2_128': 16, 

937 'pkcs12_sha1_rc2_40': 5, 

938 }[encryption_algo] 

939 

940 raise ValueError(unwrap( 

941 ''' 

942 Unrecognized encryption algorithm "%s" 

943 ''', 

944 encryption_algo 

945 )) 

946 

947 @property 

948 def encryption_mode(self): 

949 """ 

950 Returns the name of the encryption mode to use. 

951 

952 :return: 

953 A unicode string from one of the following: "cbc", "ecb", "ofb", 

954 "cfb", "wrap", "gcm", "ccm", "wrap_pad" 

955 """ 

956 

957 encryption_algo = self['algorithm'].native 

958 

959 if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']): 

960 return encryption_algo[7:] 

961 

962 if encryption_algo[0:6] == 'pbes1_': 

963 return 'cbc' 

964 

965 if encryption_algo[0:7] == 'pkcs12_': 

966 return 'cbc' 

967 

968 if encryption_algo in set(['des', 'tripledes_3key', 'rc2', 'rc5']): 

969 return 'cbc' 

970 

971 if encryption_algo == 'pbes2': 

972 return self['parameters']['encryption_scheme'].encryption_mode 

973 

974 raise ValueError(unwrap( 

975 ''' 

976 Unrecognized encryption algorithm "%s" 

977 ''', 

978 encryption_algo 

979 )) 

980 

981 @property 

982 def encryption_cipher(self): 

983 """ 

984 Returns the name of the symmetric encryption cipher to use. The key 

985 length can be retrieved via the .key_length property to disabiguate 

986 between different variations of TripleDES, AES, and the RC* ciphers. 

987 

988 :return: 

989 A unicode string from one of the following: "rc2", "rc5", "des", 

990 "tripledes", "aes" 

991 """ 

992 

993 encryption_algo = self['algorithm'].native 

994 

995 if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']): 

996 return 'aes' 

997 

998 if encryption_algo in set(['des', 'rc2', 'rc5']): 

999 return encryption_algo 

1000 

1001 if encryption_algo == 'tripledes_3key': 

1002 return 'tripledes' 

1003 

1004 if encryption_algo == 'pbes2': 

1005 return self['parameters']['encryption_scheme'].encryption_cipher 

1006 

1007 if encryption_algo.find('.') == -1: 

1008 return { 

1009 'pbes1_md2_des': 'des', 

1010 'pbes1_md5_des': 'des', 

1011 'pbes1_md2_rc2': 'rc2', 

1012 'pbes1_md5_rc2': 'rc2', 

1013 'pbes1_sha1_des': 'des', 

1014 'pbes1_sha1_rc2': 'rc2', 

1015 'pkcs12_sha1_rc4_128': 'rc4', 

1016 'pkcs12_sha1_rc4_40': 'rc4', 

1017 'pkcs12_sha1_tripledes_3key': 'tripledes', 

1018 'pkcs12_sha1_tripledes_2key': 'tripledes', 

1019 'pkcs12_sha1_rc2_128': 'rc2', 

1020 'pkcs12_sha1_rc2_40': 'rc2', 

1021 }[encryption_algo] 

1022 

1023 raise ValueError(unwrap( 

1024 ''' 

1025 Unrecognized encryption algorithm "%s" 

1026 ''', 

1027 encryption_algo 

1028 )) 

1029 

1030 @property 

1031 def encryption_block_size(self): 

1032 """ 

1033 Returns the block size of the encryption cipher, in bytes. 

1034 

1035 :return: 

1036 An integer that is the block size in bytes 

1037 """ 

1038 

1039 encryption_algo = self['algorithm'].native 

1040 

1041 if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']): 

1042 return 16 

1043 

1044 cipher_map = { 

1045 'des': 8, 

1046 'tripledes_3key': 8, 

1047 'rc2': 8, 

1048 } 

1049 if encryption_algo in cipher_map: 

1050 return cipher_map[encryption_algo] 

1051 

1052 if encryption_algo == 'rc5': 

1053 return self['parameters']['block_size_in_bits'].native // 8 

1054 

1055 if encryption_algo == 'pbes2': 

1056 return self['parameters']['encryption_scheme'].encryption_block_size 

1057 

1058 if encryption_algo.find('.') == -1: 

1059 return { 

1060 'pbes1_md2_des': 8, 

1061 'pbes1_md5_des': 8, 

1062 'pbes1_md2_rc2': 8, 

1063 'pbes1_md5_rc2': 8, 

1064 'pbes1_sha1_des': 8, 

1065 'pbes1_sha1_rc2': 8, 

1066 'pkcs12_sha1_rc4_128': 0, 

1067 'pkcs12_sha1_rc4_40': 0, 

1068 'pkcs12_sha1_tripledes_3key': 8, 

1069 'pkcs12_sha1_tripledes_2key': 8, 

1070 'pkcs12_sha1_rc2_128': 8, 

1071 'pkcs12_sha1_rc2_40': 8, 

1072 }[encryption_algo] 

1073 

1074 raise ValueError(unwrap( 

1075 ''' 

1076 Unrecognized encryption algorithm "%s" 

1077 ''', 

1078 encryption_algo 

1079 )) 

1080 

1081 @property 

1082 def encryption_iv(self): 

1083 """ 

1084 Returns the byte string of the initialization vector for the encryption 

1085 scheme. Only the PBES2 stores the IV in the params. For PBES1, the IV 

1086 is derived from the KDF and this property will return None. 

1087 

1088 :return: 

1089 A byte string or None 

1090 """ 

1091 

1092 encryption_algo = self['algorithm'].native 

1093 

1094 if encryption_algo in set(['rc2', 'rc5']): 

1095 return self['parameters']['iv'].native 

1096 

1097 # For DES/Triple DES and AES the IV is the entirety of the parameters 

1098 octet_string_iv_oids = set([ 

1099 'des', 

1100 'tripledes_3key', 

1101 'aes128_cbc', 

1102 'aes192_cbc', 

1103 'aes256_cbc', 

1104 'aes128_ofb', 

1105 'aes192_ofb', 

1106 'aes256_ofb', 

1107 ]) 

1108 if encryption_algo in octet_string_iv_oids: 

1109 return self['parameters'].native 

1110 

1111 if encryption_algo == 'pbes2': 

1112 return self['parameters']['encryption_scheme'].encryption_iv 

1113 

1114 # All of the PBES1 algos use their KDF to create the IV. For the pbkdf1, 

1115 # the KDF is told to generate a key that is an extra 8 bytes long, and 

1116 # that is used for the IV. For the PKCS#12 KDF, it is called with an id 

1117 # of 2 to generate the IV. In either case, we can't return the IV 

1118 # without knowing the user's password. 

1119 if encryption_algo.find('.') == -1: 

1120 return None 

1121 

1122 raise ValueError(unwrap( 

1123 ''' 

1124 Unrecognized encryption algorithm "%s" 

1125 ''', 

1126 encryption_algo 

1127 )) 

1128 

1129 

1130class Pbes2Params(Sequence): 

1131 _fields = [ 

1132 ('key_derivation_func', KdfAlgorithm), 

1133 ('encryption_scheme', EncryptionAlgorithm), 

1134 ] 

1135 

1136 

1137class Pbmac1Params(Sequence): 

1138 _fields = [ 

1139 ('key_derivation_func', KdfAlgorithm), 

1140 ('message_auth_scheme', HmacAlgorithm), 

1141 ] 

1142 

1143 

1144class Pkcs5MacId(ObjectIdentifier): 

1145 _map = { 

1146 '1.2.840.113549.1.5.14': 'pbmac1', 

1147 } 

1148 

1149 

1150class Pkcs5MacAlgorithm(Sequence): 

1151 _fields = [ 

1152 ('algorithm', Pkcs5MacId), 

1153 ('parameters', Any), 

1154 ] 

1155 

1156 _oid_pair = ('algorithm', 'parameters') 

1157 _oid_specs = { 

1158 'pbmac1': Pbmac1Params, 

1159 } 

1160 

1161 

1162EncryptionAlgorithm._oid_specs['pbes2'] = Pbes2Params 

1163 

1164 

1165class AnyAlgorithmId(ObjectIdentifier): 

1166 _map = {} 

1167 

1168 def _setup(self): 

1169 _map = self.__class__._map 

1170 for other_cls in (EncryptionAlgorithmId, SignedDigestAlgorithmId, DigestAlgorithmId): 

1171 for oid, name in other_cls._map.items(): 

1172 _map[oid] = name 

1173 

1174 

1175class AnyAlgorithmIdentifier(_ForceNullParameters, Sequence): 

1176 _fields = [ 

1177 ('algorithm', AnyAlgorithmId), 

1178 ('parameters', Any, {'optional': True}), 

1179 ] 

1180 

1181 _oid_pair = ('algorithm', 'parameters') 

1182 _oid_specs = {} 

1183 

1184 def _setup(self): 

1185 Sequence._setup(self) 

1186 specs = self.__class__._oid_specs 

1187 for other_cls in (EncryptionAlgorithm, SignedDigestAlgorithm): 

1188 for oid, spec in other_cls._oid_specs.items(): 

1189 specs[oid] = spec