OpenSSL MD5 사용법 (C/C++)

OpenSSL은 암호화 및 보안 기능을 제공하는 오픈소스(Open Source) 라이브러리로, MD5 (Message-Digest Algorithm 5)해시 관련 함수들을 제공한다. MD5는 임의의 길이의 데이터를 문자열 또는 파일로 입력 받아 고정된 길이의 해시 값을 출력한다. 주로 데이터 무결성 확인이나 패스워드 등의 보안 목적으로 사용된다. 이 글에서는 C/C++ 언어에서 OpenSSL MD5를 사용하는 방법에 대해 알아본다.

OpenSSL 설치

먼저, 시스템에 OpenSSL을 설치한다. 다음은 Ubuntu 기준으로 설치하는 방법이다.

sudo apt-get update
sudo apt-get install libssl-dev

문자열 MD5 해시 생성 예제 (C)

#include <stdio.h>
#include <string.h>
#include <openssl/md5.h>

void md5_string(const char *str) {
    MD5_CTX ctx;
    unsigned char digest[MD5_DIGEST_LENGTH];

    MD5_Init(&ctx);
    MD5_Update(&ctx, str, strlen(str));
    MD5_Final(digest, &ctx);

    printf("MD5(%s) = ", str);
    for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
        printf("%02x", digest[i]);
    }
    printf("\n");
}

int main() {
    const char *input = "Hello, MD5!";
    md5_string(input);

    return 0;
}
  • “Hello, MD5!” 문자열에 대한 md5 값을 출력한다.
$ ./a.out
MD5(Hello, MD5!) = 383e139e64e5f46de9d03ba3695da2d8

파일의 MD5 해시 생성 예제 (C++)

#include <openssl/md5.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdarg>
#include <memory>

/*
 * file utils
 */
bool fileExists(const char *path) {
    std::ifstream is(path);
    return is.good();
}

char* readFile(const char* filePath)
{
    if (!filePath)
        return 0;

    int fd = open(filePath, O_RDONLY);
    if (fd == -1)
        return 0;

    FILE* f = fdopen(fd, "r");
    if (!f) {
        return 0;
    }

    fseek(f, 0L, SEEK_END);
    long sz = ftell(f);
    fseek( f, 0L, SEEK_SET );
    if (sz <= 0) {
        fclose(f);
        return 0;
    }

    char* ptr = new char[sz+1];
    if (!ptr) {
        fclose(f);
        return 0;
    }
    ptr[sz] = 0;

    size_t result = fread(ptr, 1, sz, f);
    if(result != (size_t)sz) {
        fclose(f);
        delete [] ptr;
        return 0;
    }

    fclose(f);

    return ptr;
}

namespace MD5 {

static void printMD5Sum(const char *msg, unsigned char *md)
{
    char md5msg[40];
    for (int i = 0; i < MD5_DIGEST_LENGTH; ++i)
        sprintf(md5msg+(i*2), "%02x", md[i]);
    printf("%s: md5msg : %s\n", msg, md5msg);
}

int getMD5SumFile(const char *path, unsigned char *md)
{
    char *buffer = readFile(path);
    if (buffer == NULL) {
        printf("readFile(%s) failed", path);
        return -1;
    }

    unsigned long bufsize = strlen(buffer);
    MD5_CTX ctx;

    MD5_Init(&ctx);
    MD5_Update(&ctx, (const void*)buffer, (unsigned long)bufsize);
    MD5_Final(md, &ctx);

    delete []buffer;
    return 0;
}

int generateFile(const char *path)
{
    unsigned char md[MD5_DIGEST_LENGTH];

    if (getMD5SumFile(path, md)) {
        return -1;
    }

    std::string md5Path(path);
    md5Path += ".md5";

    std::ofstream ofs;
    ofs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
    try {
        ofs.open(md5Path.c_str(), std::ios::out | std::ios::trunc | std::ios::binary);
    }
    catch (std::system_error& e) {
        printf("md5: generateFile(): open(%s) failed : %s", md5Path.c_str(),
                  e.code().message().c_str());
        return -2;
    }

    ofs.write((const char*)md, (long)MD5_DIGEST_LENGTH);

    ofs.close();
    return 0;
}

bool checkFile(const char *path)
{
    unsigned char md[MD5_DIGEST_LENGTH];
    bool ret = true;

    if (getMD5SumFile(path, md)) {
        printf("getMD5SumFile() fail");
        return false;
    }

    std::string md5Path(path);
    md5Path += ".md5";

    char *data = readFile(md5Path.c_str());
    if (data == NULL) {
        return false;
    }

    /* compare */
    if (memcmp((const void*)md, (const void*)data, (size_t)MD5_DIGEST_LENGTH) != 0) {
        printf("[%s] %s: compare fail\n", __func__, path);
        printMD5Sum("orig", md);
        printMD5Sum("file", (unsigned char*)data);
        ret = false;
    }

    delete []data;
    return ret;
}

} /* namespace MD5 */


int main(int argc, const char *argv[])
{
    char *filepath = (char *)argv[1];
    MD5::generateFile(filepath);
    return 0;
}
  • 입력 받은 파일에 md5 확장자가 더해진 파일을 생성하고, 입력 파일의 MD5 값을 갖도록 한다.
$ ./a.out gen_md5.cpp139e64e5f46de9d03ba3695da2d8
$ hexdump gen_md5.cpp.md5
0000000 efab 2db2 40a5 a3ef cb51 7290 9e9e 19d4
0000010

참고 사이트

답글 남기기