【Java小工匠聊密码学】--非对称加密--DH密钥交换算法

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 1、DH密钥交换概述Diffie-Hellman由Whitfield Diffie和Martin Hellman在1976年公布的一种密钥一致性算法。Diffie-Hellman是一种建立密钥的方法,而不是加密方法。

1、DH密钥交换概述

Diffie-Hellman由Whitfield Diffie和Martin Hellman在1976年公布的一种密钥一致性算法。Diffie-Hellman是一种建立密钥的方法,而不是加密方法。然而,它所产生的密钥可用于加密、进一步的密钥管理或任何其它的加密方式。Diffie-Hellman密钥交换算法及其优化首次发表的公开密钥算法出现在Diffie和Hellman的论文中,这篇影响深远的论文奠定了公开密钥密码编码学。

2、DH密钥交换算法原理

2.1、使用颜色形象描述

设想这样一个场景,Alice(A)和Bob(B),他们想在不见面的情况下秘密约定出一种颜色,但他们互相沟通的信息都会被公开,应该怎么办呢?


DH密钥交换算法

秘密在于,颜色混合是一种“不可逆”的操作,当双方交换颜色时,尽管我们知道他们交换的颜色都是由一份黄色和另一份其他颜色混合得到的,但我们还是无法或者很难得到他们的私密颜色。

2.2、数学算法

2.2.1 算法背景

乘方得逆运算称为对数运算,比如已知 7^x = 49 那么可知 x=log(7,49)=2。 对数运算非常容易,即使在数字很大的时候是,但如果是下面的情况 7^xmod13=8 。 求X的过程称为“离散对数”,就不那么容易了,在数字很大时几乎是一个不可能的运算,而DH秘钥交换就是利用了这种离散对数计算非常困难的特性来设计的。

2.2.2 取模运算规律

公式里的mod是取模运算,取模运算有几条基本的定律如下:
(a+b) mod P =(a mod P+b mod P) mod P
(a∗b) mod P = (a mod P∗b mod P) mod P
(a^b) mod P = (a mod P)^b) mod P

2.2.3 密钥交换流程

根据上面的公式,可以推导出一个非常重要的公式。
(G^(a∗b)) mod P=(G^a mod P)^b mod P=(G^b mod P)^a mod P
根据这个公式,我们可以向上面交换颜色那样设计出一个秘密交换数字的流程出来。


交换流程

最终两个人得到的秘密数字都是g^(ab) mod p,而窃听者仅从p,g,A,B四个公开信息,是无法得到这个秘密数字的!

2.2.4举例说明

第1步.爱丽丝与鲍伯协定使用p=23以及g=5.
第2步.爱丽丝选择一个秘密整数a=6, 计算A = g^a mod p并发送给鲍伯。 A = 5^6 mod 23 = 8.
第3步.鲍伯选择一个秘密整数b=15, 计算B = g^b mod p并发送给爱丽丝。
B = 5^15 mod 23 = 19.
第4步.爱丽丝计算
s = B a mod p
19^6 mod 23 = 2.
第5步.鲍伯计算s = A b mod p
8^15 mod 23 = 2.

3、DH密钥交换算用途

可以用作对称加密算法中,双方约定的加密准则的交换(对方的公钥和自己的私钥计算的到秘密整数,可以作为双方的加密准则)。交换双方可以在不共享任何秘密的情况下协商出一个密钥。

4、中间人攻击

由于密钥交换本身并没有提供通讯双方的身份验证服务,因此它很容易受到中间人攻击。 一个中间人“丙”在信道的中央进行两次迪菲-赫尔曼密钥交换,一次和甲,另一次和乙,就能够成功的向甲假装自己是乙,反之亦然。而攻击者可以解密(读取和存储)任何一个人的信息并重新加密信息,然后传递给另一个人。因此通常都需要一个能够验证通讯双方身份的机制来防止这类攻击。

5、算法实现

5.1、JDK算法实现

package lzf.cipher;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;

import org.apache.commons.codec.binary.Hex;

/**
 * @author java小工匠
 */
public class DHUtils {

    // 甲方初始化密钥对
    public static KeyPair initKey() {
        try {
            // 实例化密钥对生成器
            KeyPairGenerator generator = KeyPairGenerator.getInstance("DH");
            // 初始化密钥对生成器参数 默认1024 512-1024之间64的倍数
            generator.initialize(1024);
            // 产生密钥对
            KeyPair keyPair = generator.genKeyPair();
            return keyPair;
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    // 乙方初始化密钥生成对
    public static KeyPair initKey(byte[] key) {
        try {
            // 公钥从字节数组转换为PublicKey
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key);
            // 实例化密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance("DH");
            // 还原甲方的公钥
            DHPublicKey dhPublicKey = (DHPublicKey) keyFactory.generatePublic(keySpec);
            // 剖析甲方公钥,得到其参数
            DHParameterSpec dhParameterSpec = dhPublicKey.getParams();
            // 实例化密钥对生成器
            KeyPairGenerator generator = KeyPairGenerator.getInstance("DH");
            // 使用得到的参数,初始化密钥生成器
            generator.initialize(dhParameterSpec);
            return generator.generateKeyPair();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    // 获取公钥
    public static byte[] getPublicKey(KeyPair keyPair) {
        byte[] bytes = keyPair.getPublic().getEncoded();
        return bytes;
    }

    // 获取公钥
    public static String getPublicKeyStr(KeyPair keyPair) {
        byte[] bytes = keyPair.getPublic().getEncoded();
        return Hex.encodeHexString(bytes);
    }

    // 获取私钥
    public static byte[] getPrivateKey(KeyPair keyPair) {
        byte[] bytes = keyPair.getPrivate().getEncoded();
        return bytes;
    }

    // 获取公钥
    public static String getPrivateKeyStr(KeyPair keyPair) {
        byte[] bytes = keyPair.getPrivate().getEncoded();
        return Hex.encodeHexString(bytes);
    }

    // 生成本地密钥
    public static byte[] getSecretKey(byte[] publicKey, byte[] privateKey) {
        try {
            // 实例化密钥工厂
            KeyFactory keyFactory = KeyFactory.getInstance("DH");
            // 将公钥从字节数组转换为PublicKey
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(keySpec);
            // 将私钥从字节数组转换为PrivateKey
            PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(privateKey);
            PrivateKey priKey = keyFactory.generatePrivate(privateSpec);
            // 先实例化KeyAgreement
            KeyAgreement keyAgreement = KeyAgreement.getInstance("DH");
            // 用自己的私钥初始化keyAgreement
            keyAgreement.init(priKey);
            // 结合对方的公钥进行运算
            keyAgreement.doPhase(pubKey, true);
            // 开始生成本地密钥SecretKey 密钥算法为对称密码算法
            SecretKey key = keyAgreement.generateSecret("AES");
            return key.getEncoded();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static void main(String[] args) {
        KeyPair keyPair1 = initKey();
        byte[] publicKey1 = getPublicKey(keyPair1);
        String publicKeyStr1 = Hex.encodeHexString(publicKey1);
        byte[] privateKey1 = getPrivateKey(keyPair1);
        String privateKeyStr1 = Hex.encodeHexString(privateKey1);
        System.out.println("甲方公钥:" + publicKeyStr1);
        System.out.println("甲方私钥:" + privateKeyStr1);
        KeyPair keyPair2 = initKey(publicKey1);
        byte[] publicKey2 = getPublicKey(keyPair2);
        String publicKeyStr2 = Hex.encodeHexString(publicKey2);
        byte[] privateKey2 = getPrivateKey(keyPair2);
        String privateKeyStr2 = Hex.encodeHexString(privateKey2);
        System.out.println("乙方公钥:" + publicKeyStr2);
        System.out.println("乙方私钥:" + privateKeyStr2);
        byte[] secrectKey1 = getSecretKey(publicKey2, privateKey1);
        byte[] secrectKey2 = getSecretKey(publicKey1, privateKey2);
        String secrectKeyStr1 = Hex.encodeHexString(secrectKey1);
        String secrectKeyStr2 = Hex.encodeHexString(secrectKey2);
        System.out.println("甲方协议密钥:"+secrectKeyStr1);
        System.out.println("乙方协议密钥:"+secrectKeyStr2);
        System.out.println("甲=乙:"+secrectKeyStr1.equals(secrectKeyStr2));

    }
}

如果读完觉得有收获的话,欢迎点赞、关注、加公众号【小工匠技术圈】

个人公众号,欢迎关注,查阅更多精彩历史!

image
相关文章
|
1月前
|
搜索推荐 算法 Java
手写快排:教你用Java写出高效排序算法!
快速排序(QuickSort)是经典的排序算法之一,基于分治思想,平均时间复杂度为O(n log n),广泛应用于各种场合。在这篇文章中,我们将手写一个Java版本的快速排序,从基础实现到优化策略,并逐步解析代码背后的逻辑。
44 1
|
12天前
|
安全 Java 数据安全/隐私保护
- 代码加密混淆工具-Java 编程安全性
在Java编程领域,保护代码安全与知识产权至关重要。本文探讨了代码加密混淆工具的重要性,并介绍了五款流行工具:ProGuard、DexGuard、Jscrambler、DashO 和 Ipa Guard。这些工具通过压缩、优化、混淆和加密等手段,提升代码安全性,保护知识产权。ProGuard 是开源工具,用于压缩和混淆Java代码;DexGuard 专为Android应用程序设计,提供强大加密功能;Jscrambler 基于云,保护Web和移动应用的JavaScript及HTML5代码;DashO 支持多种Java平台和
29 1
|
22天前
|
设计模式 缓存 算法
揭秘策略模式:如何用Java设计模式轻松切换算法?
【8月更文挑战第30天】设计模式是解决软件开发中特定问题的可重用方案。其中,策略模式是一种常用的行为型模式,允许在运行时选择算法行为。它通过定义一系列可互换的算法来封装具体的实现,使算法的变化与客户端分离。例如,在电商系统中,可以通过定义 `DiscountStrategy` 接口和多种折扣策略类(如 `FidelityDiscount`、`BulkDiscount` 和 `NoDiscount`),在运行时动态切换不同的折扣逻辑。这样,`ShoppingCart` 类无需关心具体折扣计算细节,只需设置不同的策略即可实现灵活的价格计算,符合开闭原则并提高代码的可维护性和扩展性。
37 2
|
20天前
|
安全 Java 应用服务中间件
网络安全的护城河:漏洞防御与加密技术深入浅出Java并发编程
【8月更文挑战第31天】在数字世界的棋盘上,每一次点击都可能是一步棋。网络安全的战场无声却激烈,漏洞如同裂缝中的风,悄无声息地侵袭着数据的堡垒。本文将揭示网络漏洞的隐蔽角落,探讨如何通过加密技术筑起防线,同时提升个人和组织的安全意识,共同守护我们的数字家园。
|
23天前
|
算法 安全 数据安全/隐私保护
Android经典实战之常见的移动端加密算法和用kotlin进行AES-256加密和解密
本文介绍了移动端开发中常用的数据加密算法,包括对称加密(如 AES 和 DES)、非对称加密(如 RSA)、散列算法(如 SHA-256 和 MD5)及消息认证码(如 HMAC)。重点讲解了如何使用 Kotlin 实现 AES-256 的加密和解密,并提供了详细的代码示例。通过生成密钥、加密和解密数据等步骤,展示了如何在 Kotlin 项目中实现数据的安全加密。
56 1
|
24天前
|
算法 安全 数据安全/隐私保护
Android经典实战之常见的移动端加密算法和用kotlin进行AES-256加密和解密
本文介绍了移动端开发中常用的数据加密算法,包括对称加密(如 AES 和 DES)、非对称加密(如 RSA)、散列算法(如 SHA-256 和 MD5)及消息认证码(如 HMAC)。重点展示了如何使用 Kotlin 实现 AES-256 的加密和解密,提供了详细的代码示例。
31 2
|
26天前
|
算法 JavaScript 前端开发
国标非对称加密:RSA算法、非对称特征、js还原、jsencrypt和rsa模块解析
国标非对称加密:RSA算法、非对称特征、js还原、jsencrypt和rsa模块解析
105 1
|
30天前
|
安全 算法 Java
java系列之~~网络通信安全 非对称加密算法的介绍说明
这篇文章介绍了非对称加密算法,包括其定义、加密解密过程、数字签名功能,以及与对称加密算法的比较,并解释了非对称加密在网络安全中的应用,特别是在公钥基础设施和信任网络中的重要性。
|
1月前
|
存储 算法 Java
在Java中使用MD5对用户输入密码进行加密存储、同时登录验证。
这篇文章详细介绍了在Java项目中如何使用MD5算法对用户密码进行加密存储和登录验证,包括加入依赖、编写MD5工具类、注册时的密码加密和登录时的密码验证等步骤,并通过示例代码和数据库存储信息展示了测试效果。
在Java中使用MD5对用户输入密码进行加密存储、同时登录验证。
|
1月前
|
数据采集 搜索推荐 算法
【高手进阶】Java排序算法:从零到精通——揭秘冒泡、快速、归并排序的原理与实战应用,让你的代码效率飙升!
【8月更文挑战第21天】Java排序算法是编程基础的重要部分,在算法设计与分析及实际开发中不可或缺。本文介绍内部排序算法,包括简单的冒泡排序及其逐步优化至高效的快速排序和稳定的归并排序,并提供了每种算法的Java实现示例。此外,还探讨了排序算法在电子商务、搜索引擎和数据分析等领域的广泛应用,帮助读者更好地理解和应用这些算法。
21 0