defxor(x, y): return bytes([xe ^ ye for xe,ye in zip(x,y)])
defto_blocks(m): m += to_block(len(m)) padb = N - len(m) % N m += bytes([padb]) * padb blocks = [m[N*i : N*(i+1)] for i in range(len(m) // N)] return blocks
defrot(n, c): return (n >> c) | ((n & ((1 << c) - 1)) << (8 * N - c))
deff(k0, i): return to_block(rot(to_int(k0), i % (8 * N)))
deffmac(k0, k1, m): C = AES.new(k1, AES.MODE_ECB) bs = [C.encrypt(xor(b, f(k0, i))) for i,b in enumerate(to_blocks(m))] return reduce(xor, bs, b"\x00" * N)
[입력 값] + [입력한 값의 length (16 bytes)] + [padding (N - length bytes)] 의 방법으로 블록이 만들어지고 있다.
fmac의 마지막에는 reduce를 사용하여 모든 블록을 xor한 값을 리턴해주고 있다.
이때, f(k0, i)잘 봐보면 to_block(rot(to_int(k0), i % (8 * N)))로 되어있다. N = 16이므로 f(k0, 0) == f(k0, 128)이라는 결론이 나온다.
즉, reduce에서 xor을 하며 합칠 때, 같은 입력값으로 256블록이 만들어진다면 서로 같은값끼리 xor돼서 256블록의 xor결과는 0이 되게 된다. 그러면 그 이후의 블록들의 xor결과만 남게 된다.
그럼 이제 tag를 이용해서 fmac을 생성해주는 부분과 우리가 실제로 입력한 값을 검증하는 부분의 차이점을 봐보자.