一、什么是D-H算法【参考了相关资料】
迪菲-赫尔曼**交换(Diffie–Hellman key exchange,简称“D–H”) 是一种安全协议,不是加密协议。它可以让双方在完全没有对方任何预先信息的条件下通过不安全信道建立起一个**。这个**可以在后续的通讯中作为对称**来加密通讯内容。
迪菲-赫尔曼**交换是1976年在Whitfield Diffie和Martin Hellman的合作下发明的。它是第一个实用的在非保护信道中建立共享**方法。
这个方案首先由Whitfield Diffie和Martin Hellman于1976发布。后来发现这个方案已经在之前几年由英国信号情报部门发明(发明者为Malcolm J. Williamson),但是当时这被列为是机密。2002年,赫尔曼建议将该算法改名为Diffie–Hellman–Merkle**交换以表明 Ralph Merkle对于公钥加密算法的贡献(Hellman, 2002)。
2002年,Martin Hellman写到:
这个系统…从此被称为迪菲-赫尔曼**交换。 虽然这个系统首先是在我和迪菲的一篇论文中描述的,但是这却是一个公钥交换系统,是Merkle提出的概念,因此如果加上他的名字,这个系统实际上应该称为’Diffie–Hellman–Merkle**交换’。我希望这个小小的讲坛可以帮助我们认识到Merkle对公钥密码学的同等重要的贡献。
美国专利 4,200,770, 现在已经过期。它描述了这个算法,并且表明了Hellman、Diffie和Merkle是算法的发明者。
二、相关的算法重点:
模有关的公式:
a*b mod n ≡ ( (a mod n) * (b mod n ) ) mod n
1、什么是元根(primitive_root),为什么需要元根?
(1)定义:若p为一个质数,若存在1<a<=p-1,使得:
a mod p,
a^2 mod p,
a^3 mod p,
…
a^(p-1) mod p ,两两互不相同,且构成一个1~p-1的全体数的一个排列,则a为p的原根。(元根可能有多个)。
(2)为什么需要元根?,元根的意义是什么?
元根有一些特别的特性:比如
对于p=5,那么,2和3就是其元根。在这种情况下,对于元根2,存在这种关系
2^0 =1mod5
2^1= 2mod5
2^2 =4 mod5
2^3 =3 mod5
2^4 =1 mod5
3也是一样的。
(3)为什么需要的是质数?
当 a, p都为质数时,可以利用欧拉定理,来快速计算。具体可以参考相关数论书。密码学离开欧拉定理根本就玩不转。
欧拉函数φ的定义:对于正整数N,代表小于等于N的与N互质的数的个数,记作φ(N)。
特别地,对于N为质数时,φ(N)=N-1;
欧拉定理:
若N>2; a与N互质,则a^(φ(N)) ≡1modN .
如何应用:比如,对于 3^2018 mod 7,我们就可以:
φ(7) =6;
根据欧拉定理,则有:
3^(φ(7)) mod 7
=3^6 mod 7
=1 mod7;
那么
3 ^2018 mod7
= (3^6 ) ^336 * 3^2 mod7 =( ((3^6 ) ^336 mod7 )* (3^2 mod7) ) mod7
=( 1* (3^2 mod7) ) mod7
=1*2 mod7
=2
如果不是质数,那这个情况就不容易处理了。
实际操作中,元根也会选择是一个质数的元根。这样,元根和欧拉定理的性质都能用上了。
思考一下:假定元根为a =113,N =2^127 -1 即
113^ 19 mod N,如何计算?
2、指数模的计算(x^y mod p),当x,y值较大时,直接计算是不可行了,需要借助算法。
3、为什么D-H算法会有效?
D-H算法的实质是,
(1)对于给定K,G,p 三个值,求K=(G^a ) % p,中a的值;
或者
(2)给定M,G,p 三个值,求M= (G^b) % p , 中b的值;
其中(1),K为A发给B的值;G,p是已知,G为元根,p为大质数。(2)同样。
可以看出,一方面,非常困难 。即上面的式子,在p为大质数时,G为元根的情况下,(1)或(2)的求解,目前没有快速的算法,只有暴力**,但耗时过长。【不信你可以试试,反正我是试过了,电脑一直不动】。
另一方面,却非常容易。即已知(G^a ) % p,中G,a, p;却很容易算出K; 【后面也有算法哈】
同一个公式的两边,形成了一个非常困难和一个非常容易(象不象RSA的结构?),形成一个严重不对称的结构(即单向陷门函数的特征),因此,可以用来进行密码处理。
三、相关的rust 代码
use std::{thread, time};
//D-H密码交换
fn is_prime(n: u128) -> bool {
!(2..(n)).any(|x| n % x == 0)
}
fn max_prime(n: u128) -> u128 {
let mut num = n;
while !is_prime(num) {
num = num - 1;
}
num
}
// x^y mod p 如何计算 13^15679 mod 458
fn pow_mod(x: u128, y: u128, p: u128) -> u128 {
if y == 0 {
return 1;
} else {
let z = pow_mod(x, y / 2, p); //如果y=5_u128, y/2=2
if y % 2 == 0 {
return ((z % p) * (z % p)) % p;
} else {
return ((((x % p) * (z % p)) % p) * (z % p)) % p;
}
}
}
//求p 原始根 的集合,最多产生元根的上限,从小至大
fn generator_primitive_root(p: u128, num: u128) -> Vec<u128> {
if !is_prime(p) {
panic!("p:{} is not prime!", p);
}
let mut values: Vec<u128> = Vec::new();
let target = (1..p).map(|x| x).collect::<Vec<u128>>();
for i in 1..p {
if values.len() as u128 > num {
return values;
}
let mut temp_value: Vec<u128> = (1..p).map(|y| pow_mod(i, y, p)).collect();
temp_value.sort();
if temp_value == target {
values.push(i);
//println!("value:{:?}=>{}",temp_value,x);
}
}
println!("元根value:{:?}", values);
values
}
//求 指数i, 即为b(任意数)的以a为基数的模p的离散对数。
fn dis_log(b: u128, a: u128, p: u128) -> u128 {
//对于任意数b及素数p的原始根a,可以找到一个唯一的指数i,满足:b=( a ^ i) mod p,其中 0≤i≤p-1
let data: Vec<u128> = (0..p - 1).filter(|&i| pow_mod(a, i, p) == b).collect();
println!("dis_log=> i ={:?}", data);
data[0]
}
fn main() {
let sleep_seconds = time::Duration::from_secs(1000);
let randnum = 1259_u128; //随机输入一个较大的值
let max_prime = max_prime(randnum); //求出randnum中最大的质数
let groups_primitive_root = generator_primitive_root(max_prime, 50); //50个原根
let G_primitive_root = *&groups_primitive_root[10]; //10为随机取,指取第11个元根集合数据
let P = max_prime;
let A_private_key = 14_u128; // no open
let B_private_key = 39_u128; // no open
let A_send_to_B_num = pow_mod(G_primitive_root, A_private_key, P);
let B_send_to_A_num = pow_mod(G_primitive_root, B_private_key, P);
let A_compute_key_num = pow_mod(B_send_to_A_num, A_private_key, P);
let B_compute_key_num = pow_mod(A_send_to_B_num, B_private_key, P);
println!("测试中的参数:");
println!("G_primitive_root : {:?}", G_primitive_root);
println!("A_send_to_B_num : {:?}", A_send_to_B_num);
println!("B_send_to_A_num : {:?}", B_send_to_A_num);
println!("A_compute_key_num: {:?}", A_compute_key_num);
println!("B_compute_key_num: {:?}", B_compute_key_num);
println!("\n真实环境中的参数:");
// 真实中的加密参数
let g: u128 = 113;
let p: u128 = 2_u128.pow(128) - 1; //巨大的质数
let a_private_key = 19; //保密
let b_private_key = 23; //保密
let a_send_to_b_num = pow_mod(g, a_private_key, p);
let b_send_to_a_num = pow_mod(g, b_private_key, p);
println!("真实环境中的A发送的值:{}", a_send_to_b_num);
println!("真实环境中的B发送的值:{}", b_send_to_a_num);
let a_compute_key_num = pow_mod(b_send_to_a_num, a_private_key, p);
let b_compute_key_num = pow_mod(a_send_to_b_num, b_private_key, p);
println!("真实环境中a_compute_key_num:{:?}", a_compute_key_num);
println!("真实环境中b_compute_key_num:{:?}", b_compute_key_num);
println!("mod:{}", pow_mod(48_u128, 23_u128, 187));
thread::sleep(sleep_seconds);
}
四、输出结果:
可见,在元根为32的情况下,A发送给B的数值为964;B发送给A的数值为145;但是,各自都拥有了共同的**822.可见算法经过了验证。
需要说明的是:上述算法,并没有得到与第三方验证。目前只是一种了解性的参考。
五、为什么D-H算法会有效?
问题在,当p较大时,计算元根将非常耗时,所有本文采用选用前多少个元根。尽管如何,当p较大时,计算3-5个元根集,就是巨大的运算量。因此,暴力**花的时间将非常长。
|
请发表评论