Message Digest, FingerPrint - WindyHana's Solanara

목차

개요

1) How to Break MD5 and Other Hash Functions

digest 커맨드

OpenSSL의 해시함수

libmd를 사용한 구현

MD라이브러리(솔라리스 10 이상)를 이용해 MD5와 SHA1, SHA2 계산 프로그램을 구현했다. 솔라리스 기본 라이브러리에서는 SHA-224를 지원하지 않는다.
digest_solaris.c
 다운로드 (4,549 바이트)
/*
	Hash(MD5, SHA-1, SHA-2) Sample - by using solaris MD library
	WindyHana's Solanara http://www.solanara.net/
	cc -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -lmd -m64 -fast -o digest_solaris digest_solaris.c
 */

#include <md5.h>
#include <sha1.h>
#include <sha2.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#define BUF_SIZE (64 * 1024)

void printusage(char* argv[]) {
    printf("\n");
    printf("Digest Utility for Solaris v3\n");
    printf("	- with Solaris MD Library.\n");
#if _FILE_OFFSET_BITS - 0 == 64
    printf("	- with support 64 bit file offset.\n");
#endif
    printf("Copyright (C) Jo HoSeok 2005-2011. All rights reserved.\n");
    printf("\n");
    printf("USEAGE:\n");
    printf("	%s [-a algorithm] [-h] FILENAME\n", argv[0]);
    printf("\n");
    printf("	-a algorithm: md5, sha1, sha256, sha384, sha512. default: sha256\n");
    printf("	-h: Help(this screen)\n");
    printf("\n");
    printf("OUTPUT:\n");
    printf("	DIGEST_MESSAGE ALGORITHM FILESIZE\n");
    printf("EXAMPLE:\n");
    printf("	%s -a sha256 /bin/ls\n", argv[0]);
    printf("\n");
}

int main(int argc, char* argv[])
{
	int alg = 3;               // algorithm number. 1=MD5, 2=SHA1, 3=SHA256, 4=SHA384, 5=SHA512
	char * algname = "sha256"; // algorithm name.
	FILE * fp = NULL;

	int c, errflg = 0; // getopt 에서 사용하는 임시 변수
	while ((c = getopt(argc, argv, ":ha:")) != -1) {
		switch(c) {
		case 'a':
			if (strcmp("md5", optarg) == 0) {
				alg = 1;
				algname = "md5";
			} else if (strcmp("sha1", optarg) == 0) {
				alg = 2;
				algname = "sha1";
			} else if (strcmp("sha256", optarg) == 0) {
				alg = 3;
				algname = "sha256";
			} else if (strcmp("sha384", optarg) == 0) {
				alg = 4;
				algname = "sha384";
			} else if (strcmp("sha512", optarg) == 0) {
				alg = 5;
				algname = "sha512";
			} else {
				fprintf(stderr, "illegal argument: -%c %s\n", optopt, optarg);
				errflg++;
			}
			break;
		case 'h':
			printusage(argv);
			return 0;
		case ':':
			if (optopt == '-') {
				fprintf(stderr, "%s option requires an argument.\n", argv[optind-1]);
			} else {
				fprintf(stderr, "-%c option requires an argument.\n", optopt);
			}
			errflg++;
			break;
		case '?':
			if (isprint(optopt)) {
				fprintf(stderr, "illegal option: -%c\n", optopt);
			} else {
				fprintf(stderr, "illegal option: \\x%x.\n", optopt);
			}
			errflg++;
			break;
		}
	}

	if (errflg > 0) {
		printusage(argv);
		return 1;
	}

	if (optind < argc) {
		fp = fopen(argv[optind], "rb");
		if (!fp) {
			fprintf(stderr, "Cannot Open %s.\r\n", argv[optind]);
			return 1;
		}
	} else {
		printusage(argv);
		return 0;
	}

	unsigned char* auth_buffer; // 버퍼
	char* hex_output;           // 결과값을 헥스 값으로 변환한 값. + 1 은 null 값
	long long  offset = 0;
	off_t      readcount;       // 읽은 바이트수, 파일 오프셋 위치
	int result_msgcnt = 0;
	auth_buffer = (void *) malloc(BUF_SIZE); // 버퍼
	if (alg == 1) {
		MD5_CTX    md5_context;     // MD5 컨텍스트 값

		MD5Init(&md5_context);
		while (readcount = fread(auth_buffer, 1, BUF_SIZE, fp)) {
			offset += readcount;
			MD5Update(&md5_context, auth_buffer, readcount);
		}
		MD5Final(auth_buffer, &md5_context);
		
		hex_output = malloc(16*2 + 1);
		result_msgcnt = 16;
	} else if (alg == 2) {
		SHA1_CTX   sha1_context;    // SHA1 컨텍스트 값

		SHA1Init(&sha1_context);
		while (readcount = fread(auth_buffer, 1, BUF_SIZE, fp)) {
			offset += readcount;
			SHA1Update(&sha1_context, auth_buffer, readcount);
		}
		SHA1Final(auth_buffer, &sha1_context);
		
		hex_output = malloc(20*2 + 1);
		result_msgcnt = 20;
	} else if (alg == 3 || alg == 4 || alg == 5) {
		SHA2_CTX   sha2_context;    // SHA2 컨텍스트 값
		if (alg == 3) {
			SHA2Init(SHA256, &sha2_context);
			hex_output = malloc(32*2 + 1);
			result_msgcnt = 32;
		} else if (alg == 4) {
			SHA2Init(SHA384, &sha2_context);
			hex_output = malloc(48*2 + 1);
			result_msgcnt = 48;
		} else if (alg == 5) {
			SHA2Init(SHA512, &sha2_context);
			hex_output = malloc(64*2 + 1);
			result_msgcnt = 64;
		}
		while (readcount = fread(auth_buffer, 1, BUF_SIZE, fp)) {
			offset += readcount;
			SHA2Update(&sha2_context, auth_buffer, readcount);
		}
		SHA2Final(auth_buffer, &sha2_context);
	}

	fclose(fp);

	// 16진수로 표현
	int i;
	for (i = 0; i < result_msgcnt; i++) {
		sprintf(hex_output + i * 2, "%02x", auth_buffer[i]);
	}
	printf("%s %s %lld\n", hex_output, algname, offset);

	free(auth_buffer);
	free(hex_output);
	return 0;
}
root@wl ~ # cc -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -lmd -m64 -fast -o digest_solaris digest_solaris.c

FingerPrint

※ 말 그대로 [지문]이다. 솔라리스에 설치된 파일에 대해, 이 파일이 변조되었는지 MD5해시값을 통해 확인할 수 있다. 어떤 파일인지 어떤 패키지인지, 어떤 패치를 설치했는지 나온다.
root@wl ~ $ digest -a md5 /bin/sh
4918cc526b37468c04c702100b1da7dd
root@wl ~ $
Solaris Fingerprint Database An Identification Tool for Solaris Software and Files 에서 MD5해시값을 입력하면 아래와 같이 나온다.
4918cc526b37468c04c702100b1da7dd - - 1 match(es) 
	canonical-path: /sbin/sh 
	package: SUNWcsr 
	version: 11.10.0,REV=2005.01.21.16.34 
	architecture: i386 
	source: Solaris 10/x86 
	patch: 138254-02 

컴파일러 옵션에 따른 성능

  1. 최적화된 옵션

    컴파일시 -fast 옵션을 붙이느냐 안 붙이느냐에 따라 성능에 차이가 있다. 보통 CPU의 캐시 메모리 및 인스트럭션 셋에 맞춰 컴파일 해준다. 또한 -m64 를 붙인 경우 64bit로 컴파일한다.
    root@wl ~ # cc -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -lmd5 -lmd -m64 -fast -o digest_solaris digest_solaris.c
    root@wl ~ # time ./digest_solaris -a sha1 4GFile
    1bf99ee9f374e58e201e4dda4f474e570eb77229 4294967296 sha1
    
    real    0m47.042s
    user    0m17.512s
    sys     0m2.486s
    
  2. 솔라리스 10 기본 소프트웨어

    참고삼아 솔라리스 10에 들어있는 기본 툴에 대해 재어보았다.
    root@wl ~ # time digest -a sha1 4GFile
    1bf99ee9f374e58e201e4dda4f474e570eb77229
    
    real    1m0.908s
    user    0m25.883s
    sys     0m13.137s
    
Twitter RSS IconTexto 올바른 XHTML 1.0 Transitional 입니다 올바른 CSS입니다!