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