免费做A爰片久久毛片A片下载_中文欧美三级精品_免费一级少妇A片无码专区_日韩亚洲三级片在线视频_国产熟女Aa级毛片_无码亚中文字幕2021_亚洲国产精品不卡在线观看_成人欧美一区二区三区1314_日本午夜精品理论片a级_337p日本欧洲亚洲大胆

網(wǎng)站導(dǎo)航

首頁(yè) > 解決方案 > 技術(shù)點(diǎn)滴

技術(shù)點(diǎn)滴

2018-07-11 用OpenSSL 做HMAC(C++)

參考:http://www.askyb.com/cpp/openssl-hmac-hasing-example-in-cpp/


名詞解釋?zhuān)?/b>

HMAC: Hash-based Message Authentication Code,即基于Hash的消息鑒別碼


(下面的algo_hmac.h, algo_hmac.cpp 可以直接拿來(lái)放到自己的工程中)

本文工程在這里下載

algo_hmac.h

1.  #ifndef _ALGO_HMAC_H_

2.  #define _ALGO_HMAC_H_

3.   

4.  int HmacEncode(const char * algo,

5.          const char * key, unsigned int key_length,

6.          const char * input, unsigned int input_length,

7.          unsigned char * &output, unsigned int &output_length);

8.   

9.  #endif

algo_hmac.cpp

1.  #include "algo_hmac.h"

2.  #include

3.  #include

4.  #include

5.  using namespace std;

6.   

7.  int HmacEncode(const char * algo,

8.                  const char * key, unsigned int key_length,

9.                  const char * input, unsigned int input_length,

10.                unsigned char * &output, unsigned int &output_length) {

11.        const EVP_MD * engine = NULL;

12.        if(strcasecmp("sha512", algo) == 0) {

13.                engine = EVP_sha512();

14.        }

15.        else if(strcasecmp("sha256", algo) == 0) {

16.                engine = EVP_sha256();

17.        }

18.        else if(strcasecmp("sha1", algo) == 0) {

19.                engine = EVP_sha1();

20.        }

21.        else if(strcasecmp("md5", algo) == 0) {

22.                engine = EVP_md5();

23.        }

24.        else if(strcasecmp("sha224", algo) == 0) {

25.                engine = EVP_sha224();

26.        }

27.        else if(strcasecmp("sha384", algo) == 0) {

28.                engine = EVP_sha384();

29.        }

30.        else if(strcasecmp("sha", algo) == 0) {

31.                engine = EVP_sha();

32.        }

33.        else if(strcasecmp("md2", algo) == 0) {

34.                engine = EVP_md2();

35.        }

36.        else {

37.                cout << "Algorithm " << algo << " is not supported by this program!" << endl;

38.                return -1;

39.        }

40.

41.        output = (unsigned char*)malloc(EVP_MAX_MD_SIZE);

42.

43.        HMAC_CTX ctx;

44.        HMAC_CTX_init(&ctx);

45.        HMAC_Init_ex(&ctx, key, strlen(key), engine, NULL);

46.        HMAC_Update(&ctx, (unsigned char*)input, strlen(input));        // input is OK; &input is WRONG !!!

47.

48.        HMAC_Final(&ctx, output, &output_length);

49.        HMAC_CTX_cleanup(&ctx);

50.

51.        return 0;

52.}

main.cpp

1.  #include "algo_hmac.h"

2.  #include

3.  #include

4.  #include

5.  #include

6.  #include

7.  using namespace std;

8.   

9.  int main(int argc, char * argv[])

10.{

11.        if(argc < 2) {

12.                cout << "Please specify a hash algorithm!" << endl;

13.                return -1;

14.        }

15.

16.        char key[] = "012345678";

17.        string data = "hello world";

18.

19.        unsigned char * mac = NULL;

20.        unsigned int mac_length = 0;

21.

22.        int ret = HmacEncode(argv[1], key, strlen(key), data.c_str(), data.length(), mac, mac_length);

23.

24.        if(0 == ret) {

25.                cout << "Algorithm HMAC encode succeeded!" << endl;

26.        }

27.        else {

28.                cout << "Algorithm HMAC encode failed!" << endl;

29.                return -1;

30.        }

31.

32.        cout << "mac length: " << mac_length << endl;

33.        cout << "mac:";

34.        for(int i = 0; i < mac_length; i++) {

35.                printf("%-03x", (unsigned int)mac[i]);

36.        }

37.        cout << endl;

38.

39.        if(mac) {

40.                free(mac);

41.                cout << "mac is freed!" << endl;

42.        }

43.

44.        return 0;

45.}

Makefile

1.  LNK_OPT = -g -L/usr/lib64/ -lssl

2.   

3.  all:

4.         g++ -g -c algo_hmac.cpp

5.         g++ -g main.cpp -o test algo_hmac.o $(LNK_OPT)

6.   

7.  clean:

8.         rm -f *.o

9.         rm -f test

運(yùn)行結(jié)果

1.  [root@ampcommons02 hmac]# ./test sha1

2.  Algorithm HMAC encode succeeded!

3.  mac length: 20

4.  mac:e1 9e 22 1  22 b3 7b 70 8b fb 95 ac a2 57 79 5  ac ab f0 c0

5.  mac is freed!

6.   

7.  [root@ampcommons02 hmac]# ./test sha256

8.  Algorithm HMAC encode succeeded!

9.  mac length: 32

10.mac:8b 4c 3e 7  ad 88 7a 8a 81 d0 80 ce d7 a3 bb 27 db a6 53 5f 28 fd 5e f1 45 2a 40 a6 e9 66 80 42

11.mac is freed!

12.

13.[root@ampcommons02 hmac]# ./test sha512

14.Algorithm HMAC encode succeeded!

15.mac length: 64

16.mac:40 81 e3 29 1e ec 15 4  91 10 e3 b8 d3 af 74 78 20 d1 c5 b5 39 f3 7b d7 72 49 a6 3c aa a6 e5 82 83 1  ae 2b 34 46 b1 ee 1c 45 39 d4 18 a6 4b 44 12 22 9f 9d 7  8e dc c7 8  8b 3b 41 b9 3c e6 e3

17.mac is freed!

18.

19.[root@ampcommons02 hmac]# ./test md5

20.Algorithm HMAC encode succeeded!

21.mac length: 16

22.mac:49 d5 2c b  92 54 b8 65 2b ea af fc 8d 7e 4c 21

23.mac is freed!

各種算法得到的摘要的長(zhǎng)度

算法

摘要長(zhǎng)度(字節(jié))

MD2

16

MD5

16

SHA

20

SHA1

20

SHA224

28

SHA256

32

SHA384

48

SHA512

64










注意

1)參考的帖子中的hmac_sample1.cpp,第13行沒(méi)有為digest申請(qǐng)空間,結(jié)果在第25行之后,做free(digest)會(huì)crash!但是,即使在第13行申請(qǐng)了足夠的空間,比如1024字節(jié),在第25行之后free(digest)還是會(huì)crash,原因如下:

參考 hmac.c 實(shí)現(xiàn)代碼, 如果傳入的 md 和 md_len 是NULL,則 HMAC 返回的是該函數(shù)里面定義的 static 的buffer的地址 m。這樣的m,由于是靜態(tài)分配的,不能在外面 free。

1.  unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len,

2.      const unsigned char *d, int n, unsigned char *md,

3.      unsigned int *md_len)

4.  {

5.         HMAC_CTX c;

6.         static unsigned char m[EVP_MAX_MD_SIZE];

7.   

8.         if (md == NULL) md=m;

9.         HMAC_CTX_init(&c);

10.       HMAC_Init(&c,key,key_len,evp_md);

11.       HMAC_Update(&c,d,n);

12.       HMAC_Final(&c,md,md_len);

13.       HMAC_CTX_cleanup(&c);

14.       return(md);

15.}

因此,建議使用 md, md_len 參數(shù)作為傳出值!

2)參考的帖子中的hmac_sample1.cpp,第23行的 mdString[i*2] 越界了,因?yàn)榈?/b>22行只申請(qǐng)了20字節(jié),應(yīng)改成 mdString[i]。

3)參考的帖子中的hmac_sample2.cpp,第17行有為result申請(qǐng)空間,在第36行做free(result)操作不會(huì)crash。但是根據(jù)上面表格所列的各種算法的摘要長(zhǎng)度,最大的長(zhǎng)度為64,于是申請(qǐng)的空間的大小可以用Openssl中的常量EVP_MAX_MD_SIZE,它的值就是64

4)參考的帖子中的hmac_sample2.cpp,17行為result申請(qǐng)空間的操作,可以封裝到HmacEncode() 函數(shù)里面,使用者不用關(guān)心究竟要分配多少空間,傳進(jìn)一個(gè)指針即可,用完后free 它就可以了

5)HmacEncode 函數(shù)的output_length 參數(shù)是傳出參數(shù),HmacEncode 執(zhí)行結(jié)束后,會(huì)傳出HMAC的長(zhǎng)度

6)發(fā)現(xiàn)一個(gè)問(wèn)題:對(duì)于main() 中傳給HmacEncode() 的參數(shù)input,如果它的長(zhǎng)度≤56,那么如果其他參數(shù)不變的話,每次計(jì)算得到的結(jié)果是一致的;在其他參數(shù)不變的情況下,如果input的長(zhǎng)度大于56,則每次計(jì)算的結(jié)果是不一致的!也就是說(shuō),這里給成的代碼,對(duì)于長(zhǎng)度≤56字節(jié)的待編碼字串,每次執(zhí)行的結(jié)果是一致的,但對(duì)于長(zhǎng)度大于56字節(jié)的待編碼字串,不能保證輸出結(jié)果的一致性!難道說(shuō),algo_hmac.cpp中第43行的HMAC_Update() 有可能要執(zhí)行多次多次,即,把input按56個(gè)字節(jié)為一段的方式分成多段,多所有的分段依次調(diào)用HMAC_Update()?事實(shí)證明,原因不在于此。

對(duì)于6)的問(wèn)題,后來(lái)發(fā)現(xiàn),如果把const char * input 輸入?yún)?shù)去掉,把char data[] = "hello world";寫(xiě)在HmacEncode 里面,就不存在5)的問(wèn)題。出錯(cuò)的根本原因在于:

HMAC_Update() 函數(shù)的第二個(gè)參數(shù)是const unsigned char *類(lèi)型的,而不是 const unsigned char ** data 類(lèi)型的:int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, int len); 之所以參考的帖子中,以及把char data[] = "hello world";寫(xiě)在HmacEncode 里面,沒(méi)有出錯(cuò),是因?yàn)椋?b>對(duì)于數(shù)組char data[],用指針形式輸出data &data,值是一樣的;而對(duì)于char * p,用指針形式輸出p &p,值是不一樣的!對(duì)于數(shù)組char data[]&data仍然可以作為const unsigned char *類(lèi)型變量傳給HMAC_Update() 函數(shù),傳入的值不變;而對(duì)于 char * p,&p 實(shí)際上已經(jīng)是 char ** 類(lèi)型的了,并且它值和p 不一樣,實(shí)際上,這個(gè)臨時(shí)變量p的地址在程序每次運(yùn)行時(shí)都是不一樣的,于是,每次實(shí)際上傳給HMAC_Update() 函數(shù)的東西都是變化的,怪不得每次執(zhí)行的最終結(jié)果都不一樣了?。?b>上面貼的algo_hmac.cpp中的代碼是沒(méi)有問(wèn)題的,但請(qǐng)注意第46行的注釋?zhuān)?/b>)


- 中巨偉業(yè) -

rRrHPm8F99IT6UWU7gnazcza2KIiTiW6vCSJAXQ2KzPKQgBTrje+/l8aAHBU2OBASNye7qaELt+YMhjXL0RngIwNltw51m63