首页 > 编程语言 >Diffie-Hellman密钥协商算法探究

Diffie-Hellman密钥协商算法探究

时间:2023-01-10 21:01:45浏览次数:52  
标签:BigInteger Hellman String return 密钥 new Diffie 服务端

Diffie-Hellman密钥协商算法探究_数据安全

作者 | 魔王赵二狗

导读

隐私计算(Privacy-preserving computation)是指在保证数据提供方不泄露原始数据的前提下,对数据进行分析计算的一系列信息技术,保障数据在流通与融合过程中的可用不可见。而Diffie–Hellman密钥协商是一种安全协议。它可以让双方在完全没有对方任何预先信息的条件下通过不安全信道创建起一个密钥。这个密钥可以在后续的通讯中作为对称秘钥讯内容。

全文6088字,预计阅读时间16分钟。

01 什么是DH密钥协商算法

1.1 DH由来

DH密钥协商是Whitefield与Martin Hellman在1976年提出了一个的密钥交换协议。

1.2 解决什么问题

首先我们先看一个场景:

小明要在网络上给小红发一篇情书,小明呢,比较害羞,不想让其他人知道情书的内容。

那么显而易见,小明必须要对内容进行加密,这个时候就需要选择加密的方式,我们知道对于非对称加密对内容的长度是有限制的,而小明写的情书内容又非常多,那只好选用AES对称加密。

Diffie-Hellman密钥协商算法探究_数据安全_02

我们知道,AES对称加密和解密是需要密钥key的,那么我们假定小明和小红之间需要传递密钥,那么如何保证密钥key的安全性?这时候你可能会说,把密钥key用RSA非对称加密不就好了(数字信封的概念),但我们是否有其他更好的方式解决问题?

这时候,DH密钥协商算法就应运而生,他解决的就是对称加密的密钥无需进行传输,并使小明、小红使用的AES密钥是一致的,那么这是如何实现的呢。

1.3 实现原理

DH算法解决了密钥在双方不直接传递密钥的情况下完成密钥交换,这个神奇的交换原理完全由数学理论支持。

我们来看DH算法交换密钥的步骤。假设小明、小红双方需要传递密钥,他们之间可以这么做:

Diffie-Hellman密钥协商算法探究_数据安全_03

  1. 小明首选选择一个素数Diffie-Hellman密钥协商算法探究_数据安全_04,例如:97,底数Diffie-Hellman密钥协商算法探究_数据安全_05Diffie-Hellman密钥协商算法探究_数据安全_04的一个原根,例如:5,随机数,例如:123,然后计算Diffie-Hellman密钥协商算法探究_数据安全_07 ,然后,小红发送Diffie-Hellman密钥协商算法探究_数据安全_08Diffie-Hellman密钥协商算法探究_数据安全_09Diffie-Hellman密钥协商算法探究_数据安全_10给小红;
  2. 小红收到后,也选择一个随机数Diffie-Hellman密钥协商算法探究_数据安全_11,例如:456,然后计算Diffie-Hellman密钥协商算法探究_数据安全_12 ,小红再同时计算Diffie-Hellman密钥协商算法探究_数据安全_13
  3. 小红把计算的Diffie-Hellman密钥协商算法探究_数据安全_14发给小明,小明计算Diffie-Hellman密钥协商算法探究_数据安全_15,计算结果与乙算出的结果一样,都是22。

所以最终双方协商出的密钥Diffie-Hellman密钥协商算法探究_数据安全_16。注意到这个密钥Diffie-Hellman密钥协商算法探究_数据安全_17并没有在网络上传输。而通过网络传输的Diffie-Hellman密钥协商算法探究_数据安全_04,Diffie-Hellman密钥协商算法探究_数据安全_05Diffie-Hellman密钥协商算法探究_数据安全_20Diffie-Hellman密钥协商算法探究_数据安全_21是无法推算出Diffie-Hellman密钥协商算法探究_数据安全_17的,因为实际算法选择的素数是非常大的。

所以,更确切地说,DH算法是一个密钥协商算法,双方最终协商出一个共同的密钥,而这个密钥不会通过网络传输,来保障了密钥的安全性。此时,小明和小红都露出了开心的笑容。

02 公式推导

本着严谨的态度,现在我们对Diffie-Hellman密钥协商算法探究_数据安全_23Diffie-Hellman密钥协商算法探究_数据安全_24是否恒等做公式推导。一般来说,书上是如下解释:

Diffie-Hellman密钥协商算法探究_数据安全_25

这里是运用了求余的运算规则,也就是说以下等式默认是成立的:

Diffie-Hellman密钥协商算法探究_数据安全_26

其实当成定理记住也就OK的,但是想要证明这个公式也很简单:将求余运算转换为加减乘除运算,然后利用二项式展开公式便可以得到答案。

推导过程:

Diffie-Hellman密钥协商算法探究_数据安全_27

根据①②可得

Diffie-Hellman密钥协商算法探究_数据安全_28

Diffie-Hellman密钥协商算法探究_数据安全_29

将③带入上式,可得

Diffie-Hellman密钥协商算法探究_数据安全_30

使用二项式展开公式将展开,则

Diffie-Hellman密钥协商算法探究_数据安全_31

从这个表达式可以看出,前项每一项都是的整数倍,因此 运算必定为0,因此:

Diffie-Hellman密钥协商算法探究_数据安全_32

所以

Diffie-Hellman密钥协商算法探究_数据安全_33

成立。

03 应用实现

注:本示例以Java服务端作为小明,Android客户端作为小红,下图为执行顺序。

Diffie-Hellman密钥协商算法探究_数据安全_34

1.客户端发起请求

获取服务端的p,g,serverNum

// 获取服务器的p,g,serverNum
Request request = new Request.Builder()
.get()
.url("https://xxxxx/dh/getdhbasedata")
.build();
Call call = mHttpClient.newCall(request);
Response res = call.execute();

2. 服务端创建信息

创建DHServer类

public class DHServer {
/** 用来生成大素数p */
private static final String SOURCE = "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF";
/** 大素数p */
private BigInteger mP;
/** 原根g */
private BigInteger mG;
/** 服务端随机数值 */
private int mServerNum
}

DHServer中增加初始化方法:

/**
* 初始化p g serverNum 以及计算服务端的processedServerNum
* @return HashMap<String, String> 返回初始化创建好的p g serverNum 以及计算服务端的processedServerNum
*/
public HashMap<String, String> init() {
generateBaseInfo();
HashMap<String, String> baseData = new HashMap<>();
baseData.put("p", mP.toString());
baseData.put("g", mG.toString());
baseData.put("serverNumr", mServerNum + "");
baseData.put("processedServerNum", processServerKey());
return baseData;
}

DHServer中增加创建基础信息方法:

/**
* 生成基础信息,p,g,服务端随机数serverNum
*/
private void generateBaseInfo () {
// 第一步:根据pSource生成服务器当前固定的p
BigInteger p = new BigInteger(SOURCE, 16);
BigInteger tempP;
BigInteger g;
BigInteger gFlag;
while (true) {
tempP = p.subtract(new BigInteger("1"));
// 取一个2-p中间的随机数
g = getBigIntegerRandomRange(new BigInteger("2"), tempP);
gFlag = g.modPow(tempP, p);
if (gFlag.toString().equals("1")) {
break;
}
}
Random serverNumRd = new Random();
this.mServerNum = serverNumRd.nextInt(100000) + 100;
this.mG = g;
this.mP = p;
}

DHServer中计算服务端的数值processedServerNum

/**
* 返回已处理的服务端processedServerNum
* @return processedServerNum
*/
private String processServerKey() {
return mG.modPow((new BigInteger(mServerNum + "")), mP).toString();
}

3. 客户端收到信息后进行计算

接收服务端数据

JSONObject data = new JSONObject(res.body().string());
String p = data.getString("p");
String g = data.getString("g");
String processedServerNum = data.getString("processedServerNum");

创建DHClient类并在构造方法中生成客户端随机数mClientNum

public class TiDHClient {
private final int mClientNum;
private BigInteger mP;
private BigInteger mG;
private BigInteger mProcessedServerNum;
private BigInteger mProcessedClientNum;
private BigInteger mKey;
public TiDHClient() {
mClientNum = new Random().nextInt(99999 - 10000) + 10000;
}
}

DHClient增加计算方法,计算出密钥key与客户端计算值mProcessedClientNum

/**
* 通过服务端获取的 p, g 和processedServerNum计算密钥key.
* @param p 通过服务端获取的 p
* @param g 通过服务端获取的 g
* @param serverNum 通过服务端获取的 server number
* @return 密钥字符串
*/
public String processKey(String p, String g, String processedServerNum) {
mP = new BigInteger(p);
mG = new BigInteger(g);
mProcessedServerNum = new BigInteger(processedServerNum);
mProcessedClientNum = mG.modPow(new BigInteger(String.valueOf(mClientNum)), mP);
// 计算密钥key
mPublicKey = mServerNumber.modPow(new BigInteger(String.valueOf(mClientNum)), mP);
return mPublicKey.toString();
}

DHClient中添加get方法

/**
* 获取 processedClientNum. 用于发送给服务端.
* 如果未调用 processKey 将返回空字符串.
* @return processedClientNum.
*/
public String getProcessedClientNum() {
if (mProcessedClientNum == null) {
return "";
}
return mProcessedClientNum.toString();
}

/**
* 返回密钥字符串.
* 如果未调用processKey 将返回空字符串
* @return public key
*/
public String getKey() {
if (mKey == null) {
return "";
}
return mKey.toString();
}

4.客户端将processedClientNum计算结果给服务端

// 根据processedServerNum,processedClientNum和p 计算出密钥K
TiDHClient dhClient = new TiDHClient();
mClientKey = dhClient.processKey(p, g, serverNumber);
// 将计算过后的processedClientNum发送给服务器
FormBody formBody = new FormBody
.Builder()
.add("processedClientNum",dhClient.getProcessedClientNum())
.build();
request = new Request.Builder()
.post(formBody)
.url("https://xxxxxxxxxx/dh/postdhclientdata")
.build();
call = mHttpClient.newCall(request);
res = call.execute();
data = new JSONObject(res.body().string());

5.服务端计算密钥key

DHServer中添加计算方法

/**
* 根据客户端传过来的processedClientNum 计算出key
* @param processedClientNum 客户端传过来的processedClientNum
* @param serverNum 上一次请求随机生成的serverNum
* @param p 上一次请求的 p
* @return String 密钥key
*/
public String computeShareKey (String processedClientNum, String serverNumber, String p) {
BigInteger BigClientNumber = new BigInteger(processedClientNum);
return BigClientNumber.modPow(new BigInteger(serverNumber + ""), new BigInteger(p)).toString();
}

怎么样,看到这里是否感觉这像是握手的过程,其实HTTPS的TLS1.3版本也引入了DH的概念来保证安全性。此外,p,g的生成还可以用RSA的公钥和私钥,这时候就会演变成DH-RSA算法。同时p,g的生成是放在服务端还是放在客户端其实各有优缺点,大家可以考虑下。

学会这些,我们也可以在业务中仿写数据传输的工具SDK,只要在初始化阶段进行协商,那么就能得到一个无法被抓包和破解的加密key,希望对大家的实践有所帮助。

——END——

推荐阅读:

​贴吧低代码高性能规则引擎设计​

​浅谈权限系统在多利熊业务应用​

​分布式系统关键路径延迟分析实践​

​百度工程师教你玩转设计模式(装饰器模式)​

​百度工程师带你体验引擎中的nodejs​

​揭秘百度智能测试在测试定位领域实践​

标签:BigInteger,Hellman,String,return,密钥,new,Diffie,服务端
From: https://blog.51cto.com/u_15082365/5999408

相关文章

  • Windows EC2实例自动轮换密钥符合企业合规性
    通常情况下,在组织或者企业中,各种环境都有较为严格的合规性控制,不管是访问权限还是各种资源等等,在这里我来介绍一下密码定时轮换的相关操作。--课程与题库整理--相关题库......
  • mac版达芬奇软件DaVinci Resolve Studio 18 v18.1.2B6密钥版
    mac版达芬奇软件哪里可以下载呢?小编为大家带来了mac版达芬奇软件DaVinciResolveStudio18v18.1.2B6密钥版,DaVinciResolve18破解版新增了几十项新功能和流程改进,使得剪......
  • 使用密钥对登录服务器
    使用SSH登录服务器的方式有两种。第一种是IP、密码登录。第二种是通过密钥对登录。这两种方法各有优缺点,使用IP、密码登录是最常见的方式,但是这种登录方式不安全,假如你没......
  • 通过Veritas Usage Insights下载客户注册密钥
    从NetBackup8.1.2起,在安装软件时必须要有客户注册密钥,否则无法进行安装部署,所以需要先到VeritasUsageInsights下载注册密钥文件(注意:此密钥文件并非许可证)。试用购买时......
  • 批量分发密钥脚本
    #!/bin/bash#目标主机列表IP="192.168.10.51192.168.10.52192.168.10.53192.168.10.54192.168.10.55192.168.10.56192.168.10.57192.168.10.58192.168.10.59192.168.10.601......
  • Linux设置密钥登录
    使用密钥登录分为以下步骤:1、生成密钥(公钥与私钥)2、放置公钥(PublicKey)到服务器指定用户目录的.ssh/authorized_key文件中;3、配置SSH客户端使用密钥登录。4、测试密......
  • 使用百度地图API申请密钥流程
    1、百度中搜索百度地图进行查找  2、点击控制台  3、进行开发者认证   有这个标识即可进行申请密钥 4、申请密钥        点击应用管理中的......
  • 密钥登陆报Permissions 0644
    登陆方式:修改配置文件/etc/ssh/sshd_config,将"PasswordAuthenticationyes"修改为"PasswordAuthenticationno"重启ssh服务生成密钥在服务器端输入命令:[root@local......
  • Git辅助bash脚本,-i指定独立密钥访问远程仓库,并智能判断是否需要使用网络代理
    劫持Git命令在个人配置文件(~/.bash_profile或~/.bashrc)中新建一个名为git的函数,注意,此处函数名称必须为git,这样在终端执行git命令时,才会优先调用我们定义好的Bash函数,而......
  • 生产事故-错误密钥引发的接口通信问题
    入职多年,面对生产环境,尽管都是小心翼翼,慎之又慎,还是难免捅出篓子。轻则满头大汗,面红耳赤。重则系统停摆,损失资金。每一个生产事故的背后,都是宝贵的经验和教训,都是项目成员......