|

楼主 |
发表于 2022-5-28 19:00:14
|
显示全部楼层
ECC椭圆曲线加密 一、原理
描述一条Fp上的椭圆曲线,常用到六个参量:T=(p,a,b,n,x,y)。(p,a,b)用来确定一条椭圆曲线,p为素数域内点的个数,a和b是其内的两个大数;x,y为G基点的坐标,也是两个大数;n为点G基点的阶;
以上六个量就可以描述一条椭圆曲线,有时候我们还会用到h(椭圆曲线上所有点的个数p与n相除的整数部分)。现在我们描述一个利用椭圆曲线进行加密通信的过程:
1、选定一条椭圆曲线 Ep(a,b) 并取椭圆曲线上一点,作为基点P。
2、选择一个大数k作为私钥,并生成公钥 Q=kP。
3、将 Ep(a,b) 和点Q、P传给用户。
4、用户接到信息后 ,将待传输的明文编码到Ep(a,b)上的一点M,并产生一个随机整数r。
5、公钥加密(密文C是一个点对):C={rP, M+rQ}
6、私钥解密(M + rQ - k(rP) ,解密结果就是点M),公式:M + rQ - k(rP) = M + r(kP) - k(rP) = M
7、对点M进行解码就可以得到明文
假设在加密过程中,有一个第三者H,H只能知道椭圆曲线 Ep(a,b)、公钥Q、基点P、密文点C,而通过公钥Q、基点P求私钥k或者通过密文点C、基点P求随机数r都是非常困难的,因此得以保证数据传输的安全。
二、环境
C
三、源代码
- #include <string.h>
- #include <stdio.h>
- #include <openssl/ec.h>
- #include <openssl/ecdsa.h>
- #include <openssl/objects.h>
- #include <openssl/err.h>
-
- int main()
- {
- EC_KEY *key1,*key2;
- EC_POINT *pubkey1,*pubkey2;
- EC_GROUP *group1,*group2;
- int ret,nid,size,i,sig_len;
- unsigned char*signature,digest[20];
- BIO *berr;
- EC_builtin_curve *curves;
- int crv_len;
- char shareKey1[128],shareKey2[128];
- int len1,len2;
-
- /* 构造EC_KEY数据结构 */
- key1=EC_KEY_new();
- if(key1==NULL)
- {
- printf("EC_KEY_new err!\n");
- return -1;
- }
- key2=EC_KEY_new();
- if(key2==NULL)
- {
- printf("EC_KEY_new err!\n");
- return -1;
- }
- /* 获取实现的椭圆曲线个数 */
- crv_len = EC_get_builtin_curves(NULL, 0);
- curves = (EC_builtin_curve *)malloc(sizeof(EC_builtin_curve) * crv_len);
- /* 获取椭圆曲线列表 */
- EC_get_builtin_curves(curves, crv_len);
- /*
- nid=curves[0].nid;会有错误,原因是密钥太短
- */
- /* 选取一种椭圆曲线 */
- nid=curves[25].nid;
- /* 根据选择的椭圆曲线生成密钥参数group */
- group1=EC_GROUP_new_by_curve_name(nid);
- if(group1==NULL)
- {
- printf("EC_GROUP_new_by_curve_name err!\n");
- return -1;
- }
- group2=EC_GROUP_new_by_curve_name(nid);
- if(group1==NULL)
- {
- printf("EC_GROUP_new_by_curve_name err!\n");
- return -1;
- }
- /* 设置密钥参数 */
- ret=EC_KEY_set_group(key1,group1);
- if(ret!=1)
- {
- printf("EC_KEY_set_group err.\n");
- return -1;
- }
- ret=EC_KEY_set_group(key2,group2);
- if(ret!=1)
- {
- printf("EC_KEY_set_group err.\n");
- return -1;
- }
- /* 生成密钥 */
- ret=EC_KEY_generate_key(key1);
- if(ret!=1)
- {
- printf("EC_KEY_generate_key err.\n");
- return -1;
- }
- ret=EC_KEY_generate_key(key2);
- if(ret!=1)
- {
- printf("EC_KEY_generate_key err.\n");
- return -1;
- }
- /* 检查密钥 */
- ret=EC_KEY_check_key(key1);
- if(ret!=1)
- {
- printf("check key err.\n");
- return -1;
- }
- /* 获取密钥大小 */
- size=ECDSA_size(key1);
- printf("size %d \n",size);
- for(i=0;i<20;i++)
- memset(&digest[i],i+1,1);
- signature=malloc(size);
- ERR_load_crypto_strings();
- berr=BIO_new(BIO_s_file());
- BIO_set_fp(berr,stdout,BIO_NOCLOSE);
- /* 签名数据,本例未做摘要,可将digest中的数据看作是sha1摘要结果 */
- ret=ECDSA_sign(0,digest,20,signature,&sig_len,key1);
- if(ret!=1)
- {
- ERR_print_errors(berr);
- printf("sign err!\n");
- return -1;
- }
- /* 验证签名 */
- ret=ECDSA_verify(0,digest,20,signature,sig_len,key1);
- if(ret!=1)
- {
- ERR_print_errors(berr);
- printf("ECDSA_verify err!\n");
- return -1;
- }
- /* 获取对方公钥,不能直接引用 */
- pubkey2 = EC_KEY_get0_public_key(key2);
- /* 生成一方的共享密钥 */
- len1=ECDH_compute_key(shareKey1, 128, pubkey2, key1, NULL);
- pubkey1 = EC_KEY_get0_public_key(key1);
- /* 生成另一方共享密钥 */
- len2=ECDH_compute_key(shareKey2, 128, pubkey1, key2, NULL);
- if(len1!=len2)
- {
- printf("err\n");
- }
- else
- {
- ret=memcmp(shareKey1,shareKey2,len1);
- if(ret==0)
- printf("生成共享密钥成功\n");
- else
- printf("生成共享密钥失败\n");
- }
- printf("test ok!\n");
- BIO_free(berr);
- EC_KEY_free(key1);
- EC_KEY_free(key2);
- free(signature);
- free(curves);
- return 0;
- }
复制代码
|
|