def basic_encrypt(cls, key, plaintext): assert len(plaintext) % 8 == 0 algo = ciphers.TripleDES(key.contents) cbc = modes.CBC(bytes(8)) encryptor = Cipher(algo, cbc, default_backend()).encryptor() ciphertext = encryptor.update(plaintext) return ciphertext
def basic_decrypt(cls, key, ciphertext): assert len(ciphertext) % 8 == 0 algo = ciphers.TripleDES(key.contents) cbc = modes.CBC(bytes(8)) decryptor = Cipher(algo, cbc, default_backend()).decryptor() plaintext = decryptor.update(ciphertext) return plaintext
def aes_cbc_dec(aesKey, bsEncMsg, bsMacMsg): ''' AuthenticatedEncryption - Check mac then decrypt given encrypted message. ''' ### Prepare for mac sha256 = SHA256() hmac = HMAC(aesKey, sha256, default_backend()) ### do mac hmac.update(bsEncMsg) macMsg = hmac.finalize() if (macMsg != bsMacMsg): raise Exception("ERRR:AEDecrypt:Mismatch, skipping") return None ### Prepare for decryption blockLen = 16 iv = os.urandom(blockLen) aes = AES(aesKey) cbc = CBC(iv) aesCbc = Cipher(aes, cbc, default_backend()) aesCbcDec = aesCbc.decryptor() ### do decrypt decMsg = aesCbcDec.update(bsEncMsg) decFina = aesCbcDec.finalize() decMsg = decMsg + decFina # do pkcs7 depadding unpad = PKCS7(blockLen * 8).unpadder() decMsg = unpad.update(decMsg) decMsg += unpad.finalize() # Discard the initial random block, as corresponding enc and this dec uses # non communicated random iv and inturn discardable random 0th block decMsg = decMsg[blockLen:] return decMsg
def test_nonexistent_aead_cipher(self): from cryptography.hazmat.backends.commoncrypto.backend import Backend b = Backend() cipher = Cipher( DummyCipher(), GCM(b"fake_iv_here"), backend=b, ) with raises_unsupported_algorithm(_Reasons.UNSUPPORTED_CIPHER): cipher.encryptor()
def test_nonexistent_aead_cipher(self): from cryptography.hazmat.backends.commoncrypto.backend import Backend b = Backend() cipher = Cipher( DummyCipher(), GCM(b"fake_iv_here"), backend=b, ) with pytest.raises(UnsupportedAlgorithm): cipher.encryptor()
def aes_cbc_enc(aesKey, sPlainMsg): ''' AuthenticatedEncryption - Do a encrypt then mac operation on given message. a random iv is generated but not transmitted, instead a random block is prepended to the message and encrypted. Inturn the same can be discarded during decrypting. Each CBC block depends on the previous encrypted block so the 0th block acts as a inplace iv at one level. Encryption uses AES in CBC mode with PKCS7 padding where required. MAC uses HMAC with SHA256 As encryption and mac using independent algorithms so the key is shared wrt encryption and mac operations. With aes length of key passed is independent of the block size used, and user can use any valid aes key size. This is similar to the age old encrypt as well as sign messages to ensure confidentiality as well as authenticity. But then instead of using asymm logic for signing, use a hash with hidden key based logic. Also make sure that one checks the authenticity before trying to use it or work on it, so that new oracles arent opened up, beyond the minimal unavoidable oracle. ''' ### Prepare for encryption blockLen = 16 iv = os.urandom(blockLen) aes = AES(aesKey) cbc = CBC(iv) aesCbc = Cipher(aes, cbc, default_backend()) aesCbcEnc = aesCbc.encryptor() random0thBlock = os.urandom(blockLen) # This allows iv to be discarded # so also while decrypting discard the 0th block plainMsg = random0thBlock + sPlainMsg.encode('utf-8') # do PKCS7 padding if bInternalPadder: padLen = blockLen - (len(plainMsg) % blockLen) for i in range(padLen): plainMsg += int.to_bytes(padLen, 1, 'little') else: pad = PKCS7(blockLen * 8).padder() plainMsg = pad.update(plainMsg) plainMsg += pad.finalize() ### do encrypt encMsg = aesCbcEnc.update(plainMsg) encFina = aesCbcEnc.finalize() encMsg = encMsg + encFina ### Prepare for mac sha256 = SHA256() hmac = HMAC(aesKey, sha256, default_backend()) ### do mac hmac.update(encMsg) macMsg = hmac.finalize() return encMsg, macMsg
def encrypt(cls, key, keyusage, plaintext, confounder): if confounder is None: confounder = get_random_bytes(8) ki = HMAC_HASH(key.contents, cls.usage_str(keyusage), hashes.MD5) cksum = HMAC_HASH(ki, confounder + plaintext, hashes.MD5) ke = HMAC_HASH(ki, cksum, hashes.MD5) encryptor = Cipher( ciphers.ARC4(ke), None, default_backend()).encryptor() ctext = encryptor.update(confounder + plaintext) return cksum + ctext
def decrypt(ciphertext, key, iv): """ Decrypt ciphertext """ assert len(key) == len(iv) == 32 cipher = Cipher( algorithms.AES(key), modes.CBC(iv[:16]), CRYPTO_BACKEND).decryptor() del key plaintext_padded = cipher.update(ciphertext) + cipher.finalize() unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder() plaintext = unpadder.update(plaintext_padded) + unpadder.finalize() return plaintext
def basic_decrypt(cls, key, ciphertext): assert len(ciphertext) >= 16 algo = ciphers.AES(key.contents) cbc = modes.CBC(bytes(16)) aes_ctx = Cipher(algo, cbc, default_backend()) def aes_decrypt(ciphertext): decryptor = aes_ctx.decryptor() plaintext = decryptor.update(ciphertext) return plaintext if len(ciphertext) == 16: return aes_decrypt(ciphertext) # Split the ciphertext into blocks. The last block may be partial. cblocks = [ciphertext[p:p + 16] for p in range(0, len(ciphertext), 16)] lastlen = len(cblocks[-1]) # CBC-decrypt all but the last two blocks. prev_cblock = bytes(16) plaintext = b'' for b in cblocks[:-2]: plaintext += _xorbytes(aes_decrypt(b), prev_cblock) prev_cblock = b # Decrypt the second-to-last cipher block. The left side of # the decrypted block will be the final block of plaintext # xor'd with the final partial cipher block; the right side # will be the omitted bytes of ciphertext from the final # block. b = aes_decrypt(cblocks[-2]) lastplaintext = _xorbytes(b[:lastlen], cblocks[-1]) omitted = b[lastlen:] # Decrypt the final cipher block plus the omitted bytes to get # the second-to-last plaintext block. plaintext += _xorbytes(aes_decrypt(cblocks[-1] + omitted), prev_cblock) return plaintext + lastplaintext
def encrypt(plaintext, key, iv): """ Encrypt plaintext """ assert len(key) == len(iv) == 32 cipher = Cipher( algorithms.AES(key), modes.CBC(iv[:16]), CRYPTO_BACKEND).encryptor() del key padder = padding.PKCS7(algorithms.AES.block_size).padder() padded_data = padder.update(plaintext) + padder.finalize() ciphertext = cipher.update(padded_data) + cipher.finalize() assert ciphertext return ciphertext
def decrypt(cls, key, keyusage, ciphertext): if len(ciphertext) < 24: raise ValueError('ciphertext too short') cksum, basic_ctext = ciphertext[:16], ciphertext[16:] ki = HMAC_HASH(key.contents, cls.usage_str(keyusage), hashes.MD5) ke = HMAC_HASH(ki, cksum, hashes.MD5) decryptor = Cipher( ciphers.ARC4(ke), None, default_backend()).decryptor() basic_plaintext = decryptor.update(basic_ctext) exp_cksum = HMAC_HASH(ki, basic_plaintext, hashes.MD5) ok = _mac_equal(cksum, exp_cksum) if not ok and keyusage == 9: # Try again with usage 8, due to RFC 4757 errata. ki = HMAC_HASH(key.contents, pack('<i', 8), hashes.MD5) exp_cksum = HMAC_HASH(ki, basic_plaintext, hashes.MD5) ok = _mac_equal(cksum, exp_cksum) if not ok: raise InvalidChecksum('ciphertext integrity failure') # Discard the confounder. return basic_plaintext[8:]
def basic_encrypt(cls, key, plaintext): assert len(plaintext) >= 16 algo = ciphers.AES(key.contents) cbc = modes.CBC(bytes(16)) aes_ctx = Cipher(algo, cbc, default_backend()) def aes_encrypt(plaintext): encryptor = aes_ctx.encryptor() ciphertext = encryptor.update(plaintext) return ciphertext ctext = aes_encrypt(_zeropad(plaintext, 16)) if len(plaintext) > 16: # Swap the last two ciphertext blocks and truncate the # final block to match the plaintext length. lastlen = len(plaintext) % 16 or 16 ctext = ctext[:-32] + ctext[-16:] + ctext[-32:-16][:lastlen] return ctext
def test_gmac2(): encryption_key = bytes.fromhex("000102030405060708090A0B0C0D0E0F") authentication_key = bytes.fromhex("D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF") security_control = SecurityControlField( security_suite=0, authenticated=True, encrypted=False ) client_invocation_counter = int.from_bytes(bytes.fromhex("00000001"), "big") client_system_title = bytes.fromhex("4D4D4D0000000001") # server_system_title = bytes.fromhex("4D4D4D0000BC614E") # server_invocation_counter = int.from_bytes(bytes.fromhex("01234567"), "big") # client_to_server_challenge = bytes.fromhex("4B35366956616759") server_to_client_challenge = bytes.fromhex("503677524A323146") iv = client_system_title + client_invocation_counter.to_bytes(4, "big") assert iv == bytes.fromhex("4D4D4D000000000100000001") # Construct an AES-GCM Cipher object with the given key and iv encryptor = Cipher( algorithms.AES(encryption_key), modes.GCM(initialization_vector=iv, tag=None, min_tag_length=12), ).encryptor() # associated_data will be authenticated but not encrypted, # it must also be passed in on decryption. associated_data = ( security_control.to_bytes() + authentication_key + server_to_client_challenge ) assert associated_data == bytes.fromhex( "10D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF503677524A323146" ) encryptor.authenticate_additional_data(associated_data) # Encrypt the plaintext and get the associated ciphertext. # GCM does not require padding. ciphertext = encryptor.update(b"") + encryptor.finalize() # dlms uses a tag lenght of 12 not the default of 16. Since we have set the minimum # tag length to 12 it is ok to truncated the tag. tag = encryptor.tag[:12] assert ciphertext == b"" result = ciphertext + tag assert result == bytes.fromhex("1A52FE7DD3E72748973C1E28")
def aes_decrypt(data, iv, key): cipher = Cipher(AES(key), CBC(iv), default_backend()) decryptor = cipher.decryptor() plain_text = decryptor.update(data) + decryptor.finalize() padding = plain_text[len(plain_text) - 1] return plain_text[:len(plain_text) - padding]