# Copyright (c) (2019,2020) Apple Inc. All rights reserved. # # corecrypto is licensed under Apple Inc.’s Internal Use License Agreement (which # is contained in the License.txt file distributed with corecrypto) and only to # people who accept that license. IMPORTANT: Any license rights granted to you by # Apple Inc. (if any) are limited to internal use within your organization only on # devices and computers you own or control, for the sole purpose of verifying the # security characteristics and correct functioning of the Apple Software. You may # not, directly or indirectly, redistribute the Apple Software or any portions thereof. from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, hmac from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes import binascii #There is a lot of debugging print lines that are included below that are commented out. They can be commented back in for future debugging purposes. def h2s(hs): return binascii.hexlify(hs) def encode_length_be(val): buf=bytearray (b'\x00\x00\x00\x00\x00\x00\x00\x00') for i in range(0,8): x = (val >> ((7-i)*8)) & 0xFF #print "i=="+str(i) #print str(x) buf[i]=x return buf def hash_update(hmac, data, type): #def hash_update(hmac, data): #print "ad:" + h2s(ad) hmac.update(bytes(data)) el = encode_length_be(len(data)) #print "ad LENGTH ENCODING:" + h2s(el) hmac.update(bytes(el)) hmac.update(bytes(type)) def create_tag(hm, authenticated_data, nonce, plaintext): for ad in authenticated_data: hash_update(hm, ad,'A') if len(nonce)!=0: hash_update(hm, bytes(nonce),'N') if len(plaintext)!=0: hash_update(hm, bytes(plaintext),'P') return hm.finalize() def siv_hmac_enc(key, authenticated_data_prime, nonce, plaintext, tag_length): #make sure key length is 32 (We support only same size AES and HMAC Keys current code only 128 bit keys) nonce=bytearray.fromhex(nonce) key=bytearray.fromhex(key) #authenticated_data=authenticated_data_prime[:] authenticated_data=map(bytearray.fromhex, authenticated_data_prime[:]) authenticated_data=map(bytes,authenticated_data) if (len(key)!=32): print "Error in key length" return -1; #split key: AES First, then HMAC. aes_key=key[0:16] hmac_key=key[16:32] #print "HMAC KEY = " + h2s(bytes(hmac_key)) #print "AES KEY = " + h2s(bytes(aes_key)) #setup HMAC hm = hmac.HMAC(bytes(hmac_key), hashes.SHA256(), backend=default_backend()) #digest = hashes.Hash(hashes.SHA256(), backend=default_backend()) if (len(authenticated_data)==0 and len (nonce)==0 and len(plaintext)==0): hm.update(bytes(b'\x01\x02\x03\x04')) tag=hm.finalize() return (tag[0:tag_length],'') #add nonce to the end of authenticated data list #Generate Tag #print "Encryption Authenticated Data String" """for ad in authenticated_data: hash_update(hm, ad) if len(nonce)!=0: hash_update(hm, bytes(nonce)) if len(plaintext)!=0: hash_update(hm, bytes(plaintext)) tag=hm.finalize()""" tag = create_tag(hm, authenticated_data, nonce, plaintext) #print "tag:" + h2s(tag ) #print "Computed Tag is:" + binascii.hexlify(tag) iv=bytearray(tag[0:16]) gen_key = rekey(aes_key, iv) iv[8]&=0x7F iv[12]&=0x7F #print "Tag = " + h2s(tag[0:16]) cipher = Cipher(algorithms.AES(bytes(gen_key)), modes.CTR(bytes(iv)), backend=default_backend()) encryptor = cipher.encryptor() ciphertext = encryptor.update(plaintext) #print "Encrypted Plaintext ="+plaintext encryptor.finalize() #print "Returned Ciphertext is:" + binascii.hexlify(ciphertext) return (tag[0:tag_length], ciphertext) def siv_hmac_dec(key, authenticated_data_prime, nonce, ciphertext, tag, tag_length): #make sure key length is 32 (We support only same size AES and HMAC Keys current code only 128 bit keys) nonce=bytearray.fromhex(nonce) key=bytearray.fromhex(key) authenticated_data=map(bytearray.fromhex, authenticated_data_prime[:]) authenticated_data=map(bytes,authenticated_data) if (len(key)!=32): print "Error in key length" return -1; if (len(tag)<16 or len(tag)