728x90

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 전체 구조

 

 

SHA-1은 메시지 길이에 상관없이 512비트씩 잘라서 메시지 다이제스트 함수를 돌린 뒤 160비트의 출력을 낸다.

 

원본 메시지 + 패딩 + 원본 메시지 길이(64비트) 가 512비트의 배수가 되도록 만든다. (메시지가 없어도 한다.)

 

패딩은 맨 뒤 64비트에는 메시지 전체 길이를 넣고 나머지 비트는 최상위 비트 1을 제외하고 0으로 채운다.

 

메시지가 512비트보다 길 경우 다음 번 메시지 다이제스트 함수의 입력으로 전 함수의 출력을 받는다.

 

맨 앞 초기값 ABCDE는 정해진 상수값이다.

 

초기값 160bit

 


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상에서의 덧셈을 한다.

 

그 값이 메시지 다이제스트 함수의 최종 출력값이 된다.

 

각 라운드

   

라운드별 F함수

 

 

각 라운드는 위 그림과 같이 구성되는데 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의 생성방법

 

 

Wt는 입력블록을 32비트씩 잘라 16개의 W0~W15를 만들고 이를 이용하여 W79까지 생성할 수 있다.

 

라운드 상수 Kt

 


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]);
}

 

 

728x90

'프로그래밍 > 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

+ Recent posts