1#
2#  PublicKey/_PBES.py : Password-Based Encryption functions
3#
4# ===================================================================
5#
6# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
7# All rights reserved.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions
11# are met:
12#
13# 1. Redistributions of source code must retain the above copyright
14#    notice, this list of conditions and the following disclaimer.
15# 2. Redistributions in binary form must reproduce the above copyright
16#    notice, this list of conditions and the following disclaimer in
17#    the documentation and/or other materials provided with the
18#    distribution.
19#
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31# POSSIBILITY OF SUCH DAMAGE.
32# ===================================================================
33
34from Crypto import Random
35from Crypto.Util.asn1 import (
36            DerSequence, DerOctetString,
37            DerObjectId, DerInteger,
38            )
39
40from Crypto.Util.Padding import pad, unpad
41from Crypto.Hash import MD5, SHA1, SHA224, SHA256, SHA384, SHA512
42from Crypto.Cipher import DES, ARC2, DES3, AES
43from Crypto.Protocol.KDF import PBKDF1, PBKDF2, scrypt
44
45_OID_PBE_WITH_MD5_AND_DES_CBC = "1.2.840.113549.1.5.3"
46_OID_PBE_WITH_MD5_AND_RC2_CBC = "1.2.840.113549.1.5.6"
47_OID_PBE_WITH_SHA1_AND_DES_CBC = "1.2.840.113549.1.5.10"
48_OID_PBE_WITH_SHA1_AND_RC2_CBC = "1.2.840.113549.1.5.11"
49
50_OID_PBES2 = "1.2.840.113549.1.5.13"
51
52_OID_PBKDF2 = "1.2.840.113549.1.5.12"
53_OID_SCRYPT = "1.3.6.1.4.1.11591.4.11"
54
55_OID_HMAC_SHA1 = "1.2.840.113549.2.7"
56_OID_HMAC_SHA224 = "1.2.840.113549.2.8"
57_OID_HMAC_SHA256 = "1.2.840.113549.2.9"
58_OID_HMAC_SHA384 = "1.2.840.113549.2.10"
59_OID_HMAC_SHA512 = "1.2.840.113549.2.11"
60
61_OID_DES_EDE3_CBC = "1.2.840.113549.3.7"
62_OID_AES128_CBC = "2.16.840.1.101.3.4.1.2"
63_OID_AES192_CBC = "2.16.840.1.101.3.4.1.22"
64_OID_AES256_CBC = "2.16.840.1.101.3.4.1.42"
65
66
67class PbesError(ValueError):
68    pass
69
70# These are the ASN.1 definitions used by the PBES1/2 logic:
71#
72# EncryptedPrivateKeyInfo ::= SEQUENCE {
73#   encryptionAlgorithm  EncryptionAlgorithmIdentifier,
74#   encryptedData        EncryptedData
75# }
76#
77# EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
78#
79# EncryptedData ::= OCTET STRING
80#
81# AlgorithmIdentifier  ::=  SEQUENCE  {
82#       algorithm   OBJECT IDENTIFIER,
83#       parameters  ANY DEFINED BY algorithm OPTIONAL
84# }
85#
86# PBEParameter ::= SEQUENCE {
87#       salt OCTET STRING (SIZE(8)),
88#       iterationCount INTEGER
89# }
90#
91# PBES2-params ::= SEQUENCE {
92#       keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
93#       encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
94# }
95#
96# PBKDF2-params ::= SEQUENCE {
97#   salt CHOICE {
98#       specified OCTET STRING,
99#       otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
100#       },
101#   iterationCount INTEGER (1..MAX),
102#   keyLength INTEGER (1..MAX) OPTIONAL,
103#   prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1
104#   }
105#
106# scrypt-params ::= SEQUENCE {
107#       salt OCTET STRING,
108#       costParameter INTEGER (1..MAX),
109#       blockSize INTEGER (1..MAX),
110#       parallelizationParameter INTEGER (1..MAX),
111#       keyLength INTEGER (1..MAX) OPTIONAL
112#   }
113
114class PBES1(object):
115    """Deprecated encryption scheme with password-based key derivation
116    (originally defined in PKCS#5 v1.5, but still present in `v2.0`__).
117
118    .. __: http://www.ietf.org/rfc/rfc2898.txt
119    """
120
121    @staticmethod
122    def decrypt(data, passphrase):
123        """Decrypt a piece of data using a passphrase and *PBES1*.
124
125        The algorithm to use is automatically detected.
126
127        :Parameters:
128          data : byte string
129            The piece of data to decrypt.
130          passphrase : byte string
131            The passphrase to use for decrypting the data.
132        :Returns:
133          The decrypted data, as a binary string.
134        """
135
136        enc_private_key_info = DerSequence().decode(data)
137        encrypted_algorithm = DerSequence().decode(enc_private_key_info[0])
138        encrypted_data = DerOctetString().decode(enc_private_key_info[1]).payload
139
140        pbe_oid = DerObjectId().decode(encrypted_algorithm[0]).value
141        cipher_params = {}
142        if pbe_oid == _OID_PBE_WITH_MD5_AND_DES_CBC:
143            # PBE_MD5_DES_CBC
144            hashmod = MD5
145            ciphermod = DES
146        elif pbe_oid == _OID_PBE_WITH_MD5_AND_RC2_CBC:
147            # PBE_MD5_RC2_CBC
148            hashmod = MD5
149            ciphermod = ARC2
150            cipher_params['effective_keylen'] = 64
151        elif pbe_oid == _OID_PBE_WITH_SHA1_AND_DES_CBC:
152            # PBE_SHA1_DES_CBC
153            hashmod = SHA1
154            ciphermod = DES
155        elif pbe_oid == _OID_PBE_WITH_SHA1_AND_RC2_CBC:
156            # PBE_SHA1_RC2_CBC
157            hashmod = SHA1
158            ciphermod = ARC2
159            cipher_params['effective_keylen'] = 64
160        else:
161            raise PbesError("Unknown OID for PBES1")
162
163        pbe_params = DerSequence().decode(encrypted_algorithm[1], nr_elements=2)
164        salt = DerOctetString().decode(pbe_params[0]).payload
165        iterations = pbe_params[1]
166
167        key_iv = PBKDF1(passphrase, salt, 16, iterations, hashmod)
168        key, iv = key_iv[:8], key_iv[8:]
169
170        cipher = ciphermod.new(key, ciphermod.MODE_CBC, iv, **cipher_params)
171        pt = cipher.decrypt(encrypted_data)
172        return unpad(pt, cipher.block_size)
173
174
175class PBES2(object):
176    """Encryption scheme with password-based key derivation
177    (defined in `PKCS#5 v2.0`__).
178
179    .. __: http://www.ietf.org/rfc/rfc2898.txt."""
180
181    @staticmethod
182    def encrypt(data, passphrase, protection, prot_params=None, randfunc=None):
183        """Encrypt a piece of data using a passphrase and *PBES2*.
184
185        :Parameters:
186          data : byte string
187            The piece of data to encrypt.
188          passphrase : byte string
189            The passphrase to use for encrypting the data.
190          protection : string
191            The identifier of the encryption algorithm to use.
192            The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'.
193          prot_params : dictionary
194            Parameters of the protection algorithm.
195
196            +------------------+-----------------------------------------------+
197            | Key              | Description                                   |
198            +==================+===============================================+
199            | iteration_count  | The KDF algorithm is repeated several times to|
200            |                  | slow down brute force attacks on passwords    |
201            |                  | (called *N* or CPU/memory cost in scrypt).    |
202            |                  |                                               |
203            |                  | The default value for PBKDF2 is 1 000.        |
204            |                  | The default value for scrypt is 16 384.       |
205            +------------------+-----------------------------------------------+
206            | salt_size        | Salt is used to thwart dictionary and rainbow |
207            |                  | attacks on passwords. The default value is 8  |
208            |                  | bytes.                                        |
209            +------------------+-----------------------------------------------+
210            | block_size       | *(scrypt only)* Memory-cost (r). The default  |
211            |                  | value is 8.                                   |
212            +------------------+-----------------------------------------------+
213            | parallelization  | *(scrypt only)* CPU-cost (p). The default     |
214            |                  | value is 1.                                   |
215            +------------------+-----------------------------------------------+
216
217
218          randfunc : callable
219            Random number generation function; it should accept
220            a single integer N and return a string of random data,
221            N bytes long. If not specified, a new RNG will be
222            instantiated from ``Crypto.Random``.
223
224        :Returns:
225          The encrypted data, as a binary string.
226        """
227
228        if prot_params is None:
229            prot_params = {}
230
231        if randfunc is None:
232            randfunc = Random.new().read
233
234        if protection == 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC':
235            key_size = 24
236            module = DES3
237            cipher_mode = DES3.MODE_CBC
238            enc_oid = _OID_DES_EDE3_CBC
239        elif protection in ('PBKDF2WithHMAC-SHA1AndAES128-CBC',
240                'scryptAndAES128-CBC'):
241            key_size = 16
242            module = AES
243            cipher_mode = AES.MODE_CBC
244            enc_oid = _OID_AES128_CBC
245        elif protection in ('PBKDF2WithHMAC-SHA1AndAES192-CBC',
246                'scryptAndAES192-CBC'):
247            key_size = 24
248            module = AES
249            cipher_mode = AES.MODE_CBC
250            enc_oid = _OID_AES192_CBC
251        elif protection in ('PBKDF2WithHMAC-SHA1AndAES256-CBC',
252                'scryptAndAES256-CBC'):
253            key_size = 32
254            module = AES
255            cipher_mode = AES.MODE_CBC
256            enc_oid = _OID_AES256_CBC
257        else:
258            raise ValueError("Unknown PBES2 mode")
259
260        # Get random data
261        iv = randfunc(module.block_size)
262        salt = randfunc(prot_params.get("salt_size", 8))
263
264        # Derive key from password
265        if protection.startswith('PBKDF2'):
266            count = prot_params.get("iteration_count", 1000)
267            key = PBKDF2(passphrase, salt, key_size, count)
268            kdf_info = DerSequence([
269                    DerObjectId(_OID_PBKDF2),   # PBKDF2
270                    DerSequence([
271                        DerOctetString(salt),
272                        DerInteger(count)
273                    ])
274            ])
275        else:
276            # It must be scrypt
277            count = prot_params.get("iteration_count", 16384)
278            scrypt_r = prot_params.get('block_size', 8)
279            scrypt_p = prot_params.get('parallelization', 1)
280            key = scrypt(passphrase, salt, key_size,
281                         count, scrypt_r, scrypt_p)
282            kdf_info = DerSequence([
283                    DerObjectId(_OID_SCRYPT),  # scrypt
284                    DerSequence([
285                        DerOctetString(salt),
286                        DerInteger(count),
287                        DerInteger(scrypt_r),
288                        DerInteger(scrypt_p)
289                    ])
290            ])
291
292        # Create cipher and use it
293        cipher = module.new(key, cipher_mode, iv)
294        encrypted_data = cipher.encrypt(pad(data, cipher.block_size))
295        enc_info = DerSequence([
296                DerObjectId(enc_oid),
297                DerOctetString(iv)
298        ])
299
300        # Result
301        enc_private_key_info = DerSequence([
302            # encryptionAlgorithm
303            DerSequence([
304                DerObjectId(_OID_PBES2),
305                DerSequence([
306                    kdf_info,
307                    enc_info
308                ]),
309            ]),
310            DerOctetString(encrypted_data)
311        ])
312        return enc_private_key_info.encode()
313
314    @staticmethod
315    def decrypt(data, passphrase):
316        """Decrypt a piece of data using a passphrase and *PBES2*.
317
318        The algorithm to use is automatically detected.
319
320        :Parameters:
321          data : byte string
322            The piece of data to decrypt.
323          passphrase : byte string
324            The passphrase to use for decrypting the data.
325        :Returns:
326          The decrypted data, as a binary string.
327        """
328
329        enc_private_key_info = DerSequence().decode(data, nr_elements=2)
330        enc_algo = DerSequence().decode(enc_private_key_info[0])
331        encrypted_data = DerOctetString().decode(enc_private_key_info[1]).payload
332
333        pbe_oid = DerObjectId().decode(enc_algo[0]).value
334        if pbe_oid != _OID_PBES2:
335            raise PbesError("Not a PBES2 object")
336
337        pbes2_params = DerSequence().decode(enc_algo[1], nr_elements=2)
338
339        ### Key Derivation Function selection
340        kdf_info = DerSequence().decode(pbes2_params[0], nr_elements=2)
341        kdf_oid = DerObjectId().decode(kdf_info[0]).value
342
343        kdf_key_length = None
344
345        # We only support PBKDF2 or scrypt
346        if kdf_oid == _OID_PBKDF2:
347
348            pbkdf2_params = DerSequence().decode(kdf_info[1], nr_elements=(2, 3, 4))
349            salt = DerOctetString().decode(pbkdf2_params[0]).payload
350            iteration_count = pbkdf2_params[1]
351
352            left = len(pbkdf2_params) - 2
353            idx = 2
354
355            if left > 0:
356                try:
357                    kdf_key_length = pbkdf2_params[idx] - 0
358                    left -= 1
359                    idx += 1
360                except TypeError:
361                    pass
362
363            # Default is HMAC-SHA1
364            pbkdf2_prf_oid = "1.2.840.113549.2.7"
365            if left > 0:
366                pbkdf2_prf_algo_id = DerSequence().decode(pbkdf2_params[idx])
367                pbkdf2_prf_oid = DerObjectId().decode(pbkdf2_prf_algo_id[0]).value
368
369        elif kdf_oid == _OID_SCRYPT:
370
371            scrypt_params = DerSequence().decode(kdf_info[1], nr_elements=(4, 5))
372            salt = DerOctetString().decode(scrypt_params[0]).payload
373            iteration_count, scrypt_r, scrypt_p = [scrypt_params[x]
374                                                   for x in (1, 2, 3)]
375            if len(scrypt_params) > 4:
376                kdf_key_length = scrypt_params[4]
377            else:
378                kdf_key_length = None
379        else:
380            raise PbesError("Unsupported PBES2 KDF")
381
382        ### Cipher selection
383        enc_info = DerSequence().decode(pbes2_params[1])
384        enc_oid = DerObjectId().decode(enc_info[0]).value
385
386        if enc_oid == _OID_DES_EDE3_CBC:
387            # DES_EDE3_CBC
388            ciphermod = DES3
389            key_size = 24
390        elif enc_oid == _OID_AES128_CBC:
391            # AES128_CBC
392            ciphermod = AES
393            key_size = 16
394        elif enc_oid == _OID_AES192_CBC:
395            # AES192_CBC
396            ciphermod = AES
397            key_size = 24
398        elif enc_oid == _OID_AES256_CBC:
399            # AES256_CBC
400            ciphermod = AES
401            key_size = 32
402        else:
403            raise PbesError("Unsupported PBES2 cipher")
404
405        if kdf_key_length and kdf_key_length != key_size:
406            raise PbesError("Mismatch between PBES2 KDF parameters"
407                            " and selected cipher")
408
409        IV = DerOctetString().decode(enc_info[1]).payload
410
411        # Create cipher
412        if kdf_oid == _OID_PBKDF2:
413            if pbkdf2_prf_oid == _OID_HMAC_SHA1:
414                hmac_hash_module = SHA1
415            elif pbkdf2_prf_oid == _OID_HMAC_SHA224:
416                hmac_hash_module = SHA224
417            elif pbkdf2_prf_oid == _OID_HMAC_SHA256:
418                hmac_hash_module = SHA256
419            elif pbkdf2_prf_oid == _OID_HMAC_SHA384:
420                hmac_hash_module = SHA384
421            elif pbkdf2_prf_oid == _OID_HMAC_SHA512:
422                hmac_hash_module = SHA512
423            else:
424                raise PbesError("Unsupported HMAC %s" % pbkdf2_prf_oid)
425
426            key = PBKDF2(passphrase, salt, key_size, iteration_count,
427                         hmac_hash_module=hmac_hash_module)
428        else:
429            key = scrypt(passphrase, salt, key_size, iteration_count,
430                         scrypt_r, scrypt_p)
431        cipher = ciphermod.new(key, ciphermod.MODE_CBC, IV)
432
433        # Decrypt data
434        pt = cipher.decrypt(encrypted_data)
435        return unpad(pt, cipher.block_size)
436