1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189 |
- # coding: utf-8
- """
- ASN.1 type classes for various algorithms using in various aspects of public
- key cryptography. Exports the following items:
- - AlgorithmIdentifier()
- - AnyAlgorithmIdentifier()
- - DigestAlgorithm()
- - DigestInfo()
- - DSASignature()
- - EncryptionAlgorithm()
- - HmacAlgorithm()
- - KdfAlgorithm()
- - Pkcs5MacAlgorithm()
- - SignedDigestAlgorithm()
- Other type classes are defined that help compose the types listed above.
- """
- from __future__ import unicode_literals, division, absolute_import, print_function
- from ._errors import unwrap
- from ._int import fill_width
- from .util import int_from_bytes, int_to_bytes
- from .core import (
- Any,
- Choice,
- Integer,
- Null,
- ObjectIdentifier,
- OctetString,
- Sequence,
- Void,
- )
- # Structures and OIDs in this file are pulled from
- # https://tools.ietf.org/html/rfc3279, https://tools.ietf.org/html/rfc4055,
- # https://tools.ietf.org/html/rfc5758, https://tools.ietf.org/html/rfc7292,
- # http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf
- class AlgorithmIdentifier(Sequence):
- _fields = [
- ('algorithm', ObjectIdentifier),
- ('parameters', Any, {'optional': True}),
- ]
- class _ForceNullParameters(object):
- """
- Various structures based on AlgorithmIdentifier require that the parameters
- field be core.Null() for certain OIDs. This mixin ensures that happens.
- """
- # The following attribute, plus the parameters spec callback and custom
- # __setitem__ are all to handle a situation where parameters should not be
- # optional and must be Null for certain OIDs. More info at
- # https://tools.ietf.org/html/rfc4055#page-15 and
- # https://tools.ietf.org/html/rfc4055#section-2.1
- _null_algos = set([
- '1.2.840.113549.1.1.1', # rsassa_pkcs1v15 / rsaes_pkcs1v15 / rsa
- '1.2.840.113549.1.1.11', # sha256_rsa
- '1.2.840.113549.1.1.12', # sha384_rsa
- '1.2.840.113549.1.1.13', # sha512_rsa
- '1.2.840.113549.1.1.14', # sha224_rsa
- '1.3.14.3.2.26', # sha1
- '2.16.840.1.101.3.4.2.4', # sha224
- '2.16.840.1.101.3.4.2.1', # sha256
- '2.16.840.1.101.3.4.2.2', # sha384
- '2.16.840.1.101.3.4.2.3', # sha512
- ])
- def _parameters_spec(self):
- if self._oid_pair == ('algorithm', 'parameters'):
- algo = self['algorithm'].native
- if algo in self._oid_specs:
- return self._oid_specs[algo]
- if self['algorithm'].dotted in self._null_algos:
- return Null
- return None
- _spec_callbacks = {
- 'parameters': _parameters_spec
- }
- # We have to override this since the spec callback uses the value of
- # algorithm to determine the parameter spec, however default values are
- # assigned before setting a field, so a default value can't be based on
- # another field value (unless it is a default also). Thus we have to
- # manually check to see if the algorithm was set and parameters is unset,
- # and then fix the value as appropriate.
- def __setitem__(self, key, value):
- res = super(_ForceNullParameters, self).__setitem__(key, value)
- if key != 'algorithm':
- return res
- if self['algorithm'].dotted not in self._null_algos:
- return res
- if self['parameters'].__class__ != Void:
- return res
- self['parameters'] = Null()
- return res
- class HmacAlgorithmId(ObjectIdentifier):
- _map = {
- '1.3.14.3.2.10': 'des_mac',
- '1.2.840.113549.2.7': 'sha1',
- '1.2.840.113549.2.8': 'sha224',
- '1.2.840.113549.2.9': 'sha256',
- '1.2.840.113549.2.10': 'sha384',
- '1.2.840.113549.2.11': 'sha512',
- '1.2.840.113549.2.12': 'sha512_224',
- '1.2.840.113549.2.13': 'sha512_256',
- '2.16.840.1.101.3.4.2.13': 'sha3_224',
- '2.16.840.1.101.3.4.2.14': 'sha3_256',
- '2.16.840.1.101.3.4.2.15': 'sha3_384',
- '2.16.840.1.101.3.4.2.16': 'sha3_512',
- }
- class HmacAlgorithm(Sequence):
- _fields = [
- ('algorithm', HmacAlgorithmId),
- ('parameters', Any, {'optional': True}),
- ]
- class DigestAlgorithmId(ObjectIdentifier):
- _map = {
- '1.2.840.113549.2.2': 'md2',
- '1.2.840.113549.2.5': 'md5',
- '1.3.14.3.2.26': 'sha1',
- '2.16.840.1.101.3.4.2.4': 'sha224',
- '2.16.840.1.101.3.4.2.1': 'sha256',
- '2.16.840.1.101.3.4.2.2': 'sha384',
- '2.16.840.1.101.3.4.2.3': 'sha512',
- '2.16.840.1.101.3.4.2.5': 'sha512_224',
- '2.16.840.1.101.3.4.2.6': 'sha512_256',
- '2.16.840.1.101.3.4.2.7': 'sha3_224',
- '2.16.840.1.101.3.4.2.8': 'sha3_256',
- '2.16.840.1.101.3.4.2.9': 'sha3_384',
- '2.16.840.1.101.3.4.2.10': 'sha3_512',
- '2.16.840.1.101.3.4.2.11': 'shake128',
- '2.16.840.1.101.3.4.2.12': 'shake256',
- '2.16.840.1.101.3.4.2.17': 'shake128_len',
- '2.16.840.1.101.3.4.2.18': 'shake256_len',
- }
- class DigestAlgorithm(_ForceNullParameters, Sequence):
- _fields = [
- ('algorithm', DigestAlgorithmId),
- ('parameters', Any, {'optional': True}),
- ]
- # This structure is what is signed with a SignedDigestAlgorithm
- class DigestInfo(Sequence):
- _fields = [
- ('digest_algorithm', DigestAlgorithm),
- ('digest', OctetString),
- ]
- class MaskGenAlgorithmId(ObjectIdentifier):
- _map = {
- '1.2.840.113549.1.1.8': 'mgf1',
- }
- class MaskGenAlgorithm(Sequence):
- _fields = [
- ('algorithm', MaskGenAlgorithmId),
- ('parameters', Any, {'optional': True}),
- ]
- _oid_pair = ('algorithm', 'parameters')
- _oid_specs = {
- 'mgf1': DigestAlgorithm
- }
- class TrailerField(Integer):
- _map = {
- 1: 'trailer_field_bc',
- }
- class RSASSAPSSParams(Sequence):
- _fields = [
- (
- 'hash_algorithm',
- DigestAlgorithm,
- {
- 'explicit': 0,
- 'default': {'algorithm': 'sha1'},
- }
- ),
- (
- 'mask_gen_algorithm',
- MaskGenAlgorithm,
- {
- 'explicit': 1,
- 'default': {
- 'algorithm': 'mgf1',
- 'parameters': {'algorithm': 'sha1'},
- },
- }
- ),
- (
- 'salt_length',
- Integer,
- {
- 'explicit': 2,
- 'default': 20,
- }
- ),
- (
- 'trailer_field',
- TrailerField,
- {
- 'explicit': 3,
- 'default': 'trailer_field_bc',
- }
- ),
- ]
- class SignedDigestAlgorithmId(ObjectIdentifier):
- _map = {
- '1.3.14.3.2.3': 'md5_rsa',
- '1.3.14.3.2.29': 'sha1_rsa',
- '1.3.14.7.2.3.1': 'md2_rsa',
- '1.2.840.113549.1.1.2': 'md2_rsa',
- '1.2.840.113549.1.1.4': 'md5_rsa',
- '1.2.840.113549.1.1.5': 'sha1_rsa',
- '1.2.840.113549.1.1.14': 'sha224_rsa',
- '1.2.840.113549.1.1.11': 'sha256_rsa',
- '1.2.840.113549.1.1.12': 'sha384_rsa',
- '1.2.840.113549.1.1.13': 'sha512_rsa',
- '1.2.840.113549.1.1.10': 'rsassa_pss',
- '1.2.840.10040.4.3': 'sha1_dsa',
- '1.3.14.3.2.13': 'sha1_dsa',
- '1.3.14.3.2.27': 'sha1_dsa',
- '2.16.840.1.101.3.4.3.1': 'sha224_dsa',
- '2.16.840.1.101.3.4.3.2': 'sha256_dsa',
- '1.2.840.10045.4.1': 'sha1_ecdsa',
- '1.2.840.10045.4.3.1': 'sha224_ecdsa',
- '1.2.840.10045.4.3.2': 'sha256_ecdsa',
- '1.2.840.10045.4.3.3': 'sha384_ecdsa',
- '1.2.840.10045.4.3.4': 'sha512_ecdsa',
- '2.16.840.1.101.3.4.3.9': 'sha3_224_ecdsa',
- '2.16.840.1.101.3.4.3.10': 'sha3_256_ecdsa',
- '2.16.840.1.101.3.4.3.11': 'sha3_384_ecdsa',
- '2.16.840.1.101.3.4.3.12': 'sha3_512_ecdsa',
- # For when the digest is specified elsewhere in a Sequence
- '1.2.840.113549.1.1.1': 'rsassa_pkcs1v15',
- '1.2.840.10040.4.1': 'dsa',
- '1.2.840.10045.4': 'ecdsa',
- # RFC 8410 -- https://tools.ietf.org/html/rfc8410
- '1.3.101.112': 'ed25519',
- '1.3.101.113': 'ed448',
- }
- _reverse_map = {
- 'dsa': '1.2.840.10040.4.1',
- 'ecdsa': '1.2.840.10045.4',
- 'md2_rsa': '1.2.840.113549.1.1.2',
- 'md5_rsa': '1.2.840.113549.1.1.4',
- 'rsassa_pkcs1v15': '1.2.840.113549.1.1.1',
- 'rsassa_pss': '1.2.840.113549.1.1.10',
- 'sha1_dsa': '1.2.840.10040.4.3',
- 'sha1_ecdsa': '1.2.840.10045.4.1',
- 'sha1_rsa': '1.2.840.113549.1.1.5',
- 'sha224_dsa': '2.16.840.1.101.3.4.3.1',
- 'sha224_ecdsa': '1.2.840.10045.4.3.1',
- 'sha224_rsa': '1.2.840.113549.1.1.14',
- 'sha256_dsa': '2.16.840.1.101.3.4.3.2',
- 'sha256_ecdsa': '1.2.840.10045.4.3.2',
- 'sha256_rsa': '1.2.840.113549.1.1.11',
- 'sha384_ecdsa': '1.2.840.10045.4.3.3',
- 'sha384_rsa': '1.2.840.113549.1.1.12',
- 'sha512_ecdsa': '1.2.840.10045.4.3.4',
- 'sha512_rsa': '1.2.840.113549.1.1.13',
- 'sha3_224_ecdsa': '2.16.840.1.101.3.4.3.9',
- 'sha3_256_ecdsa': '2.16.840.1.101.3.4.3.10',
- 'sha3_384_ecdsa': '2.16.840.1.101.3.4.3.11',
- 'sha3_512_ecdsa': '2.16.840.1.101.3.4.3.12',
- 'ed25519': '1.3.101.112',
- 'ed448': '1.3.101.113',
- }
- class SignedDigestAlgorithm(_ForceNullParameters, Sequence):
- _fields = [
- ('algorithm', SignedDigestAlgorithmId),
- ('parameters', Any, {'optional': True}),
- ]
- _oid_pair = ('algorithm', 'parameters')
- _oid_specs = {
- 'rsassa_pss': RSASSAPSSParams,
- }
- @property
- def signature_algo(self):
- """
- :return:
- A unicode string of "rsassa_pkcs1v15", "rsassa_pss", "dsa",
- "ecdsa", "ed25519" or "ed448"
- """
- algorithm = self['algorithm'].native
- algo_map = {
- 'md2_rsa': 'rsassa_pkcs1v15',
- 'md5_rsa': 'rsassa_pkcs1v15',
- 'sha1_rsa': 'rsassa_pkcs1v15',
- 'sha224_rsa': 'rsassa_pkcs1v15',
- 'sha256_rsa': 'rsassa_pkcs1v15',
- 'sha384_rsa': 'rsassa_pkcs1v15',
- 'sha512_rsa': 'rsassa_pkcs1v15',
- 'rsassa_pkcs1v15': 'rsassa_pkcs1v15',
- 'rsassa_pss': 'rsassa_pss',
- 'sha1_dsa': 'dsa',
- 'sha224_dsa': 'dsa',
- 'sha256_dsa': 'dsa',
- 'dsa': 'dsa',
- 'sha1_ecdsa': 'ecdsa',
- 'sha224_ecdsa': 'ecdsa',
- 'sha256_ecdsa': 'ecdsa',
- 'sha384_ecdsa': 'ecdsa',
- 'sha512_ecdsa': 'ecdsa',
- 'sha3_224_ecdsa': 'ecdsa',
- 'sha3_256_ecdsa': 'ecdsa',
- 'sha3_384_ecdsa': 'ecdsa',
- 'sha3_512_ecdsa': 'ecdsa',
- 'ecdsa': 'ecdsa',
- 'ed25519': 'ed25519',
- 'ed448': 'ed448',
- }
- if algorithm in algo_map:
- return algo_map[algorithm]
- raise ValueError(unwrap(
- '''
- Signature algorithm not known for %s
- ''',
- algorithm
- ))
- @property
- def hash_algo(self):
- """
- :return:
- A unicode string of "md2", "md5", "sha1", "sha224", "sha256",
- "sha384", "sha512", "sha512_224", "sha512_256" or "shake256"
- """
- algorithm = self['algorithm'].native
- algo_map = {
- 'md2_rsa': 'md2',
- 'md5_rsa': 'md5',
- 'sha1_rsa': 'sha1',
- 'sha224_rsa': 'sha224',
- 'sha256_rsa': 'sha256',
- 'sha384_rsa': 'sha384',
- 'sha512_rsa': 'sha512',
- 'sha1_dsa': 'sha1',
- 'sha224_dsa': 'sha224',
- 'sha256_dsa': 'sha256',
- 'sha1_ecdsa': 'sha1',
- 'sha224_ecdsa': 'sha224',
- 'sha256_ecdsa': 'sha256',
- 'sha384_ecdsa': 'sha384',
- 'sha512_ecdsa': 'sha512',
- 'ed25519': 'sha512',
- 'ed448': 'shake256',
- }
- if algorithm in algo_map:
- return algo_map[algorithm]
- if algorithm == 'rsassa_pss':
- return self['parameters']['hash_algorithm']['algorithm'].native
- raise ValueError(unwrap(
- '''
- Hash algorithm not known for %s
- ''',
- algorithm
- ))
- class Pbkdf2Salt(Choice):
- _alternatives = [
- ('specified', OctetString),
- ('other_source', AlgorithmIdentifier),
- ]
- class Pbkdf2Params(Sequence):
- _fields = [
- ('salt', Pbkdf2Salt),
- ('iteration_count', Integer),
- ('key_length', Integer, {'optional': True}),
- ('prf', HmacAlgorithm, {'default': {'algorithm': 'sha1'}}),
- ]
- class KdfAlgorithmId(ObjectIdentifier):
- _map = {
- '1.2.840.113549.1.5.12': 'pbkdf2'
- }
- class KdfAlgorithm(Sequence):
- _fields = [
- ('algorithm', KdfAlgorithmId),
- ('parameters', Any, {'optional': True}),
- ]
- _oid_pair = ('algorithm', 'parameters')
- _oid_specs = {
- 'pbkdf2': Pbkdf2Params
- }
- class DHParameters(Sequence):
- """
- Original Name: DHParameter
- Source: ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-3.asc section 9
- """
- _fields = [
- ('p', Integer),
- ('g', Integer),
- ('private_value_length', Integer, {'optional': True}),
- ]
- class KeyExchangeAlgorithmId(ObjectIdentifier):
- _map = {
- '1.2.840.113549.1.3.1': 'dh',
- }
- class KeyExchangeAlgorithm(Sequence):
- _fields = [
- ('algorithm', KeyExchangeAlgorithmId),
- ('parameters', Any, {'optional': True}),
- ]
- _oid_pair = ('algorithm', 'parameters')
- _oid_specs = {
- 'dh': DHParameters,
- }
- class Rc2Params(Sequence):
- _fields = [
- ('rc2_parameter_version', Integer, {'optional': True}),
- ('iv', OctetString),
- ]
- class Rc5ParamVersion(Integer):
- _map = {
- 16: 'v1-0'
- }
- class Rc5Params(Sequence):
- _fields = [
- ('version', Rc5ParamVersion),
- ('rounds', Integer),
- ('block_size_in_bits', Integer),
- ('iv', OctetString, {'optional': True}),
- ]
- class Pbes1Params(Sequence):
- _fields = [
- ('salt', OctetString),
- ('iterations', Integer),
- ]
- class CcmParams(Sequence):
- # https://tools.ietf.org/html/rfc5084
- # aes_ICVlen: 4 | 6 | 8 | 10 | 12 | 14 | 16
- _fields = [
- ('aes_nonce', OctetString),
- ('aes_icvlen', Integer),
- ]
- class PSourceAlgorithmId(ObjectIdentifier):
- _map = {
- '1.2.840.113549.1.1.9': 'p_specified',
- }
- class PSourceAlgorithm(Sequence):
- _fields = [
- ('algorithm', PSourceAlgorithmId),
- ('parameters', Any, {'optional': True}),
- ]
- _oid_pair = ('algorithm', 'parameters')
- _oid_specs = {
- 'p_specified': OctetString
- }
- class RSAESOAEPParams(Sequence):
- _fields = [
- (
- 'hash_algorithm',
- DigestAlgorithm,
- {
- 'explicit': 0,
- 'default': {'algorithm': 'sha1'}
- }
- ),
- (
- 'mask_gen_algorithm',
- MaskGenAlgorithm,
- {
- 'explicit': 1,
- 'default': {
- 'algorithm': 'mgf1',
- 'parameters': {'algorithm': 'sha1'}
- }
- }
- ),
- (
- 'p_source_algorithm',
- PSourceAlgorithm,
- {
- 'explicit': 2,
- 'default': {
- 'algorithm': 'p_specified',
- 'parameters': b''
- }
- }
- ),
- ]
- class DSASignature(Sequence):
- """
- An ASN.1 class for translating between the OS crypto library's
- representation of an (EC)DSA signature and the ASN.1 structure that is part
- of various RFCs.
- Original Name: DSS-Sig-Value
- Source: https://tools.ietf.org/html/rfc3279#section-2.2.2
- """
- _fields = [
- ('r', Integer),
- ('s', Integer),
- ]
- @classmethod
- def from_p1363(cls, data):
- """
- Reads a signature from a byte string encoding accordint to IEEE P1363,
- which is used by Microsoft's BCryptSignHash() function.
- :param data:
- A byte string from BCryptSignHash()
- :return:
- A DSASignature object
- """
- r = int_from_bytes(data[0:len(data) // 2])
- s = int_from_bytes(data[len(data) // 2:])
- return cls({'r': r, 's': s})
- def to_p1363(self):
- """
- Dumps a signature to a byte string compatible with Microsoft's
- BCryptVerifySignature() function.
- :return:
- A byte string compatible with BCryptVerifySignature()
- """
- r_bytes = int_to_bytes(self['r'].native)
- s_bytes = int_to_bytes(self['s'].native)
- int_byte_length = max(len(r_bytes), len(s_bytes))
- r_bytes = fill_width(r_bytes, int_byte_length)
- s_bytes = fill_width(s_bytes, int_byte_length)
- return r_bytes + s_bytes
- class EncryptionAlgorithmId(ObjectIdentifier):
- _map = {
- '1.3.14.3.2.7': 'des',
- '1.2.840.113549.3.7': 'tripledes_3key',
- '1.2.840.113549.3.2': 'rc2',
- '1.2.840.113549.3.4': 'rc4',
- '1.2.840.113549.3.9': 'rc5',
- # From http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html#AES
- '2.16.840.1.101.3.4.1.1': 'aes128_ecb',
- '2.16.840.1.101.3.4.1.2': 'aes128_cbc',
- '2.16.840.1.101.3.4.1.3': 'aes128_ofb',
- '2.16.840.1.101.3.4.1.4': 'aes128_cfb',
- '2.16.840.1.101.3.4.1.5': 'aes128_wrap',
- '2.16.840.1.101.3.4.1.6': 'aes128_gcm',
- '2.16.840.1.101.3.4.1.7': 'aes128_ccm',
- '2.16.840.1.101.3.4.1.8': 'aes128_wrap_pad',
- '2.16.840.1.101.3.4.1.21': 'aes192_ecb',
- '2.16.840.1.101.3.4.1.22': 'aes192_cbc',
- '2.16.840.1.101.3.4.1.23': 'aes192_ofb',
- '2.16.840.1.101.3.4.1.24': 'aes192_cfb',
- '2.16.840.1.101.3.4.1.25': 'aes192_wrap',
- '2.16.840.1.101.3.4.1.26': 'aes192_gcm',
- '2.16.840.1.101.3.4.1.27': 'aes192_ccm',
- '2.16.840.1.101.3.4.1.28': 'aes192_wrap_pad',
- '2.16.840.1.101.3.4.1.41': 'aes256_ecb',
- '2.16.840.1.101.3.4.1.42': 'aes256_cbc',
- '2.16.840.1.101.3.4.1.43': 'aes256_ofb',
- '2.16.840.1.101.3.4.1.44': 'aes256_cfb',
- '2.16.840.1.101.3.4.1.45': 'aes256_wrap',
- '2.16.840.1.101.3.4.1.46': 'aes256_gcm',
- '2.16.840.1.101.3.4.1.47': 'aes256_ccm',
- '2.16.840.1.101.3.4.1.48': 'aes256_wrap_pad',
- # From PKCS#5
- '1.2.840.113549.1.5.13': 'pbes2',
- '1.2.840.113549.1.5.1': 'pbes1_md2_des',
- '1.2.840.113549.1.5.3': 'pbes1_md5_des',
- '1.2.840.113549.1.5.4': 'pbes1_md2_rc2',
- '1.2.840.113549.1.5.6': 'pbes1_md5_rc2',
- '1.2.840.113549.1.5.10': 'pbes1_sha1_des',
- '1.2.840.113549.1.5.11': 'pbes1_sha1_rc2',
- # From PKCS#12
- '1.2.840.113549.1.12.1.1': 'pkcs12_sha1_rc4_128',
- '1.2.840.113549.1.12.1.2': 'pkcs12_sha1_rc4_40',
- '1.2.840.113549.1.12.1.3': 'pkcs12_sha1_tripledes_3key',
- '1.2.840.113549.1.12.1.4': 'pkcs12_sha1_tripledes_2key',
- '1.2.840.113549.1.12.1.5': 'pkcs12_sha1_rc2_128',
- '1.2.840.113549.1.12.1.6': 'pkcs12_sha1_rc2_40',
- # PKCS#1 v2.2
- '1.2.840.113549.1.1.1': 'rsaes_pkcs1v15',
- '1.2.840.113549.1.1.7': 'rsaes_oaep',
- }
- class EncryptionAlgorithm(_ForceNullParameters, Sequence):
- _fields = [
- ('algorithm', EncryptionAlgorithmId),
- ('parameters', Any, {'optional': True}),
- ]
- _oid_pair = ('algorithm', 'parameters')
- _oid_specs = {
- 'des': OctetString,
- 'tripledes_3key': OctetString,
- 'rc2': Rc2Params,
- 'rc5': Rc5Params,
- 'aes128_cbc': OctetString,
- 'aes192_cbc': OctetString,
- 'aes256_cbc': OctetString,
- 'aes128_ofb': OctetString,
- 'aes192_ofb': OctetString,
- 'aes256_ofb': OctetString,
- # From RFC5084
- 'aes128_ccm': CcmParams,
- 'aes192_ccm': CcmParams,
- 'aes256_ccm': CcmParams,
- # From PKCS#5
- 'pbes1_md2_des': Pbes1Params,
- 'pbes1_md5_des': Pbes1Params,
- 'pbes1_md2_rc2': Pbes1Params,
- 'pbes1_md5_rc2': Pbes1Params,
- 'pbes1_sha1_des': Pbes1Params,
- 'pbes1_sha1_rc2': Pbes1Params,
- # From PKCS#12
- 'pkcs12_sha1_rc4_128': Pbes1Params,
- 'pkcs12_sha1_rc4_40': Pbes1Params,
- 'pkcs12_sha1_tripledes_3key': Pbes1Params,
- 'pkcs12_sha1_tripledes_2key': Pbes1Params,
- 'pkcs12_sha1_rc2_128': Pbes1Params,
- 'pkcs12_sha1_rc2_40': Pbes1Params,
- # PKCS#1 v2.2
- 'rsaes_oaep': RSAESOAEPParams,
- }
- @property
- def kdf(self):
- """
- Returns the name of the key derivation function to use.
- :return:
- A unicode from of one of the following: "pbkdf1", "pbkdf2",
- "pkcs12_kdf"
- """
- encryption_algo = self['algorithm'].native
- if encryption_algo == 'pbes2':
- return self['parameters']['key_derivation_func']['algorithm'].native
- if encryption_algo.find('.') == -1:
- if encryption_algo.find('_') != -1:
- encryption_algo, _ = encryption_algo.split('_', 1)
- if encryption_algo == 'pbes1':
- return 'pbkdf1'
- if encryption_algo == 'pkcs12':
- return 'pkcs12_kdf'
- raise ValueError(unwrap(
- '''
- Encryption algorithm "%s" does not have a registered key
- derivation function
- ''',
- encryption_algo
- ))
- raise ValueError(unwrap(
- '''
- Unrecognized encryption algorithm "%s", can not determine key
- derivation function
- ''',
- encryption_algo
- ))
- @property
- def kdf_hmac(self):
- """
- Returns the HMAC algorithm to use with the KDF.
- :return:
- A unicode string of one of the following: "md2", "md5", "sha1",
- "sha224", "sha256", "sha384", "sha512"
- """
- encryption_algo = self['algorithm'].native
- if encryption_algo == 'pbes2':
- return self['parameters']['key_derivation_func']['parameters']['prf']['algorithm'].native
- if encryption_algo.find('.') == -1:
- if encryption_algo.find('_') != -1:
- _, hmac_algo, _ = encryption_algo.split('_', 2)
- return hmac_algo
- raise ValueError(unwrap(
- '''
- Encryption algorithm "%s" does not have a registered key
- derivation function
- ''',
- encryption_algo
- ))
- raise ValueError(unwrap(
- '''
- Unrecognized encryption algorithm "%s", can not determine key
- derivation hmac algorithm
- ''',
- encryption_algo
- ))
- @property
- def kdf_salt(self):
- """
- Returns the byte string to use as the salt for the KDF.
- :return:
- A byte string
- """
- encryption_algo = self['algorithm'].native
- if encryption_algo == 'pbes2':
- salt = self['parameters']['key_derivation_func']['parameters']['salt']
- if salt.name == 'other_source':
- raise ValueError(unwrap(
- '''
- Can not determine key derivation salt - the
- reserved-for-future-use other source salt choice was
- specified in the PBKDF2 params structure
- '''
- ))
- return salt.native
- if encryption_algo.find('.') == -1:
- if encryption_algo.find('_') != -1:
- return self['parameters']['salt'].native
- raise ValueError(unwrap(
- '''
- Encryption algorithm "%s" does not have a registered key
- derivation function
- ''',
- encryption_algo
- ))
- raise ValueError(unwrap(
- '''
- Unrecognized encryption algorithm "%s", can not determine key
- derivation salt
- ''',
- encryption_algo
- ))
- @property
- def kdf_iterations(self):
- """
- Returns the number of iterations that should be run via the KDF.
- :return:
- An integer
- """
- encryption_algo = self['algorithm'].native
- if encryption_algo == 'pbes2':
- return self['parameters']['key_derivation_func']['parameters']['iteration_count'].native
- if encryption_algo.find('.') == -1:
- if encryption_algo.find('_') != -1:
- return self['parameters']['iterations'].native
- raise ValueError(unwrap(
- '''
- Encryption algorithm "%s" does not have a registered key
- derivation function
- ''',
- encryption_algo
- ))
- raise ValueError(unwrap(
- '''
- Unrecognized encryption algorithm "%s", can not determine key
- derivation iterations
- ''',
- encryption_algo
- ))
- @property
- def key_length(self):
- """
- Returns the key length to pass to the cipher/kdf. The PKCS#5 spec does
- not specify a way to store the RC5 key length, however this tends not
- to be a problem since OpenSSL does not support RC5 in PKCS#8 and OS X
- does not provide an RC5 cipher for use in the Security Transforms
- library.
- :raises:
- ValueError - when the key length can not be determined
- :return:
- An integer representing the length in bytes
- """
- encryption_algo = self['algorithm'].native
- if encryption_algo[0:3] == 'aes':
- return {
- 'aes128_': 16,
- 'aes192_': 24,
- 'aes256_': 32,
- }[encryption_algo[0:7]]
- cipher_lengths = {
- 'des': 8,
- 'tripledes_3key': 24,
- }
- if encryption_algo in cipher_lengths:
- return cipher_lengths[encryption_algo]
- if encryption_algo == 'rc2':
- rc2_parameter_version = self['parameters']['rc2_parameter_version'].native
- # See page 24 of
- # http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf
- encoded_key_bits_map = {
- 160: 5, # 40-bit
- 120: 8, # 64-bit
- 58: 16, # 128-bit
- }
- if rc2_parameter_version in encoded_key_bits_map:
- return encoded_key_bits_map[rc2_parameter_version]
- if rc2_parameter_version >= 256:
- return rc2_parameter_version
- if rc2_parameter_version is None:
- return 4 # 32-bit default
- raise ValueError(unwrap(
- '''
- Invalid RC2 parameter version found in EncryptionAlgorithm
- parameters
- '''
- ))
- if encryption_algo == 'pbes2':
- key_length = self['parameters']['key_derivation_func']['parameters']['key_length'].native
- if key_length is not None:
- return key_length
- # If the KDF params don't specify the key size, we can infer it from
- # the encryption scheme for all schemes except for RC5. However, in
- # practical terms, neither OpenSSL or OS X support RC5 for PKCS#8
- # so it is unlikely to be an issue that is run into.
- return self['parameters']['encryption_scheme'].key_length
- if encryption_algo.find('.') == -1:
- return {
- 'pbes1_md2_des': 8,
- 'pbes1_md5_des': 8,
- 'pbes1_md2_rc2': 8,
- 'pbes1_md5_rc2': 8,
- 'pbes1_sha1_des': 8,
- 'pbes1_sha1_rc2': 8,
- 'pkcs12_sha1_rc4_128': 16,
- 'pkcs12_sha1_rc4_40': 5,
- 'pkcs12_sha1_tripledes_3key': 24,
- 'pkcs12_sha1_tripledes_2key': 16,
- 'pkcs12_sha1_rc2_128': 16,
- 'pkcs12_sha1_rc2_40': 5,
- }[encryption_algo]
- raise ValueError(unwrap(
- '''
- Unrecognized encryption algorithm "%s"
- ''',
- encryption_algo
- ))
- @property
- def encryption_mode(self):
- """
- Returns the name of the encryption mode to use.
- :return:
- A unicode string from one of the following: "cbc", "ecb", "ofb",
- "cfb", "wrap", "gcm", "ccm", "wrap_pad"
- """
- encryption_algo = self['algorithm'].native
- if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']):
- return encryption_algo[7:]
- if encryption_algo[0:6] == 'pbes1_':
- return 'cbc'
- if encryption_algo[0:7] == 'pkcs12_':
- return 'cbc'
- if encryption_algo in set(['des', 'tripledes_3key', 'rc2', 'rc5']):
- return 'cbc'
- if encryption_algo == 'pbes2':
- return self['parameters']['encryption_scheme'].encryption_mode
- raise ValueError(unwrap(
- '''
- Unrecognized encryption algorithm "%s"
- ''',
- encryption_algo
- ))
- @property
- def encryption_cipher(self):
- """
- Returns the name of the symmetric encryption cipher to use. The key
- length can be retrieved via the .key_length property to disabiguate
- between different variations of TripleDES, AES, and the RC* ciphers.
- :return:
- A unicode string from one of the following: "rc2", "rc5", "des",
- "tripledes", "aes"
- """
- encryption_algo = self['algorithm'].native
- if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']):
- return 'aes'
- if encryption_algo in set(['des', 'rc2', 'rc5']):
- return encryption_algo
- if encryption_algo == 'tripledes_3key':
- return 'tripledes'
- if encryption_algo == 'pbes2':
- return self['parameters']['encryption_scheme'].encryption_cipher
- if encryption_algo.find('.') == -1:
- return {
- 'pbes1_md2_des': 'des',
- 'pbes1_md5_des': 'des',
- 'pbes1_md2_rc2': 'rc2',
- 'pbes1_md5_rc2': 'rc2',
- 'pbes1_sha1_des': 'des',
- 'pbes1_sha1_rc2': 'rc2',
- 'pkcs12_sha1_rc4_128': 'rc4',
- 'pkcs12_sha1_rc4_40': 'rc4',
- 'pkcs12_sha1_tripledes_3key': 'tripledes',
- 'pkcs12_sha1_tripledes_2key': 'tripledes',
- 'pkcs12_sha1_rc2_128': 'rc2',
- 'pkcs12_sha1_rc2_40': 'rc2',
- }[encryption_algo]
- raise ValueError(unwrap(
- '''
- Unrecognized encryption algorithm "%s"
- ''',
- encryption_algo
- ))
- @property
- def encryption_block_size(self):
- """
- Returns the block size of the encryption cipher, in bytes.
- :return:
- An integer that is the block size in bytes
- """
- encryption_algo = self['algorithm'].native
- if encryption_algo[0:7] in set(['aes128_', 'aes192_', 'aes256_']):
- return 16
- cipher_map = {
- 'des': 8,
- 'tripledes_3key': 8,
- 'rc2': 8,
- }
- if encryption_algo in cipher_map:
- return cipher_map[encryption_algo]
- if encryption_algo == 'rc5':
- return self['parameters']['block_size_in_bits'].native // 8
- if encryption_algo == 'pbes2':
- return self['parameters']['encryption_scheme'].encryption_block_size
- if encryption_algo.find('.') == -1:
- return {
- 'pbes1_md2_des': 8,
- 'pbes1_md5_des': 8,
- 'pbes1_md2_rc2': 8,
- 'pbes1_md5_rc2': 8,
- 'pbes1_sha1_des': 8,
- 'pbes1_sha1_rc2': 8,
- 'pkcs12_sha1_rc4_128': 0,
- 'pkcs12_sha1_rc4_40': 0,
- 'pkcs12_sha1_tripledes_3key': 8,
- 'pkcs12_sha1_tripledes_2key': 8,
- 'pkcs12_sha1_rc2_128': 8,
- 'pkcs12_sha1_rc2_40': 8,
- }[encryption_algo]
- raise ValueError(unwrap(
- '''
- Unrecognized encryption algorithm "%s"
- ''',
- encryption_algo
- ))
- @property
- def encryption_iv(self):
- """
- Returns the byte string of the initialization vector for the encryption
- scheme. Only the PBES2 stores the IV in the params. For PBES1, the IV
- is derived from the KDF and this property will return None.
- :return:
- A byte string or None
- """
- encryption_algo = self['algorithm'].native
- if encryption_algo in set(['rc2', 'rc5']):
- return self['parameters']['iv'].native
- # For DES/Triple DES and AES the IV is the entirety of the parameters
- octet_string_iv_oids = set([
- 'des',
- 'tripledes_3key',
- 'aes128_cbc',
- 'aes192_cbc',
- 'aes256_cbc',
- 'aes128_ofb',
- 'aes192_ofb',
- 'aes256_ofb',
- ])
- if encryption_algo in octet_string_iv_oids:
- return self['parameters'].native
- if encryption_algo == 'pbes2':
- return self['parameters']['encryption_scheme'].encryption_iv
- # All of the PBES1 algos use their KDF to create the IV. For the pbkdf1,
- # the KDF is told to generate a key that is an extra 8 bytes long, and
- # that is used for the IV. For the PKCS#12 KDF, it is called with an id
- # of 2 to generate the IV. In either case, we can't return the IV
- # without knowing the user's password.
- if encryption_algo.find('.') == -1:
- return None
- raise ValueError(unwrap(
- '''
- Unrecognized encryption algorithm "%s"
- ''',
- encryption_algo
- ))
- class Pbes2Params(Sequence):
- _fields = [
- ('key_derivation_func', KdfAlgorithm),
- ('encryption_scheme', EncryptionAlgorithm),
- ]
- class Pbmac1Params(Sequence):
- _fields = [
- ('key_derivation_func', KdfAlgorithm),
- ('message_auth_scheme', HmacAlgorithm),
- ]
- class Pkcs5MacId(ObjectIdentifier):
- _map = {
- '1.2.840.113549.1.5.14': 'pbmac1',
- }
- class Pkcs5MacAlgorithm(Sequence):
- _fields = [
- ('algorithm', Pkcs5MacId),
- ('parameters', Any),
- ]
- _oid_pair = ('algorithm', 'parameters')
- _oid_specs = {
- 'pbmac1': Pbmac1Params,
- }
- EncryptionAlgorithm._oid_specs['pbes2'] = Pbes2Params
- class AnyAlgorithmId(ObjectIdentifier):
- _map = {}
- def _setup(self):
- _map = self.__class__._map
- for other_cls in (EncryptionAlgorithmId, SignedDigestAlgorithmId, DigestAlgorithmId):
- for oid, name in other_cls._map.items():
- _map[oid] = name
- class AnyAlgorithmIdentifier(_ForceNullParameters, Sequence):
- _fields = [
- ('algorithm', AnyAlgorithmId),
- ('parameters', Any, {'optional': True}),
- ]
- _oid_pair = ('algorithm', 'parameters')
- _oid_specs = {}
- def _setup(self):
- Sequence._setup(self)
- specs = self.__class__._oid_specs
- for other_cls in (EncryptionAlgorithm, SignedDigestAlgorithm):
- for oid, spec in other_cls._oid_specs.items():
- specs[oid] = spec
|