-
-
Save vbe0201/7e98986d8db0f52e8e55e6bbf91d48fe to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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