GCM 운영모드 표준 문서는 다음 주소에서 확인할 수 있습니다.
- www.tta.or.kr/data/androReport/standExplan/표준해설서_128비트블록암호LEA및운영모드_수정.pdf
- seed.kisa.or/kisa/Board/17/detailView.do
- nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
(SEED 블록암호 알고리즘에 대한 소스코드 활용 매뉴얼 pdf 파일에 gcm에 관한 내용이 있습니다.)
NIST 800-38d 문서의 그림이 이해하기 좋게 잘 나와 있습니다. 그림을 보면 '구조처럼 동작하고 내부적으로 inc\(_{32}\), GHASH 함수와 GCTR 함수가 필요하다' 라고 볼 수 있습니다.
GHASH 함수 내부에는 곱셈 연산을 필요로 합니다. 이 곱셈은 일반 곱셈이 아닌 이진 유한체상의 곱셈입니다. GCM 운영모드의 곱셈 연산에 대해서 알아보고 확인하는 방법에 대해서 소개하겠습니다.
NIST 문서의 곱셈 연산을 수정하여 작성했습니다. 국내 문서와 큰 차이는 없습니다. 다만 여러 문서를 볼 경우, 기호를 헷갈리지 않게 주의하도록 합니다.
이진 유한체 곱셈이지만 유한체 관한 내용 없이 shift 연산과 xor 연산으로 간단하게 동작하는 것을 확인할 수 있습니다.
여기서 한 가지 의문이 생깁니다.
'이 결과가 정확한 값인가?'
방법과 함께 결과를 확인하기 위한 방법을 알아보겠습니다.
다시 표현부터 정리하겠습니다. (기호는 문서 처음에 보는 것을 권장합니다.)
\(X\)를 다음과 같이 128비트로 표현할 수 있습니다.
$$ X = x_1x_2\ldots x_{127}. $$
다항식으로 표현하면 다음과 같습니다.
\begin{align} X&= a_0+a_1x + \cdots + a_{127}x^{127} \\ &= a_{127}x^{127} + \cdots + a_1x + a_0,\quad (a_i\in\{0,1\}, 1\leq i \leq 127 ).\end{align}
이러한 표현이 중요한 이유는 표현에 따라 구현 방법이 바뀌기 때문입니다. 예를 들어, 최상위 비트 \( a^{127}\)를 찾는다면 위의 식에서는 가장 오른쪽을, 아래 식에서는 가장 왼쪽을 확인해야 합니다.
국내 문서는 다음과 같이 표현되어 있습니다.
$$g(u) = u^{128} + u^7 + u^2 + u + 1.$$
하지만 NIST 문서와 같은 곱셈을 사용합니다. 이 표현을 주의 하면 되겠습니다.
곱셈에서 나오는 \( 11100001||0^{120} \)이 값은 \(1+x+x^2+x^7 \)을 의미합니다. 헥사로 0xe1 입니다.
알고리듬 1의 pseudo code는 다음과 같습니다.
/*
* 16 바이트 기준, check_index, XOR, rightshift1 구현 필요
*/
void GMul(unsigned char* dst, unsigned char* src1, unsigned char* src2)
{
int iter;
unsigned char V[16] = {0x0, };
unsigned char Z[16] = {0x0, };
memcpy(V, src1, 16);
for(iter = 0; iter < 128; ++iter)
{
if(check_index(src2, iter))
{
XOR(Z, Z, V, 16);
}
if((V[15] & 0x01) == 1)
{
rightshift1(V, V);
V[0] ^= 0xe1; /* R */
}
else
rightshift1(V, V);
}
memcpy(dst, Z, 16);
}
이제 결과값을 확인하는 방법을 보겠습니다.
수학 연산을 지원하는 SageMath를 이용하겠습니다. 온라인 터미널을 제공하고 있어 설치하지 않아도 됩니다.
이진유한체 상의 곱셈 연산이기에 이진 유한체를 설정해 주어야 합니다.
예시로 \( z^{127} \)을 제곱한 값을 보도록 하겠습니다. 코드는 다음과 같습니다.
bin.<z> = GF(2)[]
poly = 1+z+z^2+z^7+z^128
S = bin.quotient(poly, 'z')
A = z^127
B = z^127
print(S(A*B))
z^127 + z^126 + z^12 + z^6 + z^5 + z^2 + z + 1 #출력 결과
16바이트를 기준으로 0x00000000000000000000000000000001을 입력합니다.
결과값으로 0xe6080000000000000000000000000003을 얻었습니다.
\( 1110\ 0110\ 0000\ 1000 || 0^{108} || 0011 \) 으로 표현할 수 있고 이는 sage에서 얻은 결과와 동일한 것을 확인할 수 있습니다.
입력값을 여러 번 다르게 입력하여 곱셈 결과가 맞는지 확인합니다. (한두 번은 우연히 맞을 수 있기에)
이상으로 GCM 모드의 이진유한체 곱셈 방법과 확인 과정을 알아보았습니다.