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 1190