130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
|
#!/usr/bin/env python
|
||
|
|
||
|
from Crypto.Cipher import AES
|
||
|
from Crypto.Util import strxor
|
||
|
from struct import pack, unpack
|
||
|
|
||
|
def gcm_rightshift(vec):
|
||
|
for x in range(15, 0, -1):
|
||
|
c = vec[x] >> 1
|
||
|
c |= (vec[x-1] << 7) & 0x80
|
||
|
vec[x] = c
|
||
|
vec[0] >>= 1
|
||
|
return vec
|
||
|
|
||
|
def gcm_gf_mult(a, b):
|
||
|
mask = [ 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 ]
|
||
|
poly = [ 0x00, 0xe1 ]
|
||
|
|
||
|
Z = [0] * 16
|
||
|
V = [c for c in a]
|
||
|
|
||
|
for x in range(128):
|
||
|
if b[x >> 3] & mask[x & 7]:
|
||
|
Z = [V[y] ^ Z[y] for y in range(16)]
|
||
|
bit = V[15] & 1
|
||
|
V = gcm_rightshift(V)
|
||
|
V[0] ^= poly[bit]
|
||
|
return Z
|
||
|
|
||
|
def ghash(h, auth_data, data):
|
||
|
u = (16 - len(data)) % 16
|
||
|
v = (16 - len(auth_data)) % 16
|
||
|
|
||
|
x = auth_data + chr(0) * v + data + chr(0) * u
|
||
|
x += pack('>QQ', len(auth_data) * 8, len(data) * 8)
|
||
|
|
||
|
y = [0] * 16
|
||
|
vec_h = [ord(c) for c in h]
|
||
|
|
||
|
for i in range(0, len(x), 16):
|
||
|
block = [ord(c) for c in x[i:i+16]]
|
||
|
y = [y[j] ^ block[j] for j in range(16)]
|
||
|
y = gcm_gf_mult(y, vec_h)
|
||
|
|
||
|
return ''.join(chr(c) for c in y)
|
||
|
|
||
|
def inc32(block):
|
||
|
counter, = unpack('>L', block[12:])
|
||
|
counter += 1
|
||
|
return block[:12] + pack('>L', counter)
|
||
|
|
||
|
def gctr(k, icb, plaintext):
|
||
|
y = ''
|
||
|
if len(plaintext) == 0:
|
||
|
return y
|
||
|
|
||
|
aes = AES.new(k)
|
||
|
cb = icb
|
||
|
|
||
|
for i in range(0, len(plaintext), aes.block_size):
|
||
|
cb = inc32(cb)
|
||
|
encrypted = aes.encrypt(cb)
|
||
|
plaintext_block = plaintext[i:i+aes.block_size]
|
||
|
y += strxor.strxor(plaintext_block, encrypted[:len(plaintext_block)])
|
||
|
|
||
|
return y
|
||
|
|
||
|
def gcm_decrypt(k, iv, encrypted, auth_data, tag):
|
||
|
aes = AES.new(k)
|
||
|
h = aes.encrypt(chr(0) * aes.block_size)
|
||
|
|
||
|
if len(iv) == 12:
|
||
|
y0 = iv + "\x00\x00\x00\x01"
|
||
|
else:
|
||
|
y0 = ghash(h, '', iv)
|
||
|
|
||
|
decrypted = gctr(k, y0, encrypted)
|
||
|
s = ghash(h, auth_data, encrypted)
|
||
|
|
||
|
t = aes.encrypt(y0)
|
||
|
T = strxor.strxor(s, t)
|
||
|
if T != tag:
|
||
|
raise ValueError('Decrypted data is invalid')
|
||
|
else:
|
||
|
return decrypted
|
||
|
|
||
|
def gcm_encrypt(k, iv, plaintext, auth_data):
|
||
|
aes = AES.new(k)
|
||
|
h = aes.encrypt(chr(0) * aes.block_size)
|
||
|
|
||
|
if len(iv) == 12:
|
||
|
y0 = iv + "\x00\x00\x00\x01"
|
||
|
else:
|
||
|
y0 = ghash(h, '', iv)
|
||
|
|
||
|
encrypted = gctr(k, y0, plaintext)
|
||
|
s = ghash(h, auth_data, encrypted)
|
||
|
|
||
|
t = aes.encrypt(y0)
|
||
|
T = strxor.strxor(s, t)
|
||
|
return (encrypted, T)
|
||
|
|
||
|
def main():
|
||
|
#http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
|
||
|
k = 'AD7A2BD03EAC835A6F620FDCB506B345'.decode("hex")
|
||
|
p = ''
|
||
|
a = 'D609B1F056637A0D46DF998D88E5222AB2C2846512153524C0895E8108000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F30313233340001'.decode("hex")
|
||
|
iv = '12153524C0895E81B2C28465'.decode("hex")
|
||
|
c, t = gcm_encrypt(k, iv, '', a)
|
||
|
assert c == ""
|
||
|
assert t == "f09478a9b09007d06f46e9b6a1da25dd".decode("hex")
|
||
|
|
||
|
k = 'AD7A2BD03EAC835A6F620FDCB506B345'.decode("hex")
|
||
|
p = '08000F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A0002'.decode("hex")
|
||
|
a = 'D609B1F056637A0D46DF998D88E52E00B2C2846512153524C0895E81'.decode("hex")
|
||
|
iv = '12153524C0895E81B2C28465'.decode("hex")
|
||
|
c, t = gcm_encrypt(k, iv, p, a)
|
||
|
assert c == '701AFA1CC039C0D765128A665DAB69243899BF7318CCDC81C9931DA17FBE8EDD7D17CB8B4C26FC81E3284F2B7FBA713D'.decode("hex")
|
||
|
assert t == '4F8D55E7D3F06FD5A13C0C29B9D5B880'.decode("hex")
|
||
|
|
||
|
key = "91bfb6cbcff07b93a4c68bbfe99ac63b713f0627025c0fb1ffc5b0812dc284f8".decode("hex")
|
||
|
data = "020000000B00000028000000DE44D22E96B1966BAEF4CBEA8675871D40BA669401BD4EBB52AF9C025134187E70549012058456BF0EC0FA1F8FF9F822AC4312AB2141FA712E6D1482358EAC1421A1BFFA81EF38BD0BF2E52675D665EFE3C534E188F575774FAA92E74345575E370B9982661FAE8BD9243B7AD7D2105B275424C0CA1145B9D43AFF04F2747E40D62EC60563960D62A894BE66F267B14D75C0572BE60CC9B339D440FCB418D4F729BBF15C14E0D3A43E4A8B44523D8B3B0F3E7DF85AA67A707EE19CB893277D2392234D7DBC17DA4A0BD7F166189FC54C16C20D287E20FD2FB11BD2CE09ADBDABB95124CD4BFE219E34D3C80E69570A5A506555D7094916C5D75E0065F1796F556EDF0DAA1AA758E0C85AE3951BD363F26B1D43F6CBAEE12D97AD3B60CFA89C1C76BB29F2B54BE31B6CE166F4860C5E5DA92588EF53AA946DF159E60E6F05009D12FB1E37".decode("hex")
|
||
|
ciphertext = data[12+40:-16]
|
||
|
tag = data[-16:]
|
||
|
print repr(gcm_decrypt(key, '', ciphertext, '', tag))
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|