摘要算法:使用 openssl 實作 md5、sha256 等
相關連結:
摘要算法:MD5 及 Java實作樣例
摘要算法:SHA 及 Java 實作樣例
本文主要介紹如何使用 openssl 庫實作 md5、sha256 摘要算法。
Case 1:md5
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
int main(int argc, char *argv[])
{
EVP_MD_CTX mdctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
int md_len, i;
OpenSSL_add_all_digests();
/*********************************************************************/
char *algorithm = "md5";
char *msg = "0123456789abcdef";
md = EVP_get_digestbyname(algorithm);
if(!md) {
fprintf(stderr, "Unknown message digest %s\n", algorithm);
exit();
}
EVP_MD_CTX_init(&mdctx);
EVP_DigestInit_ex(&mdctx, md, NULL);
EVP_DigestUpdate(&mdctx, msg, strlen(msg));
EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
EVP_MD_CTX_cleanup(&mdctx);
for(i = ; i < md_len; i++) {
fprintf(stdout, "%02x", md_value[i]);
}
fprintf(stdout, "\n");
return ;
}
編譯 && 執行:
$ gcc -o main main.c -lssl
$ ./main
af8d61035123906e58e067140cc5
PS:摘要散列值以十六進制小寫字元串表示。
可以将 algorithm 改為sha256、sha224、sha512 等值以實作不同摘要算法。
Case 2:sha224
更新:
char *algorithm = "sha224";
編譯 && 執行:
$ gcc -o main main.c -lssl
$ ./main
f6741fd2bacbd3658681a70f65e2e90a02887989018974ce8
關于 openssl 的兩個函數:
int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt);
EVP_DigestUpdate() hashes cnt bytes of data at d into the digest context ctx.
This function can be called several times on the same ctx to hash additional data.
int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s);
EVP_DigestFinal_ex() retrieves the digest value from ctx and places it in md.
If the s parameter is not NULL then the number of bytes of data written (i.e. the length of the digest) will be written to the integer at s, at most EVP_MAX_MD_SIZE bytes will be written.
After calling EVP_DigestFinal_ex() no additional calls to EVP_DigestUpdate() can be made, but EVP_DigestInit_ex() can be called to initialize a new digest operation.
我們可以多次調用 EVP_DigestUpdate() 來 append 待摘要的資料到末尾,并通過調用 EVP_DigestFinal_ex 擷取最後結果。
例如:
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
int main(int argc, char *argv[])
{
EVP_MD_CTX mdctx;
const EVP_MD *md;
unsigned char md_value[EVP_MAX_MD_SIZE];
int md_len, i;
OpenSSL_add_all_digests();
/*********************************************************************/
char *algorithm = "md5";
char *msg1 = "0123";
char *msg2 = "4567";
char *msg3 = "89ab";
char *msg4 = "cdef";
md = EVP_get_digestbyname(algorithm);
if(!md) {
fprintf(stderr, "Unknown message digest %s\n", algorithm);
exit();
}
EVP_MD_CTX_init(&mdctx);
EVP_DigestInit_ex(&mdctx, md, NULL);
EVP_DigestUpdate(&mdctx, msg1, strlen(msg1));
EVP_DigestUpdate(&mdctx, msg2, strlen(msg2));
EVP_DigestUpdate(&mdctx, msg3, strlen(msg3));
EVP_DigestUpdate(&mdctx, msg4, strlen(msg4));
EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
EVP_MD_CTX_cleanup(&mdctx);
for(i = ; i < md_len; i++) {
fprintf(stdout, "%02x", md_value[i]);
}
fprintf(stdout, "\n");
return ;
}
等價于上面的一次性傳入完成的待摘要的資料。
編譯 && 執行:
$ gcc -o main main.c -lssl
$ ./main
af8d61035123906e58e067140cc5
注意:
上面的示例代碼其實并不嚴謹,使用了 strlen 去對待摘要資料計算長度,這裡限制了待摘要資料一定不能包含 0x00 位元組。
實際上,待摘要資料并無此限制,待摘要資料可以包含任意資料(包括 0x00),并由最後的長度參數指明資料長度。
待摘要資料是任意的二進制資料,可讀的字元串隻是其中一種,還有不可讀的圖檔、音頻、檔案等形式。使用 strlen 将有問題。