2015年8月4日 星期二

[Linux C] C語言MD5雜湊運算教學

本篇稍為記錄一下如何使用openssl的library快速的做MD5雜湊運算。

--

首先,要在C語言計算MD5,有一些公開的library可以幫助我們快速計算一些雜湊運算,當然MD5也是被包含在內的。

這邊介紹使用OpenSSL,基本上這個package在各版本的linux上的package list內都找的到。

筆者本次是使用Ubuntu 15.04版本,所以像我就是使用 sudo apt-get install openssl 快速透過package manager安裝。

基本上使用方法很簡單,步驟就是



  1. MD2_Init(MD2_CTX *c) :初始化 MD2_CTX 結構.
  2. MD2_Update(MD2_CTX *c, const unsigned char *data,           unsigned long len) :更新hash値,若是資料量大於你設計的buffer,可以多次呼叫此函式來更新MD5的hash値
  3. MD2_Final(unsigned char *md, MD2_CTX *c):將MD5的計算結果儲存於md並且把MD2_CTX釋放掉。


接下來就是使用文字編輯器寫一個簡單的範例吧!

假如我想要計算『Hello Ni hao ma?』這個字串的MD5,我們透過線上MD5計算機可以得到:


接下來看我的範例程式輸出的MD5碼會是如何吧!程式碼如下

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


#define KGRN "\033[0;32;32m"
#define RESET "\033[0m"


void printf_md5(unsigned char *in)
{
 int i;
 for(i = 0 ; i < MD5_DIGEST_LENGTH ; i++) {
  if ( in[i] < 0x10)
   printf("0%1x", in[i]);
  else
   printf("%2x", in[i]);
 }

 printf("\n"RESET);
}

int main(void)
{
 const char *path = "Hello Ni hao ma?";

 unsigned char digest[MD5_DIGEST_LENGTH];

 MD5_CTX context;
 MD5_Init(&context);
 MD5_Update(&context, path, strlen(path));
 MD5_Final(digest, &context);

 printf(KGRN"path '%s' md5:", path);
 printf_md5(digest);

 return 0;

}

將上述程式碼存成.c檔後,編譯時要記得對library做link唷!例如
gcc md5.c -o md5 -lcrypto

這裡比較需要注意到的是雖然該檔案是放在openssl底下,但是稍微看一下openssl/md5.h裡面,發現要link的是libcrypto.so唷


執行結果


輸出的md5碼與計算機的相同!


--

2015/08/06補充:

下面分享一段程式,編譯完成之後可以直接將檔案路徑當成參數代入,就會將該檔案讀取併計算各字的md5囉!

程式碼如下:

#include <stdio.h>
#include <string.h>
#include <openssl/md5.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#ifdef DEBUG
#ifndef MYDEBUG
#define MYDEBUG
#define debug(x)    x
#define KRED "\033[0;32;31m"
#define KRED_L "\033[1;31m"
#define KGRN "\033[0;32;32m"
#define KGRN_L "\033[1;32m"
#define KBLU "\033[0;32;34m"
#define KBLU_L "\033[1;34m"
#define KGRY "\033[1;30m"
#define KGRY_L "\033[0;37m"
#define KCYN "\033[0;36m"
#define KCYN_L "\033[1;36m"
#define KMAG "\033[0;35m"
#define KMAG_L "\033[1;35m"
#define KBRN "\033[0;33m"
#define KYEL "\033[1;33m"
#define WHITE "\033[1;37m"
#define RESET "\033[0m"
#endif
#else
#define debug(x)
#endif

static void printf_md5(unsigned char *in)
{
    int i;
    for(i = 0 ; i < MD5_DIGEST_LENGTH ; i++) {
        if ( in[i] < 0x10)
            printf("0%1x", in[i]);
        else
            printf("%2x", in[i]);
    }
    
    printf("\n"RESET);
}

int main(int argc, char *argv[])
{
    int fd, sum, i;
    char buf[1024];
    unsigned char digest[MD5_DIGEST_LENGTH];


    if (argc <= 1) {
        debug( printf("Please input the filepath that you want to calculate.\n"); );
        return -1;
    }

    // c
    for(i = 1; i < argc; i++) {

        fd = open(argv[i], O_RDONLY, S_IRUSR);
        
        if (fd < 0 ) {
            debug( printf("Opening file:%s error.\n", argv[i]); );
            continue;
        } else {
            sum = 0;
            int len, n;
            memset(digest, 0, sizeof(buf));
            memset(buf, 0 , sizeof(buf));

            len = lseek( fd, 0, SEEK_END);
            lseek(fd, 0, SEEK_SET);

            MD5_CTX context;
            MD5_Init(&context);

            while (sum < len) {
                
                n = read( fd, buf, sizeof(buf));

                MD5_Update(&context, buf, n);
                
                sum += n;

            }
            MD5_Final(digest, &context);
            
            debug(printf(KGRN"file:%s md5:", argv[i]););
            printf_md5(digest);
            close(fd);
        }
    
    }

    return 0;
}

--

 編譯方法  
 gcc md5checker.c -o md5checker -lcrypto -DDEBUG
    
-- 

執行方法  
 ./md5checker  /home/a/test1.txt  /home/a/test2.txt  /home/a/test3.txt  
 
--  

執行結果



特別注意:在不同環境(Linux/Windows/OS) 生成的文件,請注意換行符號的問題唷

1 則留言: