267 lines
8.9 KiB
Python
267 lines
8.9 KiB
Python
import math
|
|
from cryptography.hazmat.primitives.ciphers import Cipher
|
|
from cryptography.hazmat.primitives.ciphers.algorithms import AES
|
|
from cryptography.hazmat.primitives.ciphers.modes import GCM, ECB
|
|
import os
|
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
|
|
|
|
def aes_gcm_authenticated_decryption(key, iv, auth_tag, associated_data, ciphertext):
|
|
aes_gcm_decryptor = Cipher(AES(key), GCM(iv, auth_tag)).decryptor()
|
|
aes_gcm_decryptor.authenticate_additional_data(associated_data)
|
|
recovered_plaintext = aes_gcm_decryptor.update(ciphertext) + aes_gcm_decryptor.finalize()
|
|
return recovered_plaintext, auth_tag
|
|
|
|
|
|
def xor_bytes(bytes_a: bytes, bytes_b: bytes) -> bytes:
|
|
return bytes([a ^ b for (a, b) in zip(bytes_a, bytes_b)])
|
|
|
|
|
|
def MUL(X_bytes, Y_bytes):
|
|
X = int.from_bytes(X_bytes, 'big')
|
|
Y = int.from_bytes(Y_bytes, 'big')
|
|
# Constant R defined for algorithm
|
|
R = 0xe1 << 120
|
|
# Step 1
|
|
x = [1 if X & (1 << i) else 0 for i in range(127, -1, -1)]
|
|
# Steps 2 and 3
|
|
Z_i = 0
|
|
V_i = Y
|
|
for i in range(128):
|
|
if x[i] == 0:
|
|
Z_i_1 = Z_i
|
|
else:
|
|
Z_i_1 = Z_i ^ V_i
|
|
if V_i % 2 == 0:
|
|
V_i_1 = V_i >> 1
|
|
else:
|
|
V_i_1 = (V_i >> 1) ^ R
|
|
Z_i = Z_i_1
|
|
V_i = V_i_1
|
|
# Step 4
|
|
return Z_i.to_bytes(16, 'big')
|
|
|
|
|
|
def GHASH(H, X):
|
|
# Input constraint: len(X) = 128m
|
|
# 128/8=16 bo bajty
|
|
m = len(X) // 16
|
|
# Step 1
|
|
X_blocks = [X[i * 16:(i + 1) * 16] for i in range(m)]
|
|
# Step 2
|
|
# b'\x00' = 00000000
|
|
Y_0 = b'\x00' * 16
|
|
# Step 3
|
|
Y_i_1 = Y_0
|
|
for i in range(m):
|
|
X_i = X_blocks[i]
|
|
Y_i = MUL(xor_bytes(Y_i_1, X_i), H)
|
|
Y_i_1 = Y_i
|
|
# Step 4
|
|
return Y_i_1
|
|
|
|
|
|
def INC_32(Y_bytes):
|
|
Y = int.from_bytes(Y_bytes, 'big')
|
|
Y_inc = ((Y >> 32) << 32) ^ (((Y & 0xffffffff) + 1) & 0xffffffff)
|
|
return Y_inc.to_bytes(16, 'big')
|
|
|
|
|
|
def GCTR(K, ICB, X):
|
|
# Step 1
|
|
if not X:
|
|
return b''
|
|
|
|
# Step 2
|
|
n = math.ceil(len(X) / 16)
|
|
|
|
# Step 3
|
|
X_blocks = [X[i * 16:(i + 1) * 16] for i in range(n)]
|
|
|
|
# Step 4
|
|
CB = [ICB]
|
|
|
|
# Step 5
|
|
for i in range(1, n):
|
|
CB_i = INC_32(CB[i - 1])
|
|
CB.append(CB_i)
|
|
|
|
# Steps 6 and 7
|
|
Y_blocks = []
|
|
for i in range(n):
|
|
X_i = X_blocks[i]
|
|
CB_i = CB[i]
|
|
aes_encryptor = Cipher(AES(K), ECB()).encryptor()
|
|
ciphertext = aes_encryptor.update(CB_i) + aes_encryptor.finalize()
|
|
# Y_i = xor_bytes(X_i, aes_encryption(CB_i, K))
|
|
Y_i = xor_bytes(X_i, ciphertext)
|
|
Y_blocks.append(Y_i)
|
|
|
|
# Step 8
|
|
Y = b''.join(Y_blocks)
|
|
|
|
# Step 9
|
|
return Y
|
|
|
|
|
|
def aes_gcm_encrypt(P, K, IV, A, t):
|
|
# Step 1
|
|
data = (b'\x00' * 16)
|
|
aes_encryptor = Cipher(AES(K), ECB()).encryptor()
|
|
H = aes_encryptor.update(data) + aes_encryptor.finalize()
|
|
# Step 2
|
|
len_IV = len(IV) * 8
|
|
if len_IV == 96:
|
|
J_0 = IV + b'\x00\x00\x00\x01'
|
|
else:
|
|
s = 128 * math.ceil(len_IV / 128) - len_IV
|
|
O_s_64 = b'\x00' * ((s + 64) // 8)
|
|
len_IV_64 = int.to_bytes(len_IV, 8, 'big')
|
|
J_0 = GHASH(H, IV + O_s_64 + len_IV_64)
|
|
|
|
# Step 3
|
|
C = GCTR(K, INC_32(J_0), P)
|
|
|
|
# Step 4
|
|
len_C, len_A = len(C) * 8, len(A) * 8
|
|
u = 128 * math.ceil(len_C / 128) - len_C
|
|
v = 128 * math.ceil(len_A / 128) - len_A
|
|
|
|
# Step 5
|
|
O_v = b'\x00' * (v // 8)
|
|
O_u = b'\x00' * (u // 8)
|
|
len_A_64 = int.to_bytes(len_A, 8, 'big')
|
|
len_C_64 = int.to_bytes(len_C, 8, 'big')
|
|
S = GHASH(H, A + O_v + C + O_u + len_A_64 + len_C_64)
|
|
|
|
# Step 6
|
|
T = GCTR(K, J_0, S)[:t // 8] # Assumes tag length multiple of 8
|
|
|
|
# Step 7
|
|
return C, T
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# NIST Special Publication 800-38D
|
|
|
|
# NIST test vector 1
|
|
key = bytearray.fromhex('11754cd72aec309bf52f7687212e8957')
|
|
iv = bytearray.fromhex('3c819d9a9bed087615030b65')
|
|
plaintext = bytearray.fromhex('')
|
|
associated_data = bytearray.fromhex('')
|
|
expected_ciphertext = bytearray.fromhex('')
|
|
expected_tag = bytearray.fromhex('250327c674aaf477aef2675748cf6971')
|
|
tag_length = 128
|
|
|
|
ciphertext, auth_tag = aes_gcm_encrypt(plaintext, key, iv, associated_data, tag_length)
|
|
|
|
assert (ciphertext == expected_ciphertext)
|
|
assert (auth_tag == expected_tag)
|
|
|
|
message, _ = aes_gcm_authenticated_decryption(key, iv, auth_tag, associated_data, ciphertext)
|
|
print("wiadomosc:")
|
|
print(plaintext)
|
|
print("otrzymana wiadomosc:")
|
|
print(message)
|
|
|
|
# NIST test vector 2
|
|
key = bytearray.fromhex('fe47fcce5fc32665d2ae399e4eec72ba')
|
|
iv = bytearray.fromhex('5adb9609dbaeb58cbd6e7275')
|
|
plaintext = bytearray.fromhex('7c0e88c88899a779228465074797cd4c2e1498d259b54390b85e3eef1c02df60e743f1b840382c4bccaf'
|
|
'3bafb4ca8429bea063')
|
|
associated_data = bytearray.fromhex('88319d6e1d3ffa5f987199166c8a9b56c2aeba5a')
|
|
expected_ciphertext = bytearray.fromhex('98f4826f05a265e6dd2be82db241c0fbbbf9ffb1c173aa83964b7cf5393043736365253ddb'
|
|
'c5db8778371495da76d269e5db3e')
|
|
expected_tag = bytearray.fromhex('291ef1982e4defedaa2249f898556b47')
|
|
tag_length = 128
|
|
|
|
ciphertext, auth_tag = aes_gcm_encrypt(plaintext, key, iv, associated_data, tag_length)
|
|
|
|
assert (ciphertext == expected_ciphertext)
|
|
assert (auth_tag == expected_tag)
|
|
|
|
message, _ = aes_gcm_authenticated_decryption(key, iv, auth_tag, associated_data, ciphertext)
|
|
print("wiadomosc:")
|
|
print(plaintext)
|
|
print("otrzymana wiadomosc:")
|
|
print(message)
|
|
|
|
# NIST test vector 3
|
|
key = bytearray.fromhex('c7d9358af0fd737b118dbf4347fd252a')
|
|
iv = bytearray.fromhex('83de9fa52280522b55290ebe3b067286d87690560179554153cb3341a04e15c5f35390602fa07e5b5f16dc38cf0'
|
|
'82b11ad6dd3fab8552d2bf8d9c8981bbfc5f3b57e5e3066e3df23f078fa25bce63d3d6f86ce9fbc2c679655b958'
|
|
'b09a991392eb93b453ba6e7bf8242f8f61329e3afe75d0f8536aa7e507d75891e540fb1d7e')
|
|
plaintext = bytearray.fromhex('422f46223fddff25fc7a6a897d20dc8af6cc8a37828c90bd95fa9b943f460eb0a26f29ffc483592efb64'
|
|
'835774160a1bb5c0cd')
|
|
associated_data = bytearray.fromhex('5d2b9a4f994ffaa03000149956c8932e85b1a167294514e388b73b10808f509ea73c075ecbf43c'
|
|
'ecfec13c202afed62110dabf8026d237f4e765853bc078f3afe081d0a1f8d8f7556b8e42acc3cc'
|
|
'e888262185048d67c55b2df1')
|
|
expected_ciphertext = bytearray.fromhex('86eba4911578ac72ac30c25fe424da9ab625f29b5c00e36d2c24a2733dc40123dc57a8c9f1'
|
|
'7a24a26c09c73ad4efbcba3bab5b')
|
|
expected_tag = bytearray.fromhex('492305190344618cab8b40f006a57186')
|
|
tag_length = 128
|
|
|
|
ciphertext, auth_tag = aes_gcm_encrypt(plaintext, key, iv, associated_data, tag_length)
|
|
|
|
assert (ciphertext == expected_ciphertext)
|
|
assert (auth_tag == expected_tag)
|
|
|
|
message, _ = aes_gcm_authenticated_decryption(key, iv, auth_tag, associated_data, ciphertext)
|
|
print("wiadomosc:")
|
|
print(plaintext)
|
|
print("otrzymana wiadomosc:")
|
|
print(message)
|
|
|
|
print("\n" * 10)
|
|
# wlasne
|
|
key = AESGCM.generate_key(bit_length=128) # bytearray.fromhex('11754cd72aec309bf52f7687212e8957')
|
|
iv = bytearray.fromhex('3c819d9a9bed087615030b65')
|
|
|
|
plaintext = "wiadomosc1".encode()
|
|
associated_data = "potwierdzenie".encode()
|
|
ciphertext, auth_tag = aes_gcm_encrypt(plaintext, key, iv, associated_data, tag_length)
|
|
|
|
print(ciphertext)
|
|
print(auth_tag)
|
|
|
|
message, _ = aes_gcm_authenticated_decryption(key, iv, auth_tag, associated_data, ciphertext)
|
|
print(message)
|
|
|
|
data = b"wiadomosc1"
|
|
aad = b"potwierdzenie"
|
|
|
|
aesgcm = AESGCM(key)
|
|
nonce = iv # os.urandom(12)
|
|
|
|
ct = aesgcm.encrypt(nonce, data, aad)
|
|
print(ct)
|
|
|
|
msg = aesgcm.decrypt(nonce, ct, aad)
|
|
print(msg)
|
|
|
|
# przykladowe dane 10
|
|
|
|
print("\n" * 5)
|
|
# wlasne
|
|
key = bytearray.fromhex('feffe9928665731c6d6a8f9467308308feffe9928665731c')
|
|
iv = bytearray.fromhex('cafebabefacedbaddecaf888')
|
|
plaintext = bytearray.fromhex(
|
|
"d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39")
|
|
associated_data = bytearray.fromhex("feedfacedeadbeeffeedfacedeadbeefabaddad2")
|
|
|
|
# wlasne
|
|
ciphertext, auth_tag = aes_gcm_encrypt(plaintext, key, iv, associated_data, tag_length)
|
|
print(ciphertext.hex(), auth_tag.hex(), sep="")
|
|
|
|
message, _ = aes_gcm_authenticated_decryption(key, iv, auth_tag, associated_data, ciphertext)
|
|
print(message.hex())
|
|
|
|
# gotowe
|
|
aesgcm = AESGCM(key)
|
|
|
|
ciphertext = aesgcm.encrypt(iv, plaintext, associated_data)
|
|
print(ciphertext.hex())
|
|
|
|
message = aesgcm.decrypt(iv, ciphertext, associated_data)
|
|
print(message.hex())
|