廖雪峰Java10加密与安全-4加密算法-4密钥交换算法
1DH算法
1.1.原根公式:g^i mod P 条件:1<g<P,0<i<P
原根:介于[1, p-1]之间的任意2个数i,j(p为素数,i≠j)的结果不相等,即
g^i mod p ≠ g^j mod p ,则g为p的原根。
同余式:正整数a,b对p取模,它们的余数相同,记做 或者a ≡ b (mod p)
示例:模为7
设a= 2,由于2^3=8≡1(mod 7),26=64≡1(mod7),23≡2^6(mod7),所以 2 不是模 7 的一个原根。
设a= 3,由于3^1≡3(mod 7),3^2≡2(mod 7),3^3≡6(mod 7),3^4≡4(mod 7),3^5≡5(mod 7),3^6≡1(mod 7),所以 3 是模 7 的一个原根。
总之:
- 假设一个数g是P的原根,那么g^i mod P的结果两两不同
- g^(P-1)≡1 (mod P)等同于 g^(p-1) mod P = 1当且仅当指数为P-1的时候成立.(这里P是素数)。
1.2.素数:大于1的自然数
1.3Diffie-Hellman算法
基于原根的定义及性质,可以定义PH密钥交换算法
- 1.有2个全部公开的参数,一个素数q和一个整数a,a是q的一个原根。
- 2.假设用户A和B希望交换一个密钥,用户A选择一个作为私有密钥的随机数XA(XA < q),并计算公开密钥 YA = a^XA mod q。用户A对XA的值保密,而使YA能被B公开获得。
类似用户B选择一个私有的随机数XB(XB < q),并计算公开密钥 YB = a^XB mod q。B对XB的值保密,而是YB能被A公开获得。 - 3.用户A产生共享密钥的计算方式是:KA = (YB)^XA mod q。同样B产生共同密钥的计算方式是KB = (YA)^XB mod q。K值是相同的。
KA = (YB)^XA mod q
= (a^XB mod q)^XA mod q //把a替换为n*q+x:((n*q+x)^XB mod q)^XA mod q = (x^XB)^XA mod q = x^XA^XB。
//内外层都存在mod q,内层去除mod q,则为(n*q+x)^XB mod q,最终结果依然为x^XB^XA,而外层存在mod q,因此内层增加、去除mod q不会对结果造成影响。内层去除mod q后,为(a^XB)^XA mod q
= (a^XB)^XA mod q
=(a^XA)^XB mod q
=(a^XA mod q)^XB mod q
=YA^XB mod q =KB
2.密钥交换算法
在使用对称加密算法的时候,加减密使用的是同一个密钥,以AES加密为例,当加密明文,需要使用一个随机生成的key作为密钥进行加减密。
encrypt(key,message) -> s
decrypt(key,s)->message
问题:如何传递密钥?
不给对方密钥,对方就不能解密;而直接传递密钥,会被黑客监听。
所以问题变成了:如果在不安全的信道上安全的传递密钥?
密钥交换算法,Differ-Hellman算法,就是为了解决这个问题的。最后的K就是密钥,而K并未在网上传输。

#注意,python脚本
#!/user/env/python3
#coding:utf-8
class DH():
def get(self,base,factorial,divider):
return base ** factorial % divider
#XA为随机数,获取YA
def getData(self,a,q,XA,XB):
YA = self.get(a,XA,q)
print("甲->乙传递:",a,q,YA)
#XB为随机数,获取YB
YB = self.get(a,XB,q)
print("乙->甲传递:",YB)
KA=self.get(YB,XA,q)
KB=self.get(YA,XB,q)
print("K值对比:",KA==KB,KA,KB)
sh = DH()
sh.getData(5,509,123,456)

甲乙双方拥有各自的私钥,并生成公钥返回给对方。而根据DH原理,使用对方的公钥和自己的私钥生成的K值是相同的。

3.代码示例
package com.testList;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class Person {
public final String name;//发送方、接受方的名字
public PublicKey publicKey;//公钥
private PrivateKey privateKey;//私钥
private SecretKey secretKey;//密钥
public Person(String name){
this.name=name;
}
public void generateKeyPair(){//生成公钥和私钥
try{
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DH");//创建一个KeyPairGenerator,用于DH算法
kpGen.initialize(512);//创建一个512位的KeyPair
KeyPair kp = kpGen.generateKeyPair();//通过generateKeyPair()获取一个KeyPair对象
this.privateKey = kp.getPrivate();//通过getPrivate()获取私钥
this.publicKey = kp.getPublic();//通过getPublic()获取公钥
}catch (GeneralSecurityException e){
throw new RuntimeException(e);
}
}
public void generateSecretKey(byte[] receviedPubKeyBytes){//当通信双方把public
try{
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(receviedPubKeyBytes);//从收到的公钥数组恢复公钥
KeyFactory kf = KeyFactory.getInstance("DH");
PublicKey receviedPublicKey = kf.generatePublic(keySpec);
//生成本地密钥
KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
keyAgreement.init(this.privateKey);//传入自己的私钥
keyAgreement.doPhase(receviedPublicKey,true);//传入接受到的公钥
this.secretKey = keyAgreement.generateSecret("AES");//生成AES密钥
}catch (GeneralSecurityException e){
throw new RuntimeException(e);
}
}
public void printKeys(){//将用户名、公钥、私钥、密钥全部打印
System.out.printf("Name:%s\n",this.name);
System.out.printf("Private key:%s\n",new BigInteger(1,this.privateKey.getEncoded()));
System.out.printf("Public key:%s\n",new BigInteger(1,this.publicKey.getEncoded()));
System.out.printf("SecretKey:%s\n",new BigInteger(1,this.secretKey.getEncoded()));
}
public String sendMessage(String message){//测试AES加密
try{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE,this.secretKey);
byte[] data = cipher.doFinal(message.getBytes("utf-8"));
return Base64.getEncoder().encodeToString(data);
}catch (GeneralSecurityException|IOException e){
throw new RuntimeException(e);
}
}
public String receivedMessage(String message){//接受消息,并解密
try{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE,this.secretKey);
byte[] data = cipher.doFinal(Base64.getDecoder().decode(message));
return new String(data,"utf-8");
}catch (GeneralSecurityException|IOException e){
throw new RuntimeException(e);
}
}
}
package com.testList;
public class DH {
public static void main(String[] args){
//创建2个Person对象,作为发送方、接收方
Person bob = new Person("Bob");
Person alice = new Person("Alice");
//生成各自的keyPair
bob.generateKeyPair();
alice.generateKeyPair();
//双方交换各自的publickey,并生成自己的本地密钥
bob.generateSecretKey(alice.publicKey.getEncoded());
alice.generateSecretKey(bob.publicKey.getEncoded());
//检查双方的本地密钥是否相同
bob.printKeys();
alice.printKeys();
//发送
String msgBobToAlice = bob.sendMessage("Hello,Alice");
System.out.println("Bob->Alice:"+msgBobToAlice);
//接受
String aliceDecrypted = alice.receivedMessage(msgBobToAlice);
System.out.println("Alice decrypted:"+aliceDecrypted);
}
}

4.总结:
- DH算法是一种密钥交换协议,通信双方通过不安全的信道协商密钥,然后进行对称加密传输
- DH算法没有解决中间人攻击问题。
* 如果黑客假冒乙与甲交换密钥,同时冒充甲与乙交换密钥,就可以成功的进行攻击。
廖雪峰Java10加密与安全-4加密算法-4密钥交换算法的更多相关文章
- 廖雪峰Java10加密与安全-4加密算法-2口令加密算法
对称加密key是一个byte数组,如AES256算法的key是一个32字节的数组,普通的加密软件由用户输入加密口令.如果由用户输入口令,进行加密/解密,需要用到PBE算法. 1.PBE:Passwor ...
- 廖雪峰Java10加密与安全-4加密算法-5非对称加密算法
1.非对称加密 非对称加密就是加密和解密使用的不是相同的密钥 方法1: * 加密:用自己的私钥加密,然后发送给对方:encrypt(privateKeyA, message)->s * 解密:对 ...
- 廖雪峰Java10加密与安全-4加密算法-1对称加密算法
1.对称加密算法 加密和解密使用同一个密钥,例如WinRAR. WinRAR在对文件进行打包的时候,可以设置一个密码,在解压的时候需要使用同样的密码才能正确的解压. 加密:encrypt(key,me ...
- 廖雪峰Java10加密与安全-2加密算法-2Base64编码
1.Base64编码 Base64一种把二进制数据用文本表示的编码算法.例如 中有3个字节{\xe4, \xb8, \xad},一共是24位,每6位分组,变成4个字节{39, 0b, 22, 2d}, ...
- 廖雪峰Java10加密与安全-2加密算法-1URL编码
1.URL编码 URL编码是浏览器发送数据给服务器时使用的编码. 如通过百度搜索美女: 编码前:https://www.baidu.com/s?wd=美女 编码后:https://www.baidu. ...
- 廖雪峰Java10加密与安全-6数字证书-1数字证书
数字证书: 非对称加密算法:对数据进行加密/解密 签名算法:确保数据完整性和抗否认性 摘要算法:确保证书本身没有被篡改
- 廖雪峰Java10加密与安全-1数据安全-1加密与安全概念
数据安全 防窃听 防篡改 防伪造 古代加密方式: 移位密码:HELLO =>IFMMP 替代密码:HELLO=>p12,5,3 现代加密方式: 建立在严格的数学理论基础上 密码学逐渐发展成 ...
- 廖雪峰Java10加密与安全-5签名算法-1RSA签名算法
1.数字签名 甲在发送加密消息的时候,还要发送自己的签名,而这个签名是用甲的privateKey计算的:而乙要验证这个签名是否是合法的,会用甲的publicKey去验证,如果验证成功,这个消息确实是甲 ...
- 廖雪峰Java10加密与安全-3摘要算法-5Hmac
1 比较MD5和HamcMD5 HmacMD5可以看作带安全salt的MD5 import javax.crypto.KeyGenerator; import javax.crypto.Mac; im ...
随机推荐
- Windows DHCP服务器
DHCP服务器 编辑 动态主机配置协议是一个局域网的网络协议.指的是由服务器控制一段IP地址范围,客户机登录服务器时就可以自动获得服务器分配的IP地址和子网掩码.首先, DHCP服务器必须是一台安装有 ...
- platform模块和ctypes模块
一.ctypes模块 Python 的 ctypes 要使用 C 函数,需要先将 C 编译成动态链接库的形式,即 Windows 下的 .dll 文件,或者 Linux 下的 .so 文件.先来看一下 ...
- 20175323《Java程序设计》第三周学习总结
教材学习内容总结 这周开始用幕布记录学习过程和思路,下面是我这章的知识框架总结https://mubu.com/doc/aNMW9Clym0 教材学习中的问题和解决过程 问题1:教材90页的Trian ...
- 二分查找总结及部分Lintcode题目分析 4
二分法不只能像之前的记录,可以找到index~第二种类型是找到二分答案.有以下几个例子,都是之前二分法的扩展,不再赘述,只记录下忽略的点,以后回顾多注意~ 1. wood cut class Solu ...
- node.js在ubuntu上和windows上的安装
Ubuntu 上安装 Node.js Node.js 源码安装 以下部分我们将介绍在Ubuntu Linux下安装 Node.js . 其他的Linux系统,如Centos等类似如下安装步骤. 在 G ...
- 搞大数据,你不懂这三大数据处理趋势就OUT了
搞大数据,你不懂这三大数据处理趋势就OUT了 企业数据每年以PB级甚至上百PB爆炸式增长,越来越大的数据量正为扩大分析策略在企业应用软件领域的拓展提供了数据基础,但数据的价值是有时效性的,越早分析越能 ...
- Python 函数与内置函数
1.函数的基本定义 def 函数名称(参数) 执行语句 return 返回值 def : 定义函数的关键字: 函数名称:顾名思义,就是函数的名字,可以用来调用函数,不能使用关键字来命名,做好是用这个函 ...
- day 50 MySQL数据备份与还原(mysqldump)
MySQL数据备份与还原(mysqldump) 一 mysqldump指令实现数据备份.mysql指令实现数据还原 经常有朋友问我,DBA到底是做什么的,百科上说:数据库管理员(Databas ...
- python爬取(自动化)豆瓣电影影评,并存储。
from selenium import webdriverfrom selenium.webdriver import ActionChainsimport time driver = webdri ...
- mac系统升级导致无法在iOS设备中运行Safari Web 调试器
macOS系统升级之后,可能会导致Safari开发选项中没有iOS设备,进而无法运行Safari Web 调试器. 此问题的解决办法: 请转到设置>常规>重置>重置位置和隐私.现在, ...