Decrypt the provided ciphertext which has been encrypted using symmetric_encrypt() method (it assumes input is in hex notation as returned by binascii.hexlify). NOTE 1: This function assumes ciphertext has been encrypted using symmetric AES crypto from keyczar library. Underneath i
(decrypt_key, ciphertext)
| 291 | |
| 292 | |
| 293 | def cryptography_symmetric_decrypt(decrypt_key, ciphertext): |
| 294 | """ |
| 295 | Decrypt the provided ciphertext which has been encrypted using symmetric_encrypt() method (it |
| 296 | assumes input is in hex notation as returned by binascii.hexlify). |
| 297 | |
| 298 | NOTE 1: This function assumes ciphertext has been encrypted using symmetric AES crypto from |
| 299 | keyczar library. Underneath it uses crypto primitives from cryptography library which is Python |
| 300 | 3 compatible. |
| 301 | |
| 302 | NOTE 2: This function is loosely based on keyczar AESKey.Decrypt() (Apache 2.0 license). |
| 303 | """ |
| 304 | if not isinstance(decrypt_key, AESKey): |
| 305 | raise TypeError( |
| 306 | "Decrypted key needs to be an AESKey class instance" |
| 307 | f" (was {type(decrypt_key)})." |
| 308 | ) |
| 309 | if not isinstance(ciphertext, (six.text_type, six.string_types, six.binary_type)): |
| 310 | raise TypeError( |
| 311 | "Ciphertext needs to either be a string/unicode or bytes" |
| 312 | f" (was {type(ciphertext)})." |
| 313 | ) |
| 314 | aes_key_bytes = decrypt_key.aes_key_bytes |
| 315 | hmac_key_bytes = decrypt_key.hmac_key_bytes |
| 316 | |
| 317 | if not isinstance(aes_key_bytes, six.binary_type): |
| 318 | raise TypeError(f"AESKey is not bytes (it is {type(aes_key_bytes)}).") |
| 319 | if not isinstance(hmac_key_bytes, six.binary_type): |
| 320 | raise TypeError(f"HMACKey is not bytes (it is {type(hmac_key_bytes)}).") |
| 321 | |
| 322 | # Convert from hex notation ASCII string to bytes |
| 323 | ciphertext = binascii.unhexlify(ciphertext) |
| 324 | |
| 325 | data_bytes = ciphertext[KEYCZAR_HEADER_SIZE:] # remove header |
| 326 | |
| 327 | # Verify ciphertext contains IV + HMAC signature |
| 328 | if len(data_bytes) < (KEYCZAR_AES_BLOCK_SIZE + KEYCZAR_HLEN): |
| 329 | raise ValueError("Invalid or malformed ciphertext (too short)") |
| 330 | |
| 331 | iv_bytes = data_bytes[:KEYCZAR_AES_BLOCK_SIZE] # first block is IV |
| 332 | ciphertext_bytes = data_bytes[ |
| 333 | KEYCZAR_AES_BLOCK_SIZE:-KEYCZAR_HLEN |
| 334 | ] # strip IV and signature |
| 335 | signature_bytes = data_bytes[-KEYCZAR_HLEN:] # last 20 bytes are signature |
| 336 | |
| 337 | # Verify HMAC signature |
| 338 | backend = default_backend() |
| 339 | h = hmac.HMAC(hmac_key_bytes, hashes.SHA1(), backend=backend) |
| 340 | h.update(ciphertext[:-KEYCZAR_HLEN]) |
| 341 | h.verify(signature_bytes) |
| 342 | |
| 343 | # Decrypt ciphertext |
| 344 | cipher = Cipher(algorithms.AES(aes_key_bytes), modes.CBC(iv_bytes), backend=backend) |
| 345 | |
| 346 | decryptor = cipher.decryptor() |
| 347 | decrypted = decryptor.update(ciphertext_bytes) + decryptor.finalize() |
| 348 | |
| 349 | # Unpad |
| 350 | decrypted = pkcs5_unpad(decrypted) |