1# Copyright (c) 2013-2021 by Ron Frederick <ronf@timeheart.net> and others.
2#
3# This program and the accompanying materials are made available under
4# the terms of the Eclipse Public License v2.0 which accompanies this
5# distribution and is available at:
6#
7#     http://www.eclipse.org/legal/epl-2.0/
8#
9# This program may also be made available under the following secondary
10# licenses when the conditions for such availability set forth in the
11# Eclipse Public License v2.0 are satisfied:
12#
13#    GNU General Public License, Version 2.0, or any later versions of
14#    that license
15#
16# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
17#
18# Contributors:
19#     Ron Frederick - initial implementation, API, and documentation
20
21"""Asymmetric key password based encryption functions"""
22
23import os
24
25from hashlib import md5, sha1
26
27from .asn1 import ASN1DecodeError, ObjectIdentifier, der_encode, der_decode
28from .crypto import BasicCipher, get_cipher_params, pbkdf2_hmac
29
30
31_ES1_MD5_DES    = ObjectIdentifier('1.2.840.113549.1.5.3')
32_ES1_SHA1_DES   = ObjectIdentifier('1.2.840.113549.1.5.10')
33
34_ES2            = ObjectIdentifier('1.2.840.113549.1.5.13')
35
36_P12_RC4_128    = ObjectIdentifier('1.2.840.113549.1.12.1.1')
37_P12_RC4_40     = ObjectIdentifier('1.2.840.113549.1.12.1.2')
38_P12_DES3       = ObjectIdentifier('1.2.840.113549.1.12.1.3')
39_P12_DES2       = ObjectIdentifier('1.2.840.113549.1.12.1.4')
40
41_ES2_CAST128    = ObjectIdentifier('1.2.840.113533.7.66.10')
42_ES2_DES3       = ObjectIdentifier('1.2.840.113549.3.7')
43_ES2_BF         = ObjectIdentifier('1.3.6.1.4.1.3029.1.2')
44_ES2_DES        = ObjectIdentifier('1.3.14.3.2.7')
45_ES2_AES128     = ObjectIdentifier('2.16.840.1.101.3.4.1.2')
46_ES2_AES192     = ObjectIdentifier('2.16.840.1.101.3.4.1.22')
47_ES2_AES256     = ObjectIdentifier('2.16.840.1.101.3.4.1.42')
48
49_ES2_PBKDF2     = ObjectIdentifier('1.2.840.113549.1.5.12')
50
51_ES2_SHA1       = ObjectIdentifier('1.2.840.113549.2.7')
52_ES2_SHA224     = ObjectIdentifier('1.2.840.113549.2.8')
53_ES2_SHA256     = ObjectIdentifier('1.2.840.113549.2.9')
54_ES2_SHA384     = ObjectIdentifier('1.2.840.113549.2.10')
55_ES2_SHA512     = ObjectIdentifier('1.2.840.113549.2.11')
56
57_pkcs1_cipher = {}
58_pkcs1_dek_name = {}
59
60_pkcs8_handler = {}
61_pkcs8_cipher_oid = {}
62
63_pbes2_cipher = {}
64_pbes2_cipher_oid = {}
65
66_pbes2_kdf = {}
67_pbes2_kdf_oid = {}
68
69_pbes2_prf = {}
70_pbes2_prf_oid = {}
71
72
73class KeyEncryptionError(ValueError):
74    """Key encryption error
75
76       This exception is raised by key decryption functions when the data
77       provided is not a valid encrypted private key.
78
79    """
80
81
82class _RFC1423Pad:
83    """RFC 1423 padding functions
84
85       This class implements RFC 1423 padding for encryption and
86       decryption of data by block ciphers. On encryption, the data is
87       padded by between 1 and the cipher's block size number of bytes,
88       with the padding value being equal to the length of the padding.
89
90    """
91
92    def __init__(self, cipher_name, block_size, key, iv):
93        self._cipher = BasicCipher(cipher_name, key, iv)
94        self._block_size = block_size
95
96    def encrypt(self, data):
97        """Pad data before encrypting it"""
98
99        pad = self._block_size - (len(data) % self._block_size)
100        data += pad * bytes((pad,))
101        return self._cipher.encrypt(data)
102
103    def decrypt(self, data):
104        """Remove padding from data after decrypting it"""
105
106        data = self._cipher.decrypt(data)
107
108        if data:
109            pad = data[-1]
110            if (1 <= pad <= self._block_size and
111                    data[-pad:] == pad * bytes((pad,))):
112                return data[:-pad]
113
114        raise KeyEncryptionError('Unable to decrypt key')
115
116
117def _pbkdf1(hash_alg, passphrase, salt, count, key_size):
118    """PKCS#5 v1.5 key derivation function for password-based encryption
119
120       This function implements the PKCS#5 v1.5 algorithm for deriving
121       an encryption key from a passphrase and salt.
122
123       The standard PBKDF1 function cannot generate more key bytes than
124       the hash digest size, but 3DES uses a modified form of it which
125       calls PBKDF1 recursively on the result to generate more key data.
126       Support for this is implemented here.
127
128    """
129
130    if isinstance(passphrase, str):
131        passphrase = passphrase.encode('utf-8')
132
133    key = passphrase + salt
134    for _ in range(count):
135        key = hash_alg(key).digest()
136
137    if len(key) <= key_size:
138        return key + _pbkdf1(hash_alg, key + passphrase, salt, count,
139                             key_size - len(key))
140    else:
141        return key[:key_size]
142
143
144def _pbkdf_p12(hash_alg, passphrase, salt, count, key_size, idx):
145    """PKCS#12 key derivation function for password-based encryption
146
147       This function implements the PKCS#12 algorithm for deriving an
148       encryption key from a passphrase and salt.
149
150    """
151
152    def _make_block(data, v):
153        """Make a block a multiple of v bytes long by repeating data"""
154
155        l = len(data)
156        size = ((l + v - 1) // v) * v
157        return (((size + l - 1) // l) * data)[:size]
158
159    v = hash_alg().block_size
160    D = v * bytes((idx,))
161
162    if isinstance(passphrase, str):
163        passphrase = passphrase.encode('utf-16be')
164
165    I = bytearray(_make_block(salt, v) + _make_block(passphrase + b'\0\0', v))
166
167    key = b''
168    while len(key) < key_size:
169        A = D + I
170        for i in range(count):
171            A = hash_alg(A).digest()
172
173        B = int.from_bytes(_make_block(A, v), 'big')
174        for i in range(0, len(I), v):
175            x = (int.from_bytes(I[i:i+v], 'big') + B + 1) % (1 << v*8)
176            I[i:i+v] = x.to_bytes(v, 'big')
177
178        key += A
179
180    return key[:key_size]
181
182
183def _pbes1(params, passphrase, hash_alg, cipher_name):
184    """PKCS#5 v1.5 cipher selection function for password-based encryption
185
186       This function implements the PKCS#5 v1.5 algorithm for password-based
187       encryption. It returns a cipher object which can be used to encrypt
188       or decrypt data based on the specified encryption parameters,
189       passphrase, and salt.
190
191    """
192
193    if (not isinstance(params, tuple) or len(params) != 2 or
194            not isinstance(params[0], bytes) or
195            not isinstance(params[1], int)):
196        raise KeyEncryptionError('Invalid PBES1 encryption parameters')
197
198    salt, count = params
199
200    key_size, iv_size, block_size = get_cipher_params(cipher_name)
201    key = _pbkdf1(hash_alg, passphrase, salt, count, key_size + iv_size)
202    key, iv = key[:key_size], key[key_size:]
203
204    return _RFC1423Pad(cipher_name, block_size, key, iv)
205
206
207def _pbe_p12(params, passphrase, hash_alg, cipher_name):
208    """PKCS#12 cipher selection function for password-based encryption
209
210       This function implements the PKCS#12 algorithm for password-based
211       encryption. It returns a cipher object which can be used to encrypt
212       or decrypt data based on the specified encryption parameters,
213       passphrase, and salt.
214
215    """
216
217    if (not isinstance(params, tuple) or len(params) != 2 or
218            not isinstance(params[0], bytes) or not params[0] or
219            not isinstance(params[1], int) or params[1] == 0):
220        raise KeyEncryptionError('Invalid PBES1 PKCS#12 encryption parameters')
221
222    salt, count = params
223
224    key_size, iv_size, block_size = get_cipher_params(cipher_name)
225    key = _pbkdf_p12(hash_alg, passphrase, salt, count, key_size, 1)
226
227    if block_size == 1:
228        cipher = BasicCipher(cipher_name, key, b'')
229    else:
230        iv = _pbkdf_p12(hash_alg, passphrase, salt, count, iv_size, 2)
231        cipher = _RFC1423Pad(cipher_name, block_size, key, iv)
232
233    return cipher
234
235
236def _pbes2_iv(enc_params, cipher_name, key):
237    """PKCS#5 v2.0 handler for PBES2 ciphers with an IV as a parameter
238
239       This function returns the appropriate cipher object to use for
240       PBES2 encryption for ciphers that have only an IV as an encryption
241       parameter.
242
243    """
244
245    _, iv_size, block_size = get_cipher_params(cipher_name)
246
247    if len(enc_params) != 1 or not isinstance(enc_params[0], bytes):
248        raise KeyEncryptionError('Invalid PBES2 encryption parameters')
249
250    if len(enc_params[0]) != iv_size:
251        raise KeyEncryptionError('Invalid length IV for PBES2 encryption')
252
253    return _RFC1423Pad(cipher_name, block_size, key, enc_params[0])
254
255
256def _pbes2_pbkdf2(kdf_params, passphrase, default_key_size):
257    """PKCS#5 v2.0 handler for PBKDF2 key derivation
258
259       This function parses the PBKDF2 arguments from a PKCS#8 encrypted key
260       and returns the encryption key to use for encryption.
261
262    """
263
264    if (len(kdf_params) != 1 or not isinstance(kdf_params[0], tuple) or
265            len(kdf_params[0]) < 2):
266        raise KeyEncryptionError('Invalid PBES2 key derivation parameters')
267
268    kdf_params = list(kdf_params[0])
269
270    if (not isinstance(kdf_params[0], bytes) or
271            not isinstance(kdf_params[1], int)):
272        raise KeyEncryptionError('Invalid PBES2 key derivation parameters')
273
274    salt = kdf_params.pop(0)
275    count = kdf_params.pop(0)
276
277    if kdf_params and isinstance(kdf_params[0], int):
278        key_size = kdf_params.pop(0)    # pragma: no cover, used only by RC2
279    else:
280        key_size = default_key_size
281
282    if kdf_params:
283        if (isinstance(kdf_params[0], tuple) and len(kdf_params[0]) == 2 and
284                isinstance(kdf_params[0][0], ObjectIdentifier)):
285            prf_alg = kdf_params[0][0]
286            if prf_alg in _pbes2_prf:
287                hash_name = _pbes2_prf[prf_alg]
288            else:
289                raise KeyEncryptionError('Unknown PBES2 pseudo-random '
290                                         'function')
291        else:
292            raise KeyEncryptionError('Invalid PBES2 pseudo-random function '
293                                     'parameters')
294    else:
295        hash_name = 'sha1'
296
297    if isinstance(passphrase, str):
298        passphrase = passphrase.encode('utf-8')
299
300    return pbkdf2_hmac(hash_name, passphrase, salt, count, key_size)
301
302
303def _pbes2(params, passphrase):
304    """PKCS#5 v2.0 cipher selection function for password-based encryption
305
306       This function implements the PKCS#5 v2.0 algorithm for password-based
307       encryption. It returns a cipher object which can be used to encrypt
308       or decrypt data based on the specified encryption parameters and
309       passphrase.
310
311    """
312
313    if (not isinstance(params, tuple) or len(params) != 2 or
314            not isinstance(params[0], tuple) or len(params[0]) < 1 or
315            not isinstance(params[1], tuple) or len(params[1]) < 1):
316        raise KeyEncryptionError('Invalid PBES2 encryption parameters')
317
318    kdf_params = list(params[0])
319
320    kdf_alg = kdf_params.pop(0)
321    if kdf_alg not in _pbes2_kdf:
322        raise KeyEncryptionError('Unknown PBES2 key derivation function')
323
324    enc_params = list(params[1])
325
326    enc_alg = enc_params.pop(0)
327    if enc_alg not in _pbes2_cipher:
328        raise KeyEncryptionError('Unknown PBES2 encryption algorithm')
329
330    kdf_handler, kdf_args = _pbes2_kdf[kdf_alg]
331    enc_handler, cipher_name = _pbes2_cipher[enc_alg]
332    default_key_size, _, _ = get_cipher_params(cipher_name)
333
334    key = kdf_handler(kdf_params, passphrase, default_key_size, *kdf_args)
335    return enc_handler(enc_params, cipher_name, key)
336
337
338def register_pkcs1_cipher(pkcs1_cipher_name, pkcs1_dek_name, cipher_name):
339    """Register a cipher used for PKCS#1 private key encryption"""
340
341    _pkcs1_cipher[pkcs1_dek_name] = cipher_name
342    _pkcs1_dek_name[pkcs1_cipher_name] = pkcs1_dek_name
343
344
345def register_pkcs8_cipher(pkcs8_cipher_name, hash_name, pkcs8_cipher_oid,
346                          handler, hash_alg, cipher_name):
347    """Register a cipher used for PKCS#8 private key encryption"""
348
349    _pkcs8_handler[pkcs8_cipher_oid] = (handler, hash_alg, cipher_name)
350    _pkcs8_cipher_oid[pkcs8_cipher_name, hash_name] = pkcs8_cipher_oid
351
352
353def register_pbes2_cipher(pbes2_cipher_name, pbes2_cipher_oid,
354                          handler, cipher_name):
355    """Register a PBES2 encryption algorithm"""
356
357    _pbes2_cipher[pbes2_cipher_oid] = (handler, cipher_name)
358    _pbes2_cipher_oid[pbes2_cipher_name] = pbes2_cipher_oid
359
360
361def register_pbes2_kdf(kdf_name, kdf_oid, handler, *args):
362    """Register a PBES2 key derivation function"""
363
364    _pbes2_kdf[kdf_oid] = (handler, args)
365    _pbes2_kdf_oid[kdf_name] = kdf_oid
366
367
368def register_pbes2_prf(hash_name, prf_oid):
369    """Register a PBES2 pseudo-random function"""
370
371    _pbes2_prf[prf_oid] = hash_name
372    _pbes2_prf_oid[hash_name] = prf_oid
373
374
375def pkcs1_encrypt(data, pkcs1_cipher_name, passphrase):
376    """Encrypt PKCS#1 key data
377
378       This function encrypts PKCS#1 key data using the specified cipher
379       and passphrase. Available ciphers include:
380
381           aes128-cbc, aes192-cbc, aes256-cbc, des-cbc, des3-cbc
382
383    """
384
385    if pkcs1_cipher_name in _pkcs1_dek_name:
386        pkcs1_dek_name = _pkcs1_dek_name[pkcs1_cipher_name]
387        cipher_name = _pkcs1_cipher[pkcs1_dek_name]
388        key_size, iv_size, block_size = get_cipher_params(cipher_name)
389
390        iv = os.urandom(iv_size)
391        key = _pbkdf1(md5, passphrase, iv[:8], 1, key_size)
392
393        cipher = _RFC1423Pad(cipher_name, block_size, key, iv)
394        return pkcs1_dek_name, iv, cipher.encrypt(data)
395    else:
396        raise KeyEncryptionError('Unknown PKCS#1 encryption algorithm')
397
398
399def pkcs1_decrypt(data, pkcs1_dek_name, iv, passphrase):
400    """Decrypt PKCS#1 key data
401
402       This function decrypts PKCS#1 key data using the specified algorithm,
403       initialization vector, and passphrase. The algorithm name and IV
404       should be taken from the PEM DEK-Info header.
405
406    """
407
408    if pkcs1_dek_name in _pkcs1_cipher:
409        cipher_name = _pkcs1_cipher[pkcs1_dek_name]
410        key_size, _, block_size = get_cipher_params(cipher_name)
411        key = _pbkdf1(md5, passphrase, iv[:8], 1, key_size)
412
413        cipher = _RFC1423Pad(cipher_name, block_size, key, iv)
414        return cipher.decrypt(data)
415    else:
416        raise KeyEncryptionError('Unknown PKCS#1 encryption algorithm')
417
418
419def pkcs8_encrypt(data, pkcs8_cipher_name, hash_name, version, passphrase):
420    """Encrypt PKCS#8 key data
421
422       This function encrypts PKCS#8 key data using the specified cipher,
423       hash, encryption version, and passphrase.
424
425       Available ciphers include:
426
427           aes128-cbc, aes192-cbc, aes256-cbc, blowfish-cbc, cast128-cbc,
428           des-cbc, des2-cbc, des3-cbc, rc4-40, and rc4-128
429
430       Available hashes include:
431
432           md5, sha1, sha256, sha384, sha512
433
434       Available versions include 1 for PBES1 and 2 for PBES2.
435
436       Only some combinations of cipher, hash, and version are supported.
437
438    """
439
440    if version == 1 and (pkcs8_cipher_name, hash_name) in _pkcs8_cipher_oid:
441        pkcs8_cipher_oid = _pkcs8_cipher_oid[pkcs8_cipher_name, hash_name]
442        handler, hash_alg, cipher_name = _pkcs8_handler[pkcs8_cipher_oid]
443
444        alg = pkcs8_cipher_oid
445        params = (os.urandom(8), 2048)
446        cipher = handler(params, passphrase, hash_alg, cipher_name)
447    elif version == 2 and pkcs8_cipher_name in _pbes2_cipher_oid:
448        pbes2_cipher_oid = _pbes2_cipher_oid[pkcs8_cipher_name]
449        _, cipher_name = _pbes2_cipher[pbes2_cipher_oid]
450        _, iv_size, _ = get_cipher_params(cipher_name)
451
452        kdf_params = [os.urandom(8), 2048]
453        iv = os.urandom(iv_size)
454        enc_params = (pbes2_cipher_oid, iv)
455
456        if hash_name != 'sha1':
457            if hash_name in _pbes2_prf_oid:
458                kdf_params.append((_pbes2_prf_oid[hash_name], None))
459            else:
460                raise KeyEncryptionError('Unknown PBES2 hash function')
461
462        alg = _ES2
463        params = ((_ES2_PBKDF2, tuple(kdf_params)), enc_params)
464        cipher = _pbes2(params, passphrase)
465    else:
466        raise KeyEncryptionError('Unknown PKCS#8 encryption algorithm')
467
468    return der_encode(((alg, params), cipher.encrypt(data)))
469
470
471def pkcs8_decrypt(key_data, passphrase):
472    """Decrypt PKCS#8 key data
473
474       This function decrypts key data in PKCS#8 EncryptedPrivateKeyInfo
475       format using the specified passphrase.
476
477    """
478
479    if not isinstance(key_data, tuple) or len(key_data) != 2:
480        raise KeyEncryptionError('Invalid PKCS#8 encrypted key format')
481
482    alg_params, data = key_data
483
484    if (not isinstance(alg_params, tuple) or len(alg_params) != 2 or
485            not isinstance(data, bytes)):
486        raise KeyEncryptionError('Invalid PKCS#8 encrypted key format')
487
488    alg, params = alg_params
489
490    if alg == _ES2:
491        cipher = _pbes2(params, passphrase)
492    elif alg in _pkcs8_handler:
493        handler, hash_alg, cipher_name = _pkcs8_handler[alg]
494        cipher = handler(params, passphrase, hash_alg, cipher_name)
495    else:
496        raise KeyEncryptionError('Unknown PKCS#8 encryption algorithm')
497
498    try:
499        return der_decode(cipher.decrypt(data))
500    except (ASN1DecodeError, UnicodeDecodeError):
501        raise KeyEncryptionError('Invalid PKCS#8 encrypted key data') from None
502
503
504_pkcs1_cipher_list = (
505    ('aes128-cbc', b'AES-128-CBC',  'aes128-cbc'),
506    ('aes192-cbc', b'AES-192-CBC',  'aes192-cbc'),
507    ('aes256-cbc', b'AES-256-CBC',  'aes256-cbc'),
508    ('des-cbc',    b'DES-CBC',      'des-cbc'),
509    ('des3-cbc',   b'DES-EDE3-CBC', 'des3-cbc')
510)
511
512_pkcs8_cipher_list = (
513    ('des-cbc', 'md5',  _ES1_MD5_DES,  _pbes1,   md5,  'des-cbc'),
514    ('des-cbc', 'sha1', _ES1_SHA1_DES, _pbes1,   sha1, 'des-cbc'),
515
516    ('des2-cbc','sha1', _P12_DES2,     _pbe_p12, sha1, 'des2-cbc'),
517    ('des3-cbc','sha1', _P12_DES3,     _pbe_p12, sha1, 'des3-cbc'),
518    ('rc4-40',  'sha1', _P12_RC4_40,   _pbe_p12, sha1, 'arcfour40'),
519    ('rc4-128', 'sha1', _P12_RC4_128,  _pbe_p12, sha1, 'arcfour')
520)
521
522_pbes2_cipher_list = (
523    ('aes128-cbc',   _ES2_AES128,  _pbes2_iv,  'aes128-cbc'),
524    ('aes192-cbc',   _ES2_AES192,  _pbes2_iv,  'aes192-cbc'),
525    ('aes256-cbc',   _ES2_AES256,  _pbes2_iv,  'aes256-cbc'),
526    ('blowfish-cbc', _ES2_BF,      _pbes2_iv,  'blowfish-cbc'),
527    ('cast128-cbc',  _ES2_CAST128, _pbes2_iv,  'cast128-cbc'),
528    ('des-cbc',      _ES2_DES,     _pbes2_iv,  'des-cbc'),
529    ('des3-cbc',     _ES2_DES3,    _pbes2_iv,  'des3-cbc')
530)
531
532_pbes2_kdf_list = (
533    ('pbkdf2', _ES2_PBKDF2, _pbes2_pbkdf2),
534)
535
536_pbes2_prf_list = (
537    ('sha1',   _ES2_SHA1),
538    ('sha224', _ES2_SHA224),
539    ('sha256', _ES2_SHA256),
540    ('sha384', _ES2_SHA384),
541    ('sha512', _ES2_SHA512)
542)
543
544for _pkcs1_cipher_args in _pkcs1_cipher_list:
545    register_pkcs1_cipher(*_pkcs1_cipher_args)
546
547for _pkcs8_cipher_args in _pkcs8_cipher_list:
548    register_pkcs8_cipher(*_pkcs8_cipher_args)
549
550for _pbes2_cipher_args in _pbes2_cipher_list:
551    register_pbes2_cipher(*_pbes2_cipher_args)
552
553for _pbes2_kdf_args in _pbes2_kdf_list:
554    register_pbes2_kdf(*_pbes2_kdf_args)
555
556for _pbes2_prf_args in _pbes2_prf_list:
557    register_pbes2_prf(*_pbes2_prf_args)
558