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