SHA는 Secure Hash Algorithm의 줄임말로 1993년 미국 국가안보국(NSA)에 의해 설계되고 표준으로 지정되었다.
이때 출간된 SHA는 구분상 SHA-0이라하고 2년 뒤인 1995년에 개정된 SHA-1을 발표했고 현재 널리 쓰이는 해쉬 알고리즘이다.
이후 변형 버전인 SHA-2라 불리는 SHA-224, 256, 384, 512가 나왔으며 보통은 SHA-1을 사용하고 더 암호학적 안전을 요하는 곳에는
SHA-2를 사용한다.
SHA-1은 메시지 길이에 상관없이 512비트씩 잘라서 메시지 다이제스트 함수를 돌린 뒤 160비트의 출력을 낸다.
원본 메시지 + 패딩 + 원본 메시지 길이(64비트) 가 512비트의 배수가 되도록 만든다. (메시지가 없어도 한다.)
패딩은 맨 뒤 64비트에는 메시지 전체 길이를 넣고 나머지 비트는 최상위 비트 1을 제외하고 0으로 채운다.
메시지가 512비트보다 길 경우 다음 번 메시지 다이제스트 함수의 입력으로 전 함수의 출력을 받는다.
맨 앞 초기값 ABCDE는 정해진 상수값이다.
void SHA_1(FILE* fptr, BYTE* result) {
int i, size = 0;
BYTE msg[HASH_BLOCK * 2] = { 0, };
UINT64 f_size = 0;
SHA_1_init();
while ((size = fread(msg, sizeof(BYTE), HASH_BLOCK, fptr))) {
f_size += size;
if (size < HASH_BLOCK)
padding(msg, f_size);
SHA_1_digest(msg);
if (isAddpad) SHA_1_digest(msg + HASH_BLOCK);
memset(msg, 0, HASH_BLOCK * 2);
}
for (i = 0; i < HASH_DATA; i++)
result[i] = digest[i];
}
void padding(BYTE* in, UINT64 msg_len)
{
int i;
BYTE* ptr = (BYTE*)&msg_len;
in[msg_len % HASH_BLOCK] = 0x80;
msg_len *= 8;
// 메시지가 448비트 보다 작은 경우와 448비트 보다 큰 경우로 나누어 처리
// 448비트보다 큰 경우에는 512비트의 블록을 추가하여 패딩을 수행한다
if ((msg_len % HASH_BLOCK) < 56)
{
for (i = 0; i<8; i++)
in[HASH_BLOCK - i - 1] = *(ptr + i);
}
else
{
isAddpad = 1;
for (i = 0; i<8; i++)
in[HASH_BLOCK * 2 - i - 1] = *(ptr + i);
}
}
파일을 읽고 크기가 64바이트(512비트)보다 작으면 패딩을 한다. 패딩에서 메시지가 448비트보다 커서 문자열 길이를 담을 수 없는 경우
블록을 하나 더 늘리고 메시지 다이제스트 함수도 한번 더 한다.
메시지 다이제스트 함수는 총 80라운드를 돌며 초기 입력 160비트와 마지막 80번째 라운드의 출력 160비트를 32비트씩 법 2^32상에서의 덧셈을 한다.
그 값이 메시지 다이제스트 함수의 최종 출력값이 된다.
각 라운드는 위 그림과 같이 구성되는데 32비트씩 나누어 A->B', B->C', C->D', D->E'로 간단한데 (B->C'일때 좌측 순환쉬프트 30비트를 해준다.)
E->A'로 할때에는 A의 좌측 순환쉬프트를 5비트해준 값과 B,C,D를 F함수에 넣은 출력값과 E값과 Wt와 라운드 상수 Kt를 법 2^32상에서 덧셈을 하여
구한다. F함수는 오른쪽 그림과 같으며 F2와 F4는 같은 동작을 한다.
Wt는 입력블록을 32비트씩 잘라 16개의 W0~W15를 만들고 이를 이용하여 W79까지 생성할 수 있다.
void SHA_1_digest(BYTE* in) {
int i;
UINT M[16] = { 0, };
UINT W[80] = { 0, };
UINT reg[5] = { 0, };
UINT temp;
reg[0] = init_reg[0];
reg[1] = init_reg[1];
reg[2] = init_reg[2];
reg[3] = init_reg[3];
reg[4] = init_reg[4];
for (i = 0; i < 64; i += 4) {
M[i / 4] = BTOW(in[i], in[i + 1], in[i + 2], in[i + 3]);
}
for (i = 0; i < 80; i++) {
if (i < 16)
W[i] = M[i];
else
W[i] = CIR_SHIFT((W[i - 16] ^ W[i - 14] ^ W[i - 8] ^ W[i - 3]), 1);
}
for (i = 0; i < 80; i++) {
if (i < 20) {
temp = CIR_SHIFT(reg[0], 5) + F1(reg[1], reg[2], reg[3]) + reg[4] + W[i] + K0;
}
else if (i < 40) {
temp = CIR_SHIFT(reg[0], 5) + F2(reg[1], reg[2], reg[3]) + reg[4] + W[i] + K1;
}
else if (i < 60) {
temp = CIR_SHIFT(reg[0], 5) + F3(reg[1], reg[2], reg[3]) + reg[4] + W[i] + K2;
}
else {
temp = CIR_SHIFT(reg[0], 5) + F2(reg[1], reg[2], reg[3]) + reg[4] + W[i] + K3;
}
reg[4] = reg[3];
reg[3] = reg[2];
reg[2] = CIR_SHIFT(reg[1], 30);
reg[1] = reg[0];
reg[0] = temp;
}
init_reg[0] += reg[0];
init_reg[1] += reg[1];
init_reg[2] += reg[2];
init_reg[3] += reg[3];
init_reg[4] += reg[4];
make_Bit160(init_reg[0], init_reg[1], init_reg[2], init_reg[3], init_reg[4]);
}
'프로그래밍 > C++' 카테고리의 다른 글
[C++] Reference Counting (2) | 2020.11.04 |
---|---|
힙(Heap)과 완전 이진 트리(Complete binary tree) (1) | 2019.10.31 |
[c] AES 구조 및 코드 (2) | 2017.11.15 |
[c] DES 구조 및 코드 (21) | 2017.10.26 |
[소켓 프로그래밍] IOCP echo server 예제 (0) | 2016.11.17 |