Skip to content

Instantly share code, notes, and snippets.

@vbe0201

vbe0201/ghash.py Secret

Created January 24, 2023 01:56
Show Gist options
  • Select an option

  • Save vbe0201/7e98986d8db0f52e8e55e6bbf91d48fe to your computer and use it in GitHub Desktop.

Select an option

Save vbe0201/7e98986d8db0f52e8e55e6bbf91d48fe to your computer and use it in GitHub Desktop.
from struct import pack
from Crypto.Cipher import AES
from Crypto.Util import Counter
u8 = lambda x: x & 0xFF
u32 = lambda x: x & 0xFFFF_FFFF
u64 = lambda x: x & 0xFFFF_FFFF_FFFF_FFFF
LAST_4 = [
0x0000, 0x1c20, 0x3840, 0x2460,
0x7080, 0x6ca0, 0x48c0, 0x54e0,
0xe100, 0xfd20, 0xd940, 0xc560,
0x9180, 0x8da0, 0xa9c0, 0xb5e0,
]
class GHash:
def __init__(self, key: bytes):
self.hl = [0] * AES.block_size
self.hh = [0] * AES.block_size
h = AES.new(key, AES.MODE_ECB).encrypt(b"\x00" * AES.block_size)
self.populate_htables(h)
def populate_htables(self, key: bytes):
vh = int.from_bytes(key[0:8], "big")
vl = int.from_bytes(key[8:16], "big")
self.hl[8] = vl
self.hh[8] = vh
self.hh[0] = 0
self.hl[0] = 0
i = 4
while i > 0:
t = u32((vl & 1) * 0xe1000000)
self.hl[i] = u64((vh << 63) | (vl >> 1))
self.hh[i] = u64((vh >> 1) ^ u64(t << 32))
i >>= 1
i = 2
while i <= 8:
vh = self.hh[i]
vl = self.hl[i]
for j in range(1, i):
self.hh[i + j] = vh ^ self.hh[j]
self.hl[i + j] = vl ^ self.hl[j]
i *= 2
def mult(self, input: bytes) -> bytes:
lo = u8(input[15] & 0xF)
zh = self.hh[lo]
zl = self.hl[lo]
for i in range(15, -1, -1):
lo = u8(input[i] & 0xF)
hi = u8(input[i] >> 4)
if i != 15:
rem = u8(zl & 0xF)
zl = u64((zh << 60) | (zl >> 4))
zh = u64(zh >> 4)
zh ^= u64(LAST_4[rem] << 48)
zh ^= self.hh[lo]
zl ^= self.hl[lo]
rem = u8(zl & 0xF)
zl = u64((zh << 60) | (zl >> 4))
zh = u64(zh >> 4)
zh ^= u64(LAST_4[rem] << 48)
zh ^= self.hh[hi]
zl ^= self.hl[hi]
return pack(">IIII", u32(zh >> 32), u32(zh), u32(zl >> 32), u32(zl))
def get_initial_ctr(key: bytes, nonce: bytes):
ghash = GHash(key)
j0 = bytearray(b"\x00" * AES.block_size)
if len(nonce) == 12:
j0[0:12] = nonce
j0[15] = 1
else:
block = pack(">QQ", 0, len(nonce) * 8)
nonce_len = len(nonce)
while nonce_len > 0:
use_len = min(nonce_len, 16)
for i in range(0, use_len):
j0[i] ^= nonce[i]
j0 = bytearray(ghash.mult(j0))
nonce_len -= use_len
nonce = nonce[use_len:]
for i in range(0, AES.block_size):
j0[i] ^= block[i]
j0 = ghash.mult(j0)
print(j0.hex(" ").upper())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment