java ecdh秘钥交换_ECDH密钥交换的C程序
由于项目需要,使用openssl编写一段ECDH代码实现网络两端实体的密钥交换。
虽然对openssl不熟悉,但也开始做。
最先参照的是openssl官方wiki上的Elliptic Curve Diffie Hellman:http://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman
直接使用文中的代码。不过其中有段代码需要替换:
/* Get the peer's public key, and provide the peer with our public key -
* how this is done will be specific to your circumstances */
peerkey = get_peerkey(pkey);
我以为只要将这pkey和peerkey指向的密钥块通过网络交换一下就行了。
先不经过网络交换这两个密钥数据,在本地测试,完全通过。但是,一涉及网络交换,程序就崩溃,并爆出内存错误。
总以为是外围程序的问题,调试了好久好久……
直到后来,最后打印出pkey和peerkey指向的类型为EVP_PKEY的数据来看,才发现EVP_PKEY占存储量很小(32字节),这才发现奇怪。因为密钥块一般挺大的。
在openssl库安装路径include目录中找到evp.h,打开查看,发现:
struct evp_pkey_st
{
int type;
int save_type;
int references;
const EVP_PKEY_ASN1_METHOD *ameth;
ENGINE *engine;
union{
char *ptr;
#ifndef OPENSSL_NO_RSA
struct rsa_st *rsa;/* RSA */
#endif
#ifndef OPENSSL_NO_DSA
struct dsa_st *dsa;/* DSA */
#endif
#ifndef OPENSSL_NO_DH
struct dh_st *dh;/* DH */
#endif
#ifndef OPENSSL_NO_EC
struct ec_key_st *ec;/* ECC */
#endif
} pkey;
int save_parameters;
STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
} /* EVP_PKEY */;
这下明白了,原来在网络上传输的我以为的“密钥块”原来是一堆指针!(而且是公私密钥对的指针。。。。)
于是得想办法解决。找到这个帖子:
How does one access the raw ECDH public key, private key and params inside OpenSSL's EVP_PKEY structure?
http://stackoverflow.com/questions/18155559/how-does-one-access-the-raw-ecdh-public-key-private-key-and-params-inside-opens
文中指出要进行公钥的序列化。
然后挨个搜索API的说明,花了不少时间。又是一阵子调试……
最后还是卡在反序列化过程中EC_KEY_set_public_key() to get an EC_KEY和EC_KEY to EVP_PKEY_set1_EC_KEY上了。
心想只好换一种方法了。调试途中在google搜索EC_POINT_point2oct关键字时发现了一个页面:
OpenSSL - User - ECDH http://openssl.6102.n7.nabble.com/ECDH-td22150.html
3楼Rick的回复给的代码比较好。采用并改进,调试之。
最终得到完整的ECDH代码:
#include
#define ECDH_SIZE 33
void handleErrors()
{
printf("Error occurred.\n");
}
static void disp(const char *str, const void *pbuf, const int size)
{
int i=0;
if(str != NULL){
printf("%s:\n", str);
}
if(pbuf != NULL && size > 0){
for(i=0;i
printf("%02x ", *((unsigned char *)pbuf+i));
putchar('\n');
}
putchar('\n');
}
int main() {
/* alice */
EC_KEY *ecdh = EC_KEY_new();
EC_POINT *point = NULL;
EC_POINT *point2c;
EC_GROUP *group;
unsigned char pubkey[ECDH_SIZE];
unsigned char shared[ECDH_SIZE];
int len;
//Generate Public
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);//NID_secp521r1
EC_KEY_generate_key(ecdh);
point = EC_KEY_get0_public_key(ecdh);
group = EC_KEY_get0_group(ecdh);
if(0 == (len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, pubkey, ECDH_SIZE, NULL))) handleErrors();
printf("len=%d\n",len);
/* bob */
EC_KEY *ecdh2 = EC_KEY_new();
EC_POINT *point2 = NULL;
EC_POINT *pointc;
EC_GROUP *group2;
unsigned char pubkey2[ECDH_SIZE];
unsigned char shared2[ECDH_SIZE];
int len2;
//Generate Public
ecdh2 = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);//NID_secp521r1
EC_KEY_generate_key(ecdh2);
point2 = EC_KEY_get0_public_key(ecdh2);
group2 = EC_KEY_get0_group(ecdh2);
if(0 == (len2 = EC_POINT_point2oct(group2, point2, POINT_CONVERSION_COMPRESSED, pubkey2, ECDH_SIZE, NULL))) handleErrors();
printf("len2=%d\n",len);
/* alice */
//ComputeKey
point2c = EC_POINT_new(group);
EC_POINT_oct2point(group, point2c, pubkey2, ECDH_SIZE, NULL);
if (0 != EC_POINT_cmp(group, point2, point2c, NULL)) handleErrors();
if(0 == (len = ECDH_compute_key(shared, ECDH_SIZE, point2c, ecdh, NULL))) handleErrors();
printf("len=%d\n",len);
disp("shared", shared, len);
/* bob */
//ComputeKey
pointc = EC_POINT_new(group2);
EC_POINT_oct2point(group2, pointc, pubkey, ECDH_SIZE, NULL);
if (0 != EC_POINT_cmp(group2, point, pointc, NULL)) handleErrors();
if(0 == (len2 = ECDH_compute_key(shared2, ECDH_SIZE, pointc, ecdh2, NULL))) handleErrors();
printf("len2=%d\n",len2);
disp("shared2", shared2, len2);
/* alice */
EC_POINT_free(pointc);
EC_KEY_free(ecdh);
/* bob */
EC_POINT_free(point2c);
EC_KEY_free(ecdh2);
printf("To the end\n");
return 0;
}
之后抽象、整理封装后的ECDH代码:
#include
#define ECDH_SIZE 33
void handleErrors()
{
printf("Error occurred.\n");
}
static void disp(const char *str, const void *pbuf, const int size)
{
int i=0;
if(str != NULL){
printf("%s:\n", str);
}
if(pbuf != NULL && size > 0){
for(i=0;i
printf("%02x ", *((unsigned char *)pbuf+i));
putchar('\n');
}
putchar('\n');
}
static EC_KEY *genECDHtemppubkey(unsigned char *pubkey)
{
int len;
EC_KEY *ecdh = EC_KEY_new();
//Generate Public
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);//NID_secp521r1
EC_KEY_generate_key(ecdh);
const EC_POINT *point = EC_KEY_get0_public_key(ecdh);
const EC_GROUP *group = EC_KEY_get0_group(ecdh);
//unsigned char *pubkey = malloc(ECDH_SIZE);
if(0 == (len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, pubkey, ECDH_SIZE, NULL))) handleErrors();
printf("len=%d\n",len);
//return pubkey;
return ecdh;
}
static unsigned char *genECDHsharedsecret(EC_KEY *ecdh, unsigned char *peerkey, size_t secret_len)
{
int len;
unsigned char *shared = malloc(ECDH_SIZE);
const EC_GROUP *group = EC_KEY_get0_group(ecdh);
//ComputeKey
EC_POINT *point_peer = EC_POINT_new(group);
EC_POINT_oct2point(group, point_peer, peerkey, ECDH_SIZE, NULL);
//if (0 != EC_POINT_cmp(group, point2, point2c, NULL)) handleErrors();
if(0 == (len = ECDH_compute_key(shared, secret_len, point_peer, ecdh, NULL))) handleErrors();
printf("len=%d\n",len);
disp("shared", shared, secret_len);
return shared;
}
int main() {
unsigned char *keydata = malloc(ECDH_SIZE);
unsigned char *keydata2 = malloc(ECDH_SIZE);
EC_KEY *ecdh = genECDHtemppubkey(keydata);
EC_KEY *ecdh2 = genECDHtemppubkey(keydata2);
unsigned char *ECDH_keydata = genECDHsharedsecret(ecdh2, keydata, ECDH_SIZE-1);
unsigned char *ECDH_keydata2 = genECDHsharedsecret(ecdh, keydata2, ECDH_SIZE-1);
printf("To the end\n");
free(keydata);
free(keydata2);
EC_KEY_free(ecdh);
EC_KEY_free(ecdh2);
free(ECDH_keydata);
free(ECDH_keydata2);
return 0;
}
调试时在“ECDH_SIZE-1”的问题上纠结了好一阵子,不小心把EC_POINT_oct2point中参数ECDH_SIZE换成值为ECDH_SIZE-1的secret_len了;导致ECDH_compute_key一直返回-1,怎么搜索都得不到解决。
最后还是耐心的一步步调试、对比前面参考的源码、调整变量数值,终于解决。编译通过,执行的非常好。
耐心真的是非常重要,失之毫厘差之千里。
参考资料:
ECC加密算法原理入门介绍
http://blog.csdn.net/sahusoft/article/details/6868016
java ecdh秘钥交换_ECDH密钥交换的C程序相关推荐
- java ecdh秘钥交换_ECDH密钥交换使用不同长度的公钥?
我目前正致力于ECDH密钥交换的实施.我正在使用P-384曲线.其他曲线也是可能的,但我认为实现应该非常相似. 客户端(Javascript)和服务器(Java)想要找到共享密钥,因此 1)服务器创建 ...
- java ecdh秘钥交换_DH密钥交换和ECDH原理(转)
下面我们以Alice和Bob为例叙述Diffie-Hellman密钥交换的原理. 1,Diffie-Hellman交换过程中涉及到的所有参与者定义一个组,在这个组中定义一个大质数p,底数g. 2,Di ...
- java ecdh秘钥交换,ECDH密钥协商算法
ECDH是EC是"elliptic curves"的意思,DH是"Diffie-Hellman"的意思.它实际上是密钥协商算法,而不是加解密算法. 该算法可以用 ...
- java ecdh秘钥交换_了解一下密钥交换算法ECDH
https://www.jianshu.com/p/b26cd2bfdc28 搬一下别人的解释: 下面我们以Alice和Bob为例叙述Diffie-Hellman密钥交换的原理. 1,Diffie-H ...
- ECDH秘钥协商算法原理(ECDH Key Exchange)
ECDH全称是椭圆曲线迪菲-赫尔曼秘钥交换(Elliptic Curve Diffie–Hellman key Exchange),主要是用来在一个不安全的通道中建立起安全的共有加密资料,一般来说交换 ...
- Diffie-Hellman(迪菲-赫尔曼)秘钥交换协议
1. 协议背景 对称密码体制: Bob利用对称密钥K对信息进行加密并将加密结果发送给Alice,Alice收到信息之后,用同样的密钥进行解密. 问题1:Alice是如何知道对称密钥K的?------即 ...
- java中secretkey,java生成秘钥key,并保存秘钥到文件中
本例子采用的是Java的对称加密其中的一种方式(3DES),其他的加密方式也类似.生成一个key秘钥,发送方使用生成的key秘钥进行加密操作,然后把生成的key秘钥保存到文件中,提供给需要解密的一方使 ...
- java用秘钥实现试用期_Android - 如何实现免费试用期,无需提前付费
我已经开发了一个Android trial library,您可以将其放入项目中,它将为您处理所有服务器端管理(包括脱机宽限期),因此您不需要自己的服务器. 要简单地使用它 将库添加到主模块的buil ...
- Java加解密(十)持久化秘钥
目录 Java持久化秘钥 1 保存PEM文件 2 保存文本文件 3 Java序列化 Java持久化秘钥 加密算法的秘钥持久化是是一个不可避免的话题,如何安全的存储更是重中之重.将秘钥保存在文件中是最简 ...
最新文章
- SAP PI 集成引擎
- 如何强制 .NET 程序以 管理员模式 运行 ?
- 华科计算机学院三好学生,他是华科“三好学生标兵”,被保研到北大、复旦、交大等3所名校!...
- 洛谷P2023 [AHOI2009]维护序列
- 粉刷匠(bzoj 1296)
- 关于一些桌面、移动应用开发的平台
- 3D打印技术到底有多强大?
- pc弹窗宽度_弹窗设计的5条原则
- 天津大学计算机软件技术基础试题答案,天津大学网络学院计算机软件技术基础-1试题b卷.doc...
- WPS 操作之在指定页插入页码
- 提升工作效率的软件及网站(不断更新中)
- birt 报表与润乾报表对比
- CMD设置代理 注册表设置IE代理
- hp ilo 服务器 hpssacli 做 raid
- webview和H5 清除缓存和缓存文件删除。
- CFA II学习记录-Economics
- Thinkphp底层源码分析
- 根据卡号前6位判断开户银行
- IDEA 设置默认注释模板
- linux如何安装su软件下载,Linux环境软件安装
热门文章
- 亚马逊CTO沃格斯:AWS如何通过自定义硬件提升云端性能
- 动态规划求解最短路径问题:枚举法、逐段累加法、动态规划法对比理解
- html里文字自动换行属性,怎么让html换行 在HTML中怎么让输出文字换行
- ctfshow pwn——PWN签到题、pwn02
- 「业务架构」TOGAF建模系列:业务足迹图
- “远程计算机或设备将不接受连接”的解决办法
- Element-Ui 图标地址。。
- windows下用bat文件启动带参数的bat文件的方法
- java map的keyset_Java EnumMap keySet()用法及代码示例
- 初识 QR 二维码(零)