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 } 264 265 _reverse_map = { 266 'dsa': '1.2.840.10040.4.1', 267 'ecdsa': '1.2.840.10045.4', 268 'md2_rsa': '1.2.840.113549.1.1.2', 269 'md5_rsa': '1.2.840.113549.1.1.4', 270 'rsassa_pkcs1v15': '1.2.840.113549.1.1.1', 271 'rsassa_pss': '1.2.840.113549.1.1.10', 272 'sha1_dsa': '1.2.840.10040.4.3', 273 'sha1_ecdsa': '1.2.840.10045.4.1', 274 'sha1_rsa': '1.2.840.113549.1.1.5', 275 'sha224_dsa': '2.16.840.1.101.3.4.3.1', 276 'sha224_ecdsa': '1.2.840.10045.4.3.1', 277 'sha224_rsa': '1.2.840.113549.1.1.14', 278 'sha256_dsa': '2.16.840.1.101.3.4.3.2', 279 'sha256_ecdsa': '1.2.840.10045.4.3.2', 280 'sha256_rsa': '1.2.840.113549.1.1.11', 281 'sha384_ecdsa': '1.2.840.10045.4.3.3', 282 'sha384_rsa': '1.2.840.113549.1.1.12', 283 'sha512_ecdsa': '1.2.840.10045.4.3.4', 284 'sha512_rsa': '1.2.840.113549.1.1.13', 285 'sha3_224_ecdsa': '2.16.840.1.101.3.4.3.9', 286 'sha3_256_ecdsa': '2.16.840.1.101.3.4.3.10', 287 'sha3_384_ecdsa': '2.16.840.1.101.3.4.3.11', 288 'sha3_512_ecdsa': '2.16.840.1.101.3.4.3.12', 289 } 290 291 292class SignedDigestAlgorithm(_ForceNullParameters, Sequence): 293 _fields = [ 294 ('algorithm', SignedDigestAlgorithmId), 295 ('parameters', Any, {'optional': True}), 296 ] 297 298 _oid_pair = ('algorithm', 'parameters') 299 _oid_specs = { 300 'rsassa_pss': RSASSAPSSParams, 301 } 302 303 @property 304 def signature_algo(self): 305 """ 306 :return: 307 A unicode string of "rsassa_pkcs1v15", "rsassa_pss", "dsa" or 308 "ecdsa" 309 """ 310 311 algorithm = self['algorithm'].native 312 313 algo_map = { 314 'md2_rsa': 'rsassa_pkcs1v15', 315 'md5_rsa': 'rsassa_pkcs1v15', 316 'sha1_rsa': 'rsassa_pkcs1v15', 317 'sha224_rsa': 'rsassa_pkcs1v15', 318 'sha256_rsa': 'rsassa_pkcs1v15', 319 'sha384_rsa': 'rsassa_pkcs1v15', 320 'sha512_rsa': 'rsassa_pkcs1v15', 321 'rsassa_pkcs1v15': 'rsassa_pkcs1v15', 322 'rsassa_pss': 'rsassa_pss', 323 'sha1_dsa': 'dsa', 324 'sha224_dsa': 'dsa', 325 'sha256_dsa': 'dsa', 326 'dsa': 'dsa', 327 'sha1_ecdsa': 'ecdsa', 328 'sha224_ecdsa': 'ecdsa', 329 'sha256_ecdsa': 'ecdsa', 330 'sha384_ecdsa': 'ecdsa', 331 'sha512_ecdsa': 'ecdsa', 332 'sha3_224_ecdsa': 'ecdsa', 333 'sha3_256_ecdsa': 'ecdsa', 334 'sha3_384_ecdsa': 'ecdsa', 335 'sha3_512_ecdsa': 'ecdsa', 336 'ecdsa': 'ecdsa', 337 } 338 if algorithm in algo_map: 339 return algo_map[algorithm] 340 341 raise ValueError(unwrap( 342 ''' 343 Signature algorithm not known for %s 344 ''', 345 algorithm 346 )) 347 348 @property 349 def hash_algo(self): 350 """ 351 :return: 352 A unicode string of "md2", "md5", "sha1", "sha224", "sha256", 353 "sha384", "sha512", "sha512_224", "sha512_256" 354 """ 355 356 algorithm = self['algorithm'].native 357 358 algo_map = { 359 'md2_rsa': 'md2', 360 'md5_rsa': 'md5', 361 'sha1_rsa': 'sha1', 362 'sha224_rsa': 'sha224', 363 'sha256_rsa': 'sha256', 364 'sha384_rsa': 'sha384', 365 'sha512_rsa': 'sha512', 366 'sha1_dsa': 'sha1', 367 'sha224_dsa': 'sha224', 368 'sha256_dsa': 'sha256', 369 'sha1_ecdsa': 'sha1', 370 'sha224_ecdsa': 'sha224', 371 'sha256_ecdsa': 'sha256', 372 'sha384_ecdsa': 'sha384', 373 'sha512_ecdsa': 'sha512', 374 } 375 if algorithm in algo_map: 376 return algo_map[algorithm] 377 378 if algorithm == 'rsassa_pss': 379 return self['parameters']['hash_algorithm']['algorithm'].native 380 381 raise ValueError(unwrap( 382 ''' 383 Hash algorithm not known for %s 384 ''', 385 algorithm 386 )) 387 388 389class Pbkdf2Salt(Choice): 390 _alternatives = [ 391 ('specified', OctetString), 392 ('other_source', AlgorithmIdentifier), 393 ] 394 395 396class Pbkdf2Params(Sequence): 397 _fields = [ 398 ('salt', Pbkdf2Salt), 399 ('iteration_count', Integer), 400 ('key_length', Integer, {'optional': True}), 401 ('prf', HmacAlgorithm, {'default': {'algorithm': 'sha1'}}), 402 ] 403 404 405class KdfAlgorithmId(ObjectIdentifier): 406 _map = { 407 '1.2.840.113549.1.5.12': 'pbkdf2' 408 } 409 410 411class KdfAlgorithm(Sequence): 412 _fields = [ 413 ('algorithm', KdfAlgorithmId), 414 ('parameters', Any, {'optional': True}), 415 ] 416 _oid_pair = ('algorithm', 'parameters') 417 _oid_specs = { 418 'pbkdf2': Pbkdf2Params 419 } 420 421 422class DHParameters(Sequence): 423 """ 424 Original Name: DHParameter 425 Source: ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-3.asc section 9 426 """ 427 428 _fields = [ 429 ('p', Integer), 430 ('g', Integer), 431 ('private_value_length', Integer, {'optional': True}), 432 ] 433 434 435class KeyExchangeAlgorithmId(ObjectIdentifier): 436 _map = { 437 '1.2.840.113549.1.3.1': 'dh', 438 } 439 440 441class KeyExchangeAlgorithm(Sequence): 442 _fields = [ 443 ('algorithm', KeyExchangeAlgorithmId), 444 ('parameters', Any, {'optional': True}), 445 ] 446 _oid_pair = ('algorithm', 'parameters') 447 _oid_specs = { 448 'dh': DHParameters, 449 } 450 451 452class Rc2Params(Sequence): 453 _fields = [ 454 ('rc2_parameter_version', Integer, {'optional': True}), 455 ('iv', OctetString), 456 ] 457 458 459class Rc5ParamVersion(Integer): 460 _map = { 461 16: 'v1-0' 462 } 463 464 465class Rc5Params(Sequence): 466 _fields = [ 467 ('version', Rc5ParamVersion), 468 ('rounds', Integer), 469 ('block_size_in_bits', Integer), 470 ('iv', OctetString, {'optional': True}), 471 ] 472 473 474class Pbes1Params(Sequence): 475 _fields = [ 476 ('salt', OctetString), 477 ('iterations', Integer), 478 ] 479 480 481class CcmParams(Sequence): 482 # https://tools.ietf.org/html/rfc5084 483 # aes_ICVlen: 4 | 6 | 8 | 10 | 12 | 14 | 16 484 _fields = [ 485 ('aes_nonce', OctetString), 486 ('aes_icvlen', Integer), 487 ] 488 489 490class PSourceAlgorithmId(ObjectIdentifier): 491 _map = { 492 '1.2.840.113549.1.1.9': 'p_specified', 493 } 494 495 496class PSourceAlgorithm(Sequence): 497 _fields = [ 498 ('algorithm', PSourceAlgorithmId), 499 ('parameters', Any, {'optional': True}), 500 ] 501 502 _oid_pair = ('algorithm', 'parameters') 503 _oid_specs = { 504 'p_specified': OctetString 505 } 506 507 508class RSAESOAEPParams(Sequence): 509 _fields = [ 510 ( 511 'hash_algorithm', 512 DigestAlgorithm, 513 { 514 'explicit': 0, 515 'default': {'algorithm': 'sha1'} 516 } 517 ), 518 ( 519 'mask_gen_algorithm', 520 MaskGenAlgorithm, 521 { 522 'explicit': 1, 523 'default': { 524 'algorithm': 'mgf1', 525 'parameters': {'algorithm': 'sha1'} 526 } 527 } 528 ), 529 ( 530 'p_source_algorithm', 531 PSourceAlgorithm, 532 { 533 'explicit': 2, 534 'default': { 535 'algorithm': 'p_specified', 536 'parameters': b'' 537 } 538 } 539 ), 540 ] 541 542 543class DSASignature(Sequence): 544 """ 545 An ASN.1 class for translating between the OS crypto library's 546 representation of an (EC)DSA signature and the ASN.1 structure that is part 547 of various RFCs. 548 549 Original Name: DSS-Sig-Value 550 Source: https://tools.ietf.org/html/rfc3279#section-2.2.2 551 """ 552 553 _fields = [ 554 ('r', Integer), 555 ('s', Integer), 556 ] 557 558 @classmethod 559 def from_p1363(cls, data): 560 """ 561 Reads a signature from a byte string encoding accordint to IEEE P1363, 562 which is used by Microsoft's BCryptSignHash() function. 563 564 :param data: 565 A byte string from BCryptSignHash() 566 567 :return: 568 A DSASignature object 569 """ 570 571 r = int_from_bytes(data[0:len(data) // 2]) 572 s = int_from_bytes(data[len(data) // 2:]) 573 return cls({'r': r, 's': s}) 574 575 def to_p1363(self): 576 """ 577 Dumps a signature to a byte string compatible with Microsoft's 578 BCryptVerifySignature() function. 579 580 :return: 581 A byte string compatible with BCryptVerifySignature() 582 """ 583 584 r_bytes = int_to_bytes(self['r'].native) 585 s_bytes = int_to_bytes(self['s'].native) 586 587 int_byte_length = max(len(r_bytes), len(s_bytes)) 588 r_bytes = fill_width(r_bytes, int_byte_length) 589 s_bytes = fill_width(s_bytes, int_byte_length) 590 591 return r_bytes + s_bytes 592 593 594class EncryptionAlgorithmId(ObjectIdentifier): 595 _map = { 596 '1.3.14.3.2.7': 'des', 597 '1.2.840.113549.3.7': 'tripledes_3key', 598 '1.2.840.113549.3.2': 'rc2', 599 '1.2.840.113549.3.4': 'rc4', 600 '1.2.840.113549.3.9': 'rc5', 601 # From http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html#AES 602 '2.16.840.1.101.3.4.1.1': 'aes128_ecb', 603 '2.16.840.1.101.3.4.1.2': 'aes128_cbc', 604 '2.16.840.1.101.3.4.1.3': 'aes128_ofb', 605 '2.16.840.1.101.3.4.1.4': 'aes128_cfb', 606 '2.16.840.1.101.3.4.1.5': 'aes128_wrap', 607 '2.16.840.1.101.3.4.1.6': 'aes128_gcm', 608 '2.16.840.1.101.3.4.1.7': 'aes128_ccm', 609 '2.16.840.1.101.3.4.1.8': 'aes128_wrap_pad', 610 '2.16.840.1.101.3.4.1.21': 'aes192_ecb', 611 '2.16.840.1.101.3.4.1.22': 'aes192_cbc', 612 '2.16.840.1.101.3.4.1.23': 'aes192_ofb', 613 '2.16.840.1.101.3.4.1.24': 'aes192_cfb', 614 '2.16.840.1.101.3.4.1.25': 'aes192_wrap', 615 '2.16.840.1.101.3.4.1.26': 'aes192_gcm', 616 '2.16.840.1.101.3.4.1.27': 'aes192_ccm', 617 '2.16.840.1.101.3.4.1.28': 'aes192_wrap_pad', 618 '2.16.840.1.101.3.4.1.41': 'aes256_ecb', 619 '2.16.840.1.101.3.4.1.42': 'aes256_cbc', 620 '2.16.840.1.101.3.4.1.43': 'aes256_ofb', 621 '2.16.840.1.101.3.4.1.44': 'aes256_cfb', 622 '2.16.840.1.101.3.4.1.45': 'aes256_wrap', 623 '2.16.840.1.101.3.4.1.46': 'aes256_gcm', 624 '2.16.840.1.101.3.4.1.47': 'aes256_ccm', 625 '2.16.840.1.101.3.4.1.48': 'aes256_wrap_pad', 626 # From PKCS#5 627 '1.2.840.113549.1.5.13': 'pbes2', 628 '1.2.840.113549.1.5.1': 'pbes1_md2_des', 629 '1.2.840.113549.1.5.3': 'pbes1_md5_des', 630 '1.2.840.113549.1.5.4': 'pbes1_md2_rc2', 631 '1.2.840.113549.1.5.6': 'pbes1_md5_rc2', 632 '1.2.840.113549.1.5.10': 'pbes1_sha1_des', 633 '1.2.840.113549.1.5.11': 'pbes1_sha1_rc2', 634 # From PKCS#12 635 '1.2.840.113549.1.12.1.1': 'pkcs12_sha1_rc4_128', 636 '1.2.840.113549.1.12.1.2': 'pkcs12_sha1_rc4_40', 637 '1.2.840.113549.1.12.1.3': 'pkcs12_sha1_tripledes_3key', 638 '1.2.840.113549.1.12.1.4': 'pkcs12_sha1_tripledes_2key', 639 '1.2.840.113549.1.12.1.5': 'pkcs12_sha1_rc2_128', 640 '1.2.840.113549.1.12.1.6': 'pkcs12_sha1_rc2_40', 641 # PKCS#1 v2.2 642 '1.2.840.113549.1.1.1': 'rsaes_pkcs1v15', 643 '1.2.840.113549.1.1.7': 'rsaes_oaep', 644 } 645 646 647class EncryptionAlgorithm(_ForceNullParameters, Sequence): 648 _fields = [ 649 ('algorithm', EncryptionAlgorithmId), 650 ('parameters', Any, {'optional': True}), 651 ] 652 653 _oid_pair = ('algorithm', 'parameters') 654 _oid_specs = { 655 'des': OctetString, 656 'tripledes_3key': OctetString, 657 'rc2': Rc2Params, 658 'rc5': Rc5Params, 659 'aes128_cbc': OctetString, 660 'aes192_cbc': OctetString, 661 'aes256_cbc': OctetString, 662 'aes128_ofb': OctetString, 663 'aes192_ofb': OctetString, 664 'aes256_ofb': OctetString, 665 # From RFC5084 666 'aes128_ccm': CcmParams, 667 'aes192_ccm': CcmParams, 668 'aes256_ccm': CcmParams, 669 # From PKCS#5 670 'pbes1_md2_des': Pbes1Params, 671 'pbes1_md5_des': Pbes1Params, 672 'pbes1_md2_rc2': Pbes1Params, 673 'pbes1_md5_rc2': Pbes1Params, 674 'pbes1_sha1_des': Pbes1Params, 675 'pbes1_sha1_rc2': Pbes1Params, 676 # From PKCS#12 677 'pkcs12_sha1_rc4_128': Pbes1Params, 678 'pkcs12_sha1_rc4_40': Pbes1Params, 679 'pkcs12_sha1_tripledes_3key': Pbes1Params, 680 'pkcs12_sha1_tripledes_2key': Pbes1Params, 681 'pkcs12_sha1_rc2_128': Pbes1Params, 682 'pkcs12_sha1_rc2_40': Pbes1Params, 683 # PKCS#1 v2.2 684 'rsaes_oaep': RSAESOAEPParams, 685 } 686 687 @property 688 def kdf(self): 689 """ 690 Returns the name of the key derivation function to use. 691 692 :return: 693 A unicode from of one of the following: "pbkdf1", "pbkdf2", 694 "pkcs12_kdf" 695 """ 696 697 encryption_algo = self['algorithm'].native 698 699 if encryption_algo == 'pbes2': 700 return self['parameters']['key_derivation_func']['algorithm'].native 701 702 if encryption_algo.find('.') == -1: 703 if encryption_algo.find('_') != -1: 704 encryption_algo, _ = encryption_algo.split('_', 1) 705 706 if encryption_algo == 'pbes1': 707 return 'pbkdf1' 708 709 if encryption_algo == 'pkcs12': 710 return 'pkcs12_kdf' 711 712 raise ValueError(unwrap( 713 ''' 714 Encryption algorithm "%s" does not have a registered key 715 derivation function 716 ''', 717 encryption_algo 718 )) 719 720 raise ValueError(unwrap( 721 ''' 722 Unrecognized encryption algorithm "%s", can not determine key 723 derivation function 724 ''', 725 encryption_algo 726 )) 727 728 @property 729 def kdf_hmac(self): 730 """ 731 Returns the HMAC algorithm to use with the KDF. 732 733 :return: 734 A unicode string of one of the following: "md2", "md5", "sha1", 735 "sha224", "sha256", "sha384", "sha512" 736 """ 737 738 encryption_algo = self['algorithm'].native 739 740 if encryption_algo == 'pbes2': 741 return self['parameters']['key_derivation_func']['parameters']['prf']['algorithm'].native 742 743 if encryption_algo.find('.') == -1: 744 if encryption_algo.find('_') != -1: 745 _, hmac_algo, _ = encryption_algo.split('_', 2) 746 return hmac_algo 747 748 raise ValueError(unwrap( 749 ''' 750 Encryption algorithm "%s" does not have a registered key 751 derivation function 752 ''', 753 encryption_algo 754 )) 755 756 raise ValueError(unwrap( 757 ''' 758 Unrecognized encryption algorithm "%s", can not determine key 759 derivation hmac algorithm 760 ''', 761 encryption_algo 762 )) 763 764 @property 765 def kdf_salt(self): 766 """ 767 Returns the byte string to use as the salt for the KDF. 768 769 :return: 770 A byte string 771 """ 772 773 encryption_algo = self['algorithm'].native 774 775 if encryption_algo == 'pbes2': 776 salt = self['parameters']['key_derivation_func']['parameters']['salt'] 777 778 if salt.name == 'other_source': 779 raise ValueError(unwrap( 780 ''' 781 Can not determine key derivation salt - the 782 reserved-for-future-use other source salt choice was 783 specified in the PBKDF2 params structure 784 ''' 785 )) 786 787 return salt.native 788 789 if encryption_algo.find('.') == -1: 790 if encryption_algo.find('_') != -1: 791 return self['parameters']['salt'].native 792 793 raise ValueError(unwrap( 794 ''' 795 Encryption algorithm "%s" does not have a registered key 796 derivation function 797 ''', 798 encryption_algo 799 )) 800 801 raise ValueError(unwrap( 802 ''' 803 Unrecognized encryption algorithm "%s", can not determine key 804 derivation salt 805 ''', 806 encryption_algo 807 )) 808 809 @property 810 def kdf_iterations(self): 811 """ 812 Returns the number of iterations that should be run via the KDF. 813 814 :return: 815 An integer 816 """ 817 818 encryption_algo = self['algorithm'].native 819 820 if encryption_algo == 'pbes2': 821 return self['parameters']['key_derivation_func']['parameters']['iteration_count'].native 822 823 if encryption_algo.find('.') == -1: 824 if encryption_algo.find('_') != -1: 825 return self['parameters']['iterations'].native 826 827 raise ValueError(unwrap( 828 ''' 829 Encryption algorithm "%s" does not have a registered key 830 derivation function 831 ''', 832 encryption_algo 833 )) 834 835 raise ValueError(unwrap( 836 ''' 837 Unrecognized encryption algorithm "%s", can not determine key 838 derivation iterations 839 ''', 840 encryption_algo 841 )) 842 843 @property 844 def key_length(self): 845 """ 846 Returns the key length to pass to the cipher/kdf. The PKCS#5 spec does 847 not specify a way to store the RC5 key length, however this tends not 848 to be a problem since OpenSSL does not support RC5 in PKCS#8 and OS X 849 does not provide an RC5 cipher for use in the Security Transforms 850 library. 851 852 :raises: 853 ValueError - when the key length can not be determined 854 855 :return: 856 An integer representing the length in bytes 857 """ 858 859 encryption_algo = self['algorithm'].native 860 861 if encryption_algo[0:3] == 'aes': 862 return { 863 'aes128_': 16, 864 'aes192_': 24, 865 'aes256_': 32, 866 }[encryption_algo[0:7]] 867 868 cipher_lengths = { 869 'des': 8, 870 'tripledes_3key': 24, 871 } 872 873 if encryption_algo in cipher_lengths: 874 return cipher_lengths[encryption_algo] 875 876 if encryption_algo == 'rc2': 877 rc2_params = self['parameters'].parsed['encryption_scheme']['parameters'].parsed 878 rc2_parameter_version = rc2_params['rc2_parameter_version'].native 879 880 # See page 24 of 881 # http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf 882 encoded_key_bits_map = { 883 160: 5, # 40-bit 884 120: 8, # 64-bit 885 58: 16, # 128-bit 886 } 887 888 if rc2_parameter_version in encoded_key_bits_map: 889 return encoded_key_bits_map[rc2_parameter_version] 890 891 if rc2_parameter_version >= 256: 892 return rc2_parameter_version 893 894 if rc2_parameter_version is None: 895 return 4 # 32-bit default 896 897 raise ValueError(unwrap( 898 ''' 899 Invalid RC2 parameter version found in EncryptionAlgorithm 900 parameters 901 ''' 902 )) 903 904 if encryption_algo == 'pbes2': 905 key_length = self['parameters']['key_derivation_func']['parameters']['key_length'].native 906 if key_length is not None: 907 return key_length 908 909 # If the KDF params don't specify the key size, we can infer it from 910 # the encryption scheme for all schemes except for RC5. However, in 911 # practical terms, neither OpenSSL or OS X support RC5 for PKCS#8 912 # so it is unlikely to be an issue that is run into. 913 914 return self['parameters']['encryption_scheme'].key_length 915 916 if encryption_algo.find('.') == -1: 917 return { 918 'pbes1_md2_des': 8, 919 'pbes1_md5_des': 8, 920 'pbes1_md2_rc2': 8, 921 'pbes1_md5_rc2': 8, 922 'pbes1_sha1_des': 8, 923 'pbes1_sha1_rc2': 8, 924 'pkcs12_sha1_rc4_128': 16, 925 'pkcs12_sha1_rc4_40': 5, 926 'pkcs12_sha1_tripledes_3key': 24, 927 'pkcs12_sha1_tripledes_2key': 16, 928 'pkcs12_sha1_rc2_128': 16, 929 'pkcs12_sha1_rc2_40': 5, 930 }[encryption_algo] 931 932 raise ValueError(unwrap( 933 ''' 934 Unrecognized encryption algorithm "%s" 935 ''', 936 encryption_algo 937 )) 938 939 @property 940 def encryption_mode(self): 941 """ 942 Returns the name of the encryption mode to use. 943 944 :return: 945 A unicode string from one of the following: "cbc", "ecb", "ofb", 946 "cfb", "wrap", "gcm", "ccm", "wrap_pad" 947 """ 948 949 encryption_algo = self['algorithm'].native 950 951 if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']): 952 return encryption_algo[7:] 953 954 if encryption_algo[0:6] == 'pbes1_': 955 return 'cbc' 956 957 if encryption_algo[0:7] == 'pkcs12_': 958 return 'cbc' 959 960 if encryption_algo in set(['des', 'tripledes_3key', 'rc2', 'rc5']): 961 return 'cbc' 962 963 if encryption_algo == 'pbes2': 964 return self['parameters']['encryption_scheme'].encryption_mode 965 966 raise ValueError(unwrap( 967 ''' 968 Unrecognized encryption algorithm "%s" 969 ''', 970 encryption_algo 971 )) 972 973 @property 974 def encryption_cipher(self): 975 """ 976 Returns the name of the symmetric encryption cipher to use. The key 977 length can be retrieved via the .key_length property to disabiguate 978 between different variations of TripleDES, AES, and the RC* ciphers. 979 980 :return: 981 A unicode string from one of the following: "rc2", "rc5", "des", 982 "tripledes", "aes" 983 """ 984 985 encryption_algo = self['algorithm'].native 986 987 if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']): 988 return 'aes' 989 990 if encryption_algo in set(['des', 'rc2', 'rc5']): 991 return encryption_algo 992 993 if encryption_algo == 'tripledes_3key': 994 return 'tripledes' 995 996 if encryption_algo == 'pbes2': 997 return self['parameters']['encryption_scheme'].encryption_cipher 998 999 if encryption_algo.find('.') == -1: 1000 return { 1001 'pbes1_md2_des': 'des', 1002 'pbes1_md5_des': 'des', 1003 'pbes1_md2_rc2': 'rc2', 1004 'pbes1_md5_rc2': 'rc2', 1005 'pbes1_sha1_des': 'des', 1006 'pbes1_sha1_rc2': 'rc2', 1007 'pkcs12_sha1_rc4_128': 'rc4', 1008 'pkcs12_sha1_rc4_40': 'rc4', 1009 'pkcs12_sha1_tripledes_3key': 'tripledes', 1010 'pkcs12_sha1_tripledes_2key': 'tripledes', 1011 'pkcs12_sha1_rc2_128': 'rc2', 1012 'pkcs12_sha1_rc2_40': 'rc2', 1013 }[encryption_algo] 1014 1015 raise ValueError(unwrap( 1016 ''' 1017 Unrecognized encryption algorithm "%s" 1018 ''', 1019 encryption_algo 1020 )) 1021 1022 @property 1023 def encryption_block_size(self): 1024 """ 1025 Returns the block size of the encryption cipher, in bytes. 1026 1027 :return: 1028 An integer that is the block size in bytes 1029 """ 1030 1031 encryption_algo = self['algorithm'].native 1032 1033 if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']): 1034 return 16 1035 1036 cipher_map = { 1037 'des': 8, 1038 'tripledes_3key': 8, 1039 'rc2': 8, 1040 } 1041 if encryption_algo in cipher_map: 1042 return cipher_map[encryption_algo] 1043 1044 if encryption_algo == 'rc5': 1045 return self['parameters'].parsed['block_size_in_bits'].native / 8 1046 1047 if encryption_algo == 'pbes2': 1048 return self['parameters']['encryption_scheme'].encryption_block_size 1049 1050 if encryption_algo.find('.') == -1: 1051 return { 1052 'pbes1_md2_des': 8, 1053 'pbes1_md5_des': 8, 1054 'pbes1_md2_rc2': 8, 1055 'pbes1_md5_rc2': 8, 1056 'pbes1_sha1_des': 8, 1057 'pbes1_sha1_rc2': 8, 1058 'pkcs12_sha1_rc4_128': 0, 1059 'pkcs12_sha1_rc4_40': 0, 1060 'pkcs12_sha1_tripledes_3key': 8, 1061 'pkcs12_sha1_tripledes_2key': 8, 1062 'pkcs12_sha1_rc2_128': 8, 1063 'pkcs12_sha1_rc2_40': 8, 1064 }[encryption_algo] 1065 1066 raise ValueError(unwrap( 1067 ''' 1068 Unrecognized encryption algorithm "%s" 1069 ''', 1070 encryption_algo 1071 )) 1072 1073 @property 1074 def encryption_iv(self): 1075 """ 1076 Returns the byte string of the initialization vector for the encryption 1077 scheme. Only the PBES2 stores the IV in the params. For PBES1, the IV 1078 is derived from the KDF and this property will return None. 1079 1080 :return: 1081 A byte string or None 1082 """ 1083 1084 encryption_algo = self['algorithm'].native 1085 1086 if encryption_algo in set(['rc2', 'rc5']): 1087 return self['parameters'].parsed['iv'].native 1088 1089 # For DES/Triple DES and AES the IV is the entirety of the parameters 1090 octet_string_iv_oids = set([ 1091 'des', 1092 'tripledes_3key', 1093 'aes128_cbc', 1094 'aes192_cbc', 1095 'aes256_cbc', 1096 'aes128_ofb', 1097 'aes192_ofb', 1098 'aes256_ofb', 1099 ]) 1100 if encryption_algo in octet_string_iv_oids: 1101 return self['parameters'].native 1102 1103 if encryption_algo == 'pbes2': 1104 return self['parameters']['encryption_scheme'].encryption_iv 1105 1106 # All of the PBES1 algos use their KDF to create the IV. For the pbkdf1, 1107 # the KDF is told to generate a key that is an extra 8 bytes long, and 1108 # that is used for the IV. For the PKCS#12 KDF, it is called with an id 1109 # of 2 to generate the IV. In either case, we can't return the IV 1110 # without knowing the user's password. 1111 if encryption_algo.find('.') == -1: 1112 return None 1113 1114 raise ValueError(unwrap( 1115 ''' 1116 Unrecognized encryption algorithm "%s" 1117 ''', 1118 encryption_algo 1119 )) 1120 1121 1122class Pbes2Params(Sequence): 1123 _fields = [ 1124 ('key_derivation_func', KdfAlgorithm), 1125 ('encryption_scheme', EncryptionAlgorithm), 1126 ] 1127 1128 1129class Pbmac1Params(Sequence): 1130 _fields = [ 1131 ('key_derivation_func', KdfAlgorithm), 1132 ('message_auth_scheme', HmacAlgorithm), 1133 ] 1134 1135 1136class Pkcs5MacId(ObjectIdentifier): 1137 _map = { 1138 '1.2.840.113549.1.5.14': 'pbmac1', 1139 } 1140 1141 1142class Pkcs5MacAlgorithm(Sequence): 1143 _fields = [ 1144 ('algorithm', Pkcs5MacId), 1145 ('parameters', Any), 1146 ] 1147 1148 _oid_pair = ('algorithm', 'parameters') 1149 _oid_specs = { 1150 'pbmac1': Pbmac1Params, 1151 } 1152 1153 1154EncryptionAlgorithm._oid_specs['pbes2'] = Pbes2Params 1155 1156 1157class AnyAlgorithmId(ObjectIdentifier): 1158 _map = {} 1159 1160 def _setup(self): 1161 _map = self.__class__._map 1162 for other_cls in (EncryptionAlgorithmId, SignedDigestAlgorithmId, DigestAlgorithmId): 1163 for oid, name in other_cls._map.items(): 1164 _map[oid] = name 1165 1166 1167class AnyAlgorithmIdentifier(_ForceNullParameters, Sequence): 1168 _fields = [ 1169 ('algorithm', AnyAlgorithmId), 1170 ('parameters', Any, {'optional': True}), 1171 ] 1172 1173 _oid_pair = ('algorithm', 'parameters') 1174 _oid_specs = {} 1175 1176 def _setup(self): 1177 Sequence._setup(self) 1178 specs = self.__class__._oid_specs 1179 for other_cls in (EncryptionAlgorithm, SignedDigestAlgorithm): 1180 for oid, spec in other_cls._oid_specs.items(): 1181 specs[oid] = spec 1182