openssl 编程之DH

转:http://caisenchen.blog.163.com/blog/static/552865502008763598101/

19.1  DH算法介绍

DH算法是W.Diffie和M.Hellman提出的。此算法是最早的公钥算法。它实质是一个通信双方进行密钥协商的协议:两个实体中的任何一个使用自己的私钥和另一实体的公钥,得到一个对称密钥,这一对称密钥其它实体都计算不出来。DH算法的安全性基于有限域上计算离散对数的困难性。离散对数的研究现状表明:所使用的DH密钥至少需要1024位,才能保证有足够的中、长期安全。

首先,发送方和接收方设置相同的大数数n和g,这两个数不是保密的,他们可以通过非安全通道来协商这两个素数;

       接着,他们用下面的方法协商密钥:

发送方选择一个大随机整数x,计算X= g^x mod n ,发送X给接收者;

接收方选择一个大随机整数y,计算Y = g^y mod n ,发送Y给发送方;

双方计算密钥:发送方密钥为k1=Y^x mod n,接收方密钥为k2=X^y mod n。

其中k1=k2=g^(xy) mod n。

其他人可以知道n、g、X和Y,但是他们不能计算出密钥,除非他们能恢复x和y。DH算法不能抵御中间人攻击,中间人可以伪造假的X和Y分别发送给双方来获取他们的秘密密钥,所以需要保证X和Y的来源合法性。

19.2  openssl的DH实现

       Openssl的DH实现在crypto/dh目录中。各个源码如下:

       1)  dh.h

              定义了DH密钥数据结构以及各种函数。

       2)    dh_asn1.c

              DH密钥参数的DER编解码实现。

       3)  dh_lib.c

              实现了通用的DH函数。

       4)  dh_gen.c

              实现了生成DH密钥参数。

       5)  dh_key.c

实现openssl提供的默认的DH_METHOD,实现了根据密钥参数生成DH公私钥,以及根据DH公钥(一方)以及DH私钥(另一方)来生成一个共享密钥,用于密钥交换。

       6)dh_err.c

              实现了DH错误处理。

       7)  dh_check.c

              实现了DH密钥检查。

19.3数据结构

DH数据结构定义在crypto/dh/dh.h中,主要包含两项,如下:

1)    DH_METHOD

       struct dh_method

       {

              const char *name;

int (*generate_key)(DH *dh);

              int (*compute_key)(unsigned char *key,const BIGNUM *pub_key,DH *dh);

              int (*bn_mod_exp)(const DH *dh, BIGNUM *r, const BIGNUM *a,

                            const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,

                            BN_MONT_CTX *m_ctx);

              int (*init)(DH *dh);

              int (*finish)(DH *dh);

              int flags;

              char *app_data;

              int (*generate_params)(DH *dh, int prime_len, int generator, BN_GENCB *cb);

       };

       DH_METHOD指明了一个DH密钥所有的计算方法函数。用户可以实现自己的DH_METHOD来替换openssl提供默认方法。各项意义如下:

name:DH_METHOD方法名称。

generate_key:生成DH公私钥的函数。

compute_key:根据对方公钥和己方DH密钥来生成共享密钥的函数。

       bn_mod_exp:大数模运算函数,如果用户实现了它,生成DH密钥时,将采用用户实现的该回调函数。用于干预DH密钥生成。

       init:初始化函数。

       finish:结束函数。

       flags:用于记录标记。

       app_data:用于存放应用数据。

       generate_params:生成DH密钥参数的回调函数,生成的密钥参数是可以公开的。

2)    DH

struct dh_st

       {

              /* 其他 */

              BIGNUM *p;

              BIGNUM *g;

              long length; /* optional */

              BIGNUM *pub_key;

              BIGNUM *priv_key;

              int references;

              CRYPTO_EX_DATA ex_data;

              const DH_METHOD *meth;

              ENGINE *engine;

              /* 其他 */

       };

       p、g、length:DH密钥参数;

       pub_key:DH公钥;

       priv_key:DH私钥;

       references:引用;

       ex_data:扩展数据;

       meth:DH_METHOD,本DH密钥的各种计算方法,明确指明了DH的各种运算方式;

       engine:硬件引擎。

19.4 主要函数

1)  DH_new

       生成DH数据结构,其DH_METHOD采用openssl默认提供的。

       2)  DH_free

              释放DH数据结构。

       3)  DH_generate_parameters

              生成DH密钥参数。

       4)  DH_generate_key

              生成DH公私钥。

       5)  DH_compute_key

              计算共享密钥,用于数据交换。

       6)  DH_check

              检查DH密钥。

       7)  DH_get_default_method

              获取默认的DH_METHOD,该方法是可以由用户设置的。

       8)  DH_get_ex_data

              获取DH结构中的扩展数据。

9)    DH_new_method

生成DH数据结构。

       10)DH_OpenSSL

              获取openssl提供的DH_METHOD。

       11)DH_set_default_method

设置默认的DH_METHOD方法,当用户实现了自己的DH_METHOD时,可调用本函数来设置,控制DH各种计算。

       12)DH_set_ex_data

              获取扩展数据。

13)DH_set_method

       替换已有的DH_METHOD。

14)DH_size

       获取DH密钥长度的字节数。

15)  DH_up_ref

增加DH结构的一个引用。

       16)DHparams_print

              将DH密钥参数输出到bio中。

17)  DHparams_print_fp

       将DH密钥参数输出到FILE中。

19.5 编程示例

       #include <openssl/dh.h>

#include <memory.h>

int    main()

{

       DH         *d1,*d2;

       BIO        *b;

       int           ret,size,i,len1,len2;

       char sharekey1[128],sharekey2[128];


       /* 构造DH数据结构 */

       d1=DH_new();

       d2=DH_new();

       /* 生成d1的密钥参数,该密钥参数是可以公开的 */

       ret=DH_generate_parameters_ex(d1,64,DH_GENERATOR_2,NULL);

       if(ret!=1)

       {

              printf("DH_generate_parameters_ex err!\n");

              return -1;

       }

       /* 检查密钥参数 */

       ret=DH_check(d1,&i);

       if(ret!=1)

       {

              printf("DH_check err!\n");

              if(i&DH_CHECK_P_NOT_PRIME)

                     printf("p value is not prime\n");

              if(i&DH_CHECK_P_NOT_SAFE_PRIME)

                     printf("p value is not a safe prime\n");

              if (i&DH_UNABLE_TO_CHECK_GENERATOR)

                     printf("unable to check the generator value\n");

              if (i&DH_NOT_SUITABLE_GENERATOR)

                     printf("the g value is not a generator\n");

       }

       printf("DH parameters appear to be ok.\n");

       /* 密钥大小 */

       size=DH_size(d1);

       printf("DH key1 size : %d\n",size);

       /* 生成公私钥 */

       ret=DH_generate_key(d1);

       if(ret!=1)

       {

              printf("DH_generate_key err!\n");

              return -1;

       }

       /* p和g为公开的密钥参数,因此可以拷贝 */

       d2->p=BN_dup(d1->p);

       d2->g=BN_dup(d1->g);

       /* 生成公私钥,用于测试生成共享密钥 */

       ret=DH_generate_key(d2);

       if(ret!=1)

       {

              printf("DH_generate_key err!\n");

              return -1;

       }

       /* 检查公钥 */

       ret=DH_check_pub_key(d1,d1->pub_key,&i);

       if(ret!=1)

       {

              if (i&DH_CHECK_PUBKEY_TOO_SMALL)

                     printf("pub key too small \n");

              if (i&DH_CHECK_PUBKEY_TOO_LARGE)

                     printf("pub key too large \n");

       }

       /* 计算共享密钥 */

       len1=DH_compute_key(sharekey1,d2->pub_key,d1);

       len2=DH_compute_key(sharekey2,d1->pub_key,d2);

       if(len1!=len2)

       {

              printf("生成共享密钥失败1\n");

              return -1;

       }

       if(memcmp(sharekey1,sharekey2,len1)!=0)

       {

              printf("生成共享密钥失败2\n");

              return -1;

       }

       printf("生成共享密钥成功\n");

       b=BIO_new(BIO_s_file());

       BIO_set_fp(b,stdout,BIO_NOCLOSE);

       /* 打印密钥 */

       DHparams_print(b,d1);

       BIO_free(b);

       DH_free(d1);

       DH_free(d2);

       return 0;

}

本例主要演示了生成DH密钥以及密钥交换函数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352