Folded PKCS#5 algos into asn1crypto.algos
diff --git a/asn1crypto/algos.py b/asn1crypto/algos.py
index fb801e2..eb32a60 100644
--- a/asn1crypto/algos.py
+++ b/asn1crypto/algos.py
@@ -2,11 +2,13 @@
from __future__ import unicode_literals
from __future__ import absolute_import
-from .core import Any, Integer, ObjectIdentifier, OctetString, Sequence
+from .core import Any, Choice, Integer, ObjectIdentifier, OctetString, Sequence
-# OID in this file are pulled from https://tools.ietf.org/html/rfc3279,
-# https://tools.ietf.org/html/rfc4055 and https://tools.ietf.org/html/rfc5758
+# 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 = [
@@ -100,6 +102,39 @@
]
+class Pbkdf2Salt(Choice):
+ _fields = [
+ ('specified', OctetString),
+ ('other_source', AlgorithmIdentifier),
+ ]
+
+
+class Pbkdf2Params(Sequence):
+ _fields = [
+ ('salt', Pbkdf2Salt),
+ ('iteration_count', Integer),
+ ('key_length', Integer, {'optional': True}),
+ ('prf', HmacAlgorithm, {'optional': True}),
+ ]
+
+
+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 Rc2Params(Sequence):
_fields = [
('rc2_parameter_version', Integer, {'optional': True}),
@@ -122,6 +157,13 @@
]
+class Pbes1Params(Sequence):
+ _fields = [
+ ('salt', OctetString),
+ ('iterations', Integer),
+ ]
+
+
class EncryptionAlgorithmId(ObjectIdentifier):
_map = {
'1.3.14.3.2.7': 'des',
@@ -131,6 +173,21 @@
'2.16.840.1.101.3.4.1.2': 'aes128',
'2.16.840.1.101.3.4.1.22': 'aes192',
'2.16.840.1.101.3.4.1.42': 'aes256',
+ # 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',
}
@@ -149,12 +206,126 @@
'aes128': OctetString,
'aes192': OctetString,
'aes256': OctetString,
+ # 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,
}
@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'].parsed['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('Encryption algorithm "%s" does not have a registered key derivation function' % encryption_algo)
+
+ raise ValueError('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'].parsed['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('Encryption algorithm "%s" does not have a registered key derivation function' % encryption_algo)
+
+ raise ValueError('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'].parsed['key_derivation_func']['algorithm']['salt']
+
+ if salt.name == 'other_source':
+ raise ValueError('Can not determine key derivation salt - the reversed-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('Encryption algorithm "%s" does not have a registered key derivation function' % encryption_algo)
+
+ raise ValueError('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']['algorithm']['iteration_count'].native
+
+ if encryption_algo.find('.') == -1:
+ if encryption_algo.find('_') != -1:
+ return self['parameters']['iterations'].native
+
+ raise ValueError('Encryption algorithm "%s" does not have a registered key derivation function' % encryption_algo)
+
+ raise ValueError('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. The PKCS#5 spec does
+ 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
@@ -167,7 +338,7 @@
An integer representing the length in bytes
"""
- cipher = self['algorithm'].native
+ encryption_algo = self['algorithm'].native
cipher_lengths = {
'des': 8,
@@ -177,10 +348,10 @@
'aes256': 32,
}
- if cipher in cipher_lengths:
- return cipher_lengths[cipher]
+ if encryption_algo in cipher_lengths:
+ return cipher_lengths[encryption_algo]
- if cipher == 'rc2':
+ if encryption_algo == 'rc2':
rc2_params = self['parameters'].parsed['encryption_scheme']['parameters'].parsed
rc2_parameter_version = rc2_params['rc2_parameter_version'].native
@@ -202,7 +373,35 @@
raise ValueError('Invalid RC2 parameter version found in EncryptionAlgorithm parameters')
- raise ValueError('Unable to determine the key length for the encryption scheme "%s"' % cipher)
+ if encryption_algo == 'pbes2':
+ key_length = self['parameters']['key_derivation_func']['algorithm']['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('Unrecognized encryption algorithm "%s"' % encryption_algo)
@property
def encryption_cipher(self):
@@ -215,7 +414,7 @@
A unicode string from one of the following: "rc2", "rc5", "des", "tripledes", "aes"
"""
- cipher = self['algorithm'].native
+ encryption_algo = self['algorithm'].native
cipher_map = {
'des': 'des',
@@ -226,10 +425,29 @@
'rc2': 'rc2',
'rc5': 'rc5',
}
- if cipher in cipher_map:
- return cipher_map[cipher]
+ if encryption_algo in cipher_map:
+ return cipher_map[encryption_algo]
- raise ValueError('Unrecognized encryption cipher "%s"' % cipher)
+ 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('Unrecognized encryption algorithm "%s"' % encryption_algo)
@property
def encryption_block_size(self):
@@ -240,7 +458,7 @@
An integer that is the block size in bytes
"""
- cipher = self['algorithm'].native
+ encryption_algo = self['algorithm'].native
cipher_map = {
'des': 8,
@@ -250,13 +468,32 @@
'aes256': 16,
'rc2': 8,
}
- if cipher in cipher_map:
- return cipher_map[cipher]
+ if encryption_algo in cipher_map:
+ return cipher_map[encryption_algo]
- if cipher == 'rc5':
+ if encryption_algo == 'rc5':
return self['parameters'].parsed['block_size_in_bits'].native / 8
- raise ValueError('Unrecognized encryption cipher "%s", can not determine block size' % cipher)
+ 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('Unrecognized encryption algorithm "%s"' % encryption_algo)
@property
def encryption_iv(self):
@@ -269,13 +506,59 @@
A byte string or None
"""
- cipher = self['algorithm'].native
+ encryption_algo = self['algorithm'].native
- if cipher == 'rc2' or cipher == 'rc5':
+ if encryption_algo in ('rc2', 'rc5'):
return self['parameters'].parsed['iv'].native
# For DES/Triple DES and AES the IV is the entirety of the parameters
- if cipher.find('.') == -1:
+ if encryption_algo in ('des', 'tripledes_3key', 'aes128', 'aes192', 'aes256'):
return self['parameters'].native
- raise ValueError('Unrecognized encryption cipher "%s", can not determine initialization vector' % cipher)
+ 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('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 #pylint: disable=W0212
diff --git a/asn1crypto/cms.py b/asn1crypto/cms.py
index 0c2c42f..85fe9d0 100644
--- a/asn1crypto/cms.py
+++ b/asn1crypto/cms.py
@@ -9,8 +9,10 @@
from .algos import (
DigestAlgorithm,
- SignedDigestAlgorithm,
+ EncryptionAlgorithm,
HmacAlgorithm,
+ KdfAlgorithm,
+ SignedDigestAlgorithm,
)
from .core import (
Any,
@@ -29,7 +31,6 @@
from .crl import CertificateList
from .keys import PublicKeyInfo
from .ocsp import OCSPResponse
-from .pkcs5 import KdfAlgorithm, Pkcs5EncryptionAlgorithm
from .x509 import Attributes, Certificate, Extensions, GeneralNames, Name
@@ -521,7 +522,7 @@
class EncryptedContentInfo(Sequence):
_fields = [
('content_type', ContentType),
- ('content_encryption_algorithm', Pkcs5EncryptionAlgorithm),
+ ('content_encryption_algorithm', EncryptionAlgorithm),
('encrypted_content', OctetString, {'tag_type': 'implicit', 'tag': 0, 'optional': True}),
]
diff --git a/asn1crypto/keys.py b/asn1crypto/keys.py
index 76ba948..9632b33 100644
--- a/asn1crypto/keys.py
+++ b/asn1crypto/keys.py
@@ -5,7 +5,7 @@
import hashlib
from decimal import localcontext
-from .algos import DigestAlgorithm
+from .algos import DigestAlgorithm, EncryptionAlgorithm
from .core import (
Any,
Choice,
@@ -20,7 +20,6 @@
SequenceOf,
SetOf,
)
-from .pkcs5 import Pkcs5EncryptionAlgorithm
try:
# Python 2
@@ -497,7 +496,7 @@
"""
_fields = [
- ('encryption_algorithm', Pkcs5EncryptionAlgorithm),
+ ('encryption_algorithm', EncryptionAlgorithm),
('encrypted_data', OctetString),
]
diff --git a/asn1crypto/pkcs5.py b/asn1crypto/pkcs5.py
deleted file mode 100644
index 1043567..0000000
--- a/asn1crypto/pkcs5.py
+++ /dev/null
@@ -1,354 +0,0 @@
-# coding: utf-8
-from __future__ import unicode_literals
-from __future__ import absolute_import
-
-from .algos import AlgorithmIdentifier, EncryptionAlgorithm, HmacAlgorithm
-from .core import Any, Choice, Integer, ObjectIdentifier, OctetString, Sequence
-
-
-# The structures in this file are taken from
-# http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf
-# with extra OIDs from https://tools.ietf.org/html/rfc7292 (PKCS#12)
-
-
-class Pbes1Params(Sequence):
- _fields = [
- ('salt', OctetString),
- ('iterations', Integer),
- ]
-
-
-class Pbkdf2Salt(Choice):
- _fields = [
- ('specified', OctetString),
- ('other_source', AlgorithmIdentifier),
- ]
-
-
-class Pbkdf2Params(Sequence):
- _fields = [
- ('salt', Pbkdf2Salt),
- ('iteration_count', Integer),
- ('key_length', Integer, {'optional': True}),
- ('prf', HmacAlgorithm, {'optional': True}),
- ]
-
-
-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 Pbes2Params(Sequence):
- _fields = [
- ('key_derivation_func', KdfAlgorithm),
- ('encryption_scheme', EncryptionAlgorithm),
- ]
-
-
-class Pkcs5EncryptionId(ObjectIdentifier):
- _map = {
- '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',
- '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',
- }
-
-
-class Pkcs5EncryptionAlgorithm(Sequence):
- _fields = [
- ('algorithm', Pkcs5EncryptionId),
- ('parameters', Any),
- ]
-
- _oid_pair = ('algorithm', 'parameters')
- _oid_specs = {
- 'pbes2': Pbes2Params,
- 'pbes1_md2_des': Pbes1Params,
- 'pbes1_md5_des': Pbes1Params,
- 'pbes1_md2_rc2': Pbes1Params,
- 'pbes1_md5_rc2': Pbes1Params,
- 'pbes1_sha1_des': Pbes1Params,
- 'pbes1_sha1_rc2': Pbes1Params,
- '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,
- }
-
- @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'].parsed['key_derivation_func']['algorithm'].native
-
- if encryption_algo.find('.') == -1:
- encryption_algo, _ = self['algorithm'].native.split('_', 1)
-
- if encryption_algo == 'pbes1':
- return 'pbkdf1'
-
- if encryption_algo == 'pkcs12':
- return 'pkcs12_kdf'
-
- raise ValueError('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'].parsed['key_derivation_func']['parameters']['prf']['algorithm'].native
-
- if encryption_algo.find('.') == -1:
- _, hmac_algo, _ = self['algorithm'].native.split('_', 2)
- return hmac_algo
-
- raise ValueError('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'].parsed['key_derivation_func']['algorithm']['salt']
-
- if salt.name == 'other_source':
- raise ValueError('Can not determine key derivation salt - the reversed-for-future-use other source salt choice was specified in the PBKDF2 params structure')
-
- return salt.native
-
- if encryption_algo.find('.') == -1:
- return self['parameters']['salt'].native
-
- raise ValueError('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']['algorithm']['iteration_count'].native
-
- if encryption_algo.find('.') == -1:
- return self['parameters']['iterations'].native
-
- raise ValueError('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 KDF/cipher. 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 == 'pbes2':
- key_length = self['parameters']['key_derivation_func']['algorithm']['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('Unrecognized encryption algorithm "%s", can not determine key derivation function key length' % 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", "rc4", "rc5", "des", "tripledes", "aes"
- """
-
- encryption_algo = self['algorithm'].native
-
- 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('Unrecognized encryption algorithm "%s", can not determine encryption cipher' % encryption_algo)
-
- @property
- def encryption_block_size(self):
- """
- Returns the block size of the encryption cipher, in bytes. For RC4, a
- stream cipher, 0 is returned.
-
- :return:
- An integer that is the block size in bytes
- """
-
- encryption_algo = self['algorithm'].native
-
- 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('Unrecognized encryption algorithm "%s", can not determine encryption block size' % 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 == '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('Unrecognized encryption algorithm "%s", can not determine initialization vector' % encryption_algo)
-
-
-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,
- }
diff --git a/docs/readme.md b/docs/readme.md
index b987385..7dc216f 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -14,7 +14,6 @@
- [X509 certificates](../asn1crypto/x509.py), `asn1crypto.x509`
- [Certificate revocation lists (CRLs)](../asn1crypto/crl.py), `asn1crypto.crl`
- [Online certificate status protocol (OCSP)](../asn1crypto/ocsp.py), `asn1crypto.ocsp`
- - [Private key encryption (PKCS#5)](../asn1crypto/pkcs5.py), `asn1crypto.pkcs5`
- [Private key/certificate containers (PKCS#12)](../asn1crypto/pkcs12.py), `asn1crypto.pkcs12`
- [Cryptographic message syntax (CMS, PKCS#7)](../asn1crypto/cms.py), `asn1crypto.cms`
- [Time stamp protocol (TSP)](../asn1crypto/tsp.py), `asn1crypto.tsp`
diff --git a/lint.py b/lint.py
index bead1e8..557f0b9 100644
--- a/lint.py
+++ b/lint.py
@@ -21,7 +21,6 @@
'ocsp.py',
'pdf.py',
'pkcs12.py',
- 'pkcs5.py',
'teletex_codec.py',
'tsa.py',
'x509.py',
diff --git a/readme.md b/readme.md
index c9336e9..2c9df2b 100644
--- a/readme.md
+++ b/readme.md
@@ -14,7 +14,7 @@
| PKCS#1 v2.1 (RSA keys) | [`asn1crypto.keys`](asn1crypto/keys.py) | [RFC3447](https://tools.ietf.org/html/rfc3447) |
| DSA keys | [`asn1crypto.keys`](asn1crypto/keys.py) | [RFC3279](https://tools.ietf.org/html/rfc3279) |
| Elliptic curve keys | [`asn1crypto.keys`](asn1crypto/keys.py) | [SECG SEC1 V2](http://www.secg.org/sec1-v2.pdf) |
-| PKCS#5 v2.1 | [`asn1crypto.pkcs5`](asn1crypto/pkcs5.py) | [PKCS#5 v2.1](http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf) |
+| PKCS#5 v2.1 | [`asn1crypto.algos`](asn1crypto/algos.py) | [PKCS#5 v2.1](http://www.emc.com/collateral/white-papers/h11302-pkcs5v2-1-password-based-cryptography-standard-wp.pdf) |
| CMS (and PKCS#7) | [`asn1crypto.cms`](asn1crypto/cms.py) | [RFC5652](https://tools.ietf.org/html/rfc5652), [RFC2315](https://tools.ietf.org/html/rfc2315) |
| TSP | [`asn1crypto.tsp`](asn1crypto/tsp.py) | [RFC3161](https://tools.ietf.org/html/rfc3161) |
| PDF signatures | [`asn1crypto.pdf`](asn1crypto/pdf.py) | [PDF 1.7](http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf) |
@@ -54,7 +54,6 @@
- [X509 certificates](asn1crypto/x509.py), `asn1crypto.x509`
- [Certificate revocation lists (CRLs)](asn1crypto/crl.py), `asn1crypto.crl`
- [Online certificate status protocol (OCSP)](asn1crypto/ocsp.py), `asn1crypto.ocsp`
- - [Private key encryption (PKCS#5)](asn1crypto/pkcs5.py), `asn1crypto.pkcs5`
- [Private key/certificate containers (PKCS#12)](asn1crypto/pkcs12.py), `asn1crypto.pkcs12`
- [Cryptographic message syntax (CMS, PKCS#7)](asn1crypto/cms.py), `asn1crypto.cms`
- [Time stamp protocol (TSP)](asn1crypto/tsp.py), `asn1crypto.tsp`