1. 개요

MD5(Message-Digest algorithm 5)는 Hash Function의 한 종류이다. Hash Function은 키가 없고 복호화를 할 수 없는 특성을 지니고 있다. 

MD5는 MD4를 수정한 것으로 MIT의 Ronald Lorin Rivest가 개발하였으며 임의의 메시지 길이로부터 128비트의 해시 값을 생산한다. 1996년에 설계상 결함이 발견되었고 이후 SHA 계열을 주로 사용하게 되었다.

사실 MD5는 MD의 다섯 번째 버전이다. MD2(RFC 1319)는 1989년에 개발되었으며 8bit 컴퓨터에 적합한 알고리즘이다. 또 MD4(RFC 1320)는 1990년에 개발되었으며 이후 MD5, SHA-1 등에 영향을 주었다.

단방향 암호화 기법이지만 단시간내에 쉽게 풀어낼 수 있는 상황이 되었으므로 암호화 목적으로는 사용할 수 없다고 해도 무방하다.


2. 단계 

MD5는 5단계를 거치는데 각 단계는 다음과 같다.

2-1. Append Padding Bits

MD5는 512비트 단위로 알고리즘을 수행하기 때문에 512비트로 나눠지도록 메시지 길이를 맞춰야 한다. 만약 메시지가 512비트라도 패딩하여 1024비트가 되도록 해야 한다. 다만 64비트를 비워두고 패딩해야 한다. 이 비워진 공간에 2) 단계에서 메시지 길이를 추가해야 하기 때문이다.

예1) 입력 메시지의 길이가 448비트인 경우 : 512비트 기준 64비트를 비우면 패딩할 수 없으므로 512비트를 더해 960비트로 만든다.

예2) 입력 메시지의 길이가 400비트인 경우 : 48비트만 패딩하여 448비트로 만든다.

2-2. Append Length

원 메시지의 길이를 나타내는 64비트 정수(integer)를 첨가한다. 따라서 원 메시지의 길이가 2의 64승보다 크다면 2의 64승으로 표현 가능한 값을 사용한다. 이렇게 1, 2단계에 의해 512비트의 정수배 길이의 메시지를 획득한다.

2-3. Initialze MD Buffer

MD5는 128비트의 해시 값을 생산하는데 해시 값 계산 시 각 단계마다 4개의 워드, 즉 32비트 레지스터(각각 A, B, C,D라고 부름)를 사용한다. 4개 레지스터는 각각 다음과 같은 16진수 상수 값으로 초기화되어 있다.

  • A : 01 23 45 67
  • B : 89 ab cd ef
  • C : fe dc ba 98
  • D : 76 54 32 10

이 때 워드는 작은 단위의 바이트가 먼저 저장된 형태, 즉 little-endian이다.

2-4. Process Message in 16-word blocks

512비트 블록 단위로 실제 Message Digest를 수행하는 과정이다.

2-5. Output

A, B, C, D의 값을 연결하여 128비트 출력을 획득한다.


3. 예제

3-1. C언어 예제 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/md5.h>
 
char *str2md5(const char *str, int length) {
  int n;
  MD5_CTX c;
  unsigned char digest[16];
  char *out=(char*)malloc(33);
 
  MD5_Init(&amp;c);
 
  while ( length > 0 ) {
    if ( length > 512 ) {
      MD5_Update(&amp;c, str, 512);
    } else {
      MD5_Update(&amp;c, str, length);
    }
    length-=512;
    str+=512;
  }
 
  MD5_Final(digest, &amp;c);
 
  for ( n=0; n<16; ++n ) {
    snprintf(&amp;(out[n*2]), 16*2, "%02x", (unsigned int)digest[n]);
  }
 
  return out;
}
 
int main(int argc, char **argv) {
  if ( argv[1] != NULL ) {
    char *output=str2md5(argv[1], strlen(argv[1]));
    printf("MD5 for [%s] = %s\n", argv[1], output);
    free(output);
    return 0;
  } else {
    printf("No Text Argument !\n");
    return 1;
  }
}

[ 실행 ]

$ gcc getMD5.c -o getMD5 -lssl

$ ./getMD5 md5_test_string
MD5 for [md5_test_string] = 0a87306ea08adcdd8467784e072a6846

* 해시란 가변 길이의 데이터를 고정 길이의 문자열로 변환하는 역할을 한다. 복호화가 되지 않으므로 원문을 알 수는 없다.


4. 결과값

MD5는 128비트의 결과값을 생산한다고 했다. 그리고 그것은 32개의 문자로 표현된다고 한다. 그런데 1바이트는 8비트이므로, 128비트라면 32문자가 아닌 16문자로 표현되어야 하는 것이 아니냐는 의문을 가질 수 있다.

이는 MD5가 Hex Digit(16진수 문자)으로 표현하기 때문이다. ISO-8859-1과 같은 일반적인 문자가 2의 8승(=16비트=1바이트)을 필요로 하는데 반해, 16진수를 표현하기 위해서는 단지 2의 4승(=8비트)가 필요할 뿐이다.

이는 Hex Digit으로 표현하는 SHA-1, SHA-512 등 모두 마찬가지이다.

  • SHA-1 = 160비트 = 40 Hex Digit
  • SHA-512 = 512비트 = 128 Hex Digit