def encode(data, marker, passphrase=None, randfunc=None): """Encode a piece of binary data into PEM format. Args: data (byte string): The piece of binary data to encode. marker (string): The marker for the PEM block (e.g. "PUBLIC KEY"). Note that there is no official master list for all allowed markers. Still, you can refer to the OpenSSL_ source code. passphrase (byte string): If given, the PEM block will be encrypted. The key is derived from the passphrase. randfunc (callable): Random number generation function; it accepts an integer N and returns a byte string of random data, N bytes long. If not given, a new one is instantiated. Returns: The PEM block, as a string. .. _OpenSSL: https://github.com/openssl/openssl/blob/master/include/openssl/pem.h """ if randfunc is None: randfunc = get_random_bytes out = "-----BEGIN %s-----\n" % marker if passphrase: # We only support 3DES for encryption salt = randfunc(8) key = PBKDF1(passphrase, salt, 16, 1, MD5) key += PBKDF1(key + passphrase, salt, 8, 1, MD5) objenc = DES3.new(key, DES3.MODE_CBC, salt) out += "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,%s\n\n" %\ tostr(hexlify(salt).upper()) # Encrypt with PKCS#7 padding data = objenc.encrypt(pad(data, objenc.block_size)) elif passphrase is not None: raise ValueError("Empty password") # Each BASE64 line can take up to 64 characters (=48 bytes of data) # b2a_base64 adds a new line character! chunks = [ tostr(b2a_base64(data[i:i + 48])) for i in range(0, len(data), 48) ] out += "".join(chunks) out += "-----END %s-----" % marker return out
def crypt(_cfgUpgSecPls, flag): #gen key passphrase = b'h@k8807H$Z5998' passphrase = passphrase.ljust(31, b'\x00') salt = b'HangZhou' key = PBKDF1(passphrase, salt, 16, 2, MD5) key += PBKDF1(key + passphrase, salt, 16, 2, MD5) cipher = AES.new(key, AES.MODE_ECB) _cfgUpgSecPls = pad(_cfgUpgSecPls, 16) if flag == 'd': #dec _cfg dec_cfgUpgSecPls = cipher.decrypt(_cfgUpgSecPls) return dec_cfgUpgSecPls else: #enc _cfg enc_cfgUpgSecPls = cipher.encrypt(_cfgUpgSecPls) return enc_cfgUpgSecPls
def decrypt(data, passphrase): """Decrypt a piece of data using a passphrase and *PBES1*. The algorithm to use is automatically detected. :Parameters: data : byte string The piece of data to decrypt. passphrase : byte string The passphrase to use for decrypting the data. :Returns: The decrypted data, as a binary string. """ enc_private_key_info = DerSequence().decode(data) encrypted_algorithm = DerSequence().decode(enc_private_key_info[0]) encrypted_data = DerOctetString().decode( enc_private_key_info[1]).payload pbe_oid = DerObjectId().decode(encrypted_algorithm[0]).value cipher_params = {} if pbe_oid == _OID_PBE_WITH_MD5_AND_DES_CBC: # PBE_MD5_DES_CBC hashmod = MD5 ciphermod = DES elif pbe_oid == _OID_PBE_WITH_MD5_AND_RC2_CBC: # PBE_MD5_RC2_CBC hashmod = MD5 ciphermod = ARC2 cipher_params['effective_keylen'] = 64 elif pbe_oid == _OID_PBE_WITH_SHA1_AND_DES_CBC: # PBE_SHA1_DES_CBC hashmod = SHA1 ciphermod = DES elif pbe_oid == _OID_PBE_WITH_SHA1_AND_RC2_CBC: # PBE_SHA1_RC2_CBC hashmod = SHA1 ciphermod = ARC2 cipher_params['effective_keylen'] = 64 else: raise PbesError("Unknown OID for PBES1") pbe_params = DerSequence().decode(encrypted_algorithm[1], nr_elements=2) salt = DerOctetString().decode(pbe_params[0]).payload iterations = pbe_params[1] key_iv = PBKDF1(passphrase, salt, 16, iterations, hashmod) key, iv = key_iv[:8], key_iv[8:] cipher = ciphermod.new(key, ciphermod.MODE_CBC, iv, **cipher_params) pt = cipher.decrypt(encrypted_data) return unpad(pt, cipher.block_size)
def test1(self): v = self._testData[0] res = PBKDF1(v[0], t2b(v[1]), v[2], v[3], SHA1) self.assertEqual(res, t2b(v[4]))
def decode(pem_data, passphrase=None): """Decode a PEM block into binary. :Parameters: pem_data : string The PEM block. passphrase : byte string If given and the PEM block is encrypted, the key will be derived from the passphrase. :Returns: A tuple with the binary data, the marker string, and a boolean to indicate if decryption was performed. :Raises ValueError: If decoding fails, if the PEM file is encrypted and no passphrase has been provided or if the passphrase is incorrect. """ # Verify Pre-Encapsulation Boundary r = re.compile("\s*-----BEGIN (.*)-----\s+") m = r.match(pem_data) if not m: raise ValueError("Not a valid PEM pre boundary") marker = m.group(1) # Verify Post-Encapsulation Boundary r = re.compile("-----END (.*)-----\s*$") m = r.search(pem_data) if not m or m.group(1) != marker: raise ValueError("Not a valid PEM post boundary") # Removes spaces and slit on lines lines = pem_data.replace(" ", '').split() # Decrypts, if necessary if lines[1].startswith('Proc-Type:4,ENCRYPTED'): if not passphrase: raise ValueError("PEM is encrypted, but no passphrase available") DEK = lines[2].split(':') if len(DEK) != 2 or DEK[0] != 'DEK-Info': raise ValueError("PEM encryption format not supported.") algo, salt = DEK[1].split(',') salt = unhexlify(tobytes(salt)) if algo == "DES-CBC": # This is EVP_BytesToKey in OpenSSL key = PBKDF1(passphrase, salt, 8, 1, MD5) objdec = DES.new(key, DES.MODE_CBC, salt) elif algo == "DES-EDE3-CBC": # Note that EVP_BytesToKey is note exactly the same as PBKDF1 key = PBKDF1(passphrase, salt, 16, 1, MD5) key += PBKDF1(key + passphrase, salt, 8, 1, MD5) objdec = DES3.new(key, DES3.MODE_CBC, salt) elif algo == "AES-128-CBC": key = PBKDF1(passphrase, salt[:8], 16, 1, MD5) objdec = AES.new(key, AES.MODE_CBC, salt) else: raise ValueError("Unsupport PEM encryption algorithm (%s)." % algo) lines = lines[2:] else: objdec = None # Decode body data = a2b_base64(b(''.join(lines[1:-1]))) enc_flag = False if objdec: data = unpad(objdec.decrypt(data), objdec.block_size) enc_flag = True return (data, marker, enc_flag)