栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

非对称加密 DH算法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

非对称加密 DH算法

DH算法简介

迪菲-赫尔曼密钥交换(Diffie–Hellman key exchange,缩写为D-H) 是一种安全协议。
它可以让双方在完全没有对方任何预先信息的条件下通过不安全信道创建起一个密钥。
这个密钥可以在后续的通讯中作为对称密钥来加密通讯内容。

迪菲-赫尔曼通过公共信道交换一个信息,就可以创建一个可以用于在公共信道上安全通信的对称密钥

交换过程

原理

最简单,最早提出的个协议使用一个质数p的整数模n乘法群以及其原根g。下面展示这个算法,绿色表示非秘密信息,红色粗体表示秘密信息:

爱丽丝和鲍伯最终都得到了同样的值,因为在模p下 g^{ab} 和 g^{ba} 相等。 注意a, b 和 g^ab = g^ba mod p 是秘密的。 其他所有的值 p, g, g^a mod p, 以及 g^b mod p 都可以在公共信道上传递。 一旦爱丽丝和鲍伯得出了公共秘密,他们就可以把它用作对称密钥,以进行双方的加密通讯,因为这个密钥只有他们才能得到。

这个问题就是著名的离散对数问题。注意g则不需要很大,并且在一般的实践中通常是2或者5。IETF RFC3526 文档中有几个常用的大质数可供使用。


以下是一个更为一般的描述:

    爱丽丝和鲍伯协商一个有限循环群 G 和它的一个生成元 g。 (这通常在协议开始很久以前就已经规定好; g是公开的,并可以被所有的攻击者看到。)爱丽丝选择一个随机自然数 a 并且将 g^a mod p 发送给鲍伯。鲍伯选择一个随机自然数 b 并且将 g^b mod p 发送给爱丽丝。爱丽丝 计算 g^{ba} mod p鲍伯 计算 g^{ab} mod p
java jdk实现

DhUtils.java

package crypto.dh2;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.crypto.*;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;


public class DhUtils {

    
    private static final String ALGORITHM = "DH";

    
    public static final String DEFAULT_ALGORITHM = "DES";

    
    private static final int DEFAULT_KEY_SIZE = 1024;

    public static InnerKey generateSenderKey() throws NoSuchAlgorithmException {
        return generateSenderKey(DEFAULT_KEY_SIZE);
    }

    
    public static InnerKey generateSenderKey(int keySize)
            throws NoSuchAlgorithmException {
        KeyPairGenerator senderGenerator = KeyPairGenerator.getInstance(ALGORITHM);
        senderGenerator.initialize(keySize);
        KeyPair senderKeyPair = senderGenerator.generateKeyPair();
        return InnerKey.builder()
                .publicKey(senderKeyPair.getPublic().getEncoded())
                .privateKey(senderKeyPair.getPrivate().getEncoded())
                .build();
    }

    
    public static InnerKey generateReceiverKey(byte[] senderPublicKeyBytes)
            throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidAlgorithmParameterException {
        // 根据发送方公钥 初始化接收方密钥
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(senderPublicKeyBytes);
        PublicKey senderPublicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        DHParameterSpec dhParameterSpec = ((DHPublicKey) senderPublicKey).getParams();
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
        keyPairGenerator.initialize(dhParameterSpec);
        KeyPair receiverKeyPair = keyPairGenerator.generateKeyPair();
        return InnerKey.builder()
                .publicKey(receiverKeyPair.getPublic().getEncoded())
                .privateKey(receiverKeyPair.getPrivate().getEncoded())
                .build();
    }

    
    public static SecretKey computeSecretKey(byte[] publicKeyBytes, byte[] privateKeyBytes, String algorithm)
            throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);

        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBytes);
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

        KeyAgreement keyAgreement = KeyAgreement.getInstance(keyFactory.getAlgorithm());
        keyAgreement.init(privateKey);
        keyAgreement.doPhase(publicKey, true);
        SecretKey secretKey = keyAgreement.generateSecret(algorithm);
        return secretKey;
    }

    public static byte[] encrypt(byte[] receiverPublicKey, byte[] senderPrivateKey, byte[] data)
            throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, NoSuchPaddingException,
            BadPaddingException, IllegalBlockSizeException {
        return encrypt(receiverPublicKey, senderPrivateKey, data, DEFAULT_ALGORITHM);
    }

    
    public static byte[] encrypt(byte[] receiverPublicKey, byte[] senderPrivateKey, byte[] data, String algorithm)
            throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, NoSuchPaddingException,
            BadPaddingException, IllegalBlockSizeException {
        SecretKey secretKey = computeSecretKey(receiverPublicKey, senderPrivateKey, algorithm);
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] bytes = cipher.doFinal(data);
        return bytes;
    }

    public static byte[] decrypt(byte[] senderPublicKey, byte[] receiverPrivateKey, byte[] data)
            throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, NoSuchPaddingException,
            BadPaddingException, IllegalBlockSizeException {
        return decrypt(senderPublicKey, receiverPrivateKey, data, DEFAULT_ALGORITHM);
    }

    
    public static byte[] decrypt(byte[] senderPublicKey, byte[] receiverPrivateKey, byte[] data, String algorithm)
            throws NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException, NoSuchPaddingException,
            BadPaddingException, IllegalBlockSizeException {
        SecretKey secretKey = computeSecretKey(senderPublicKey, receiverPrivateKey, algorithm);
        Cipher cipher = Cipher.getInstance(algorithm);
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] bytes = cipher.doFinal(data);
        return bytes;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public static class InnerKey {
        private byte[] publicKey;
        private byte[] privateKey;
    }
}

测试代码

package crypto.dh2;

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

import javax.crypto.SecretKey;
import java.util.Objects;


public class DhUtilsTest {

    public static void main(String[] args) throws Exception {
        String text = "DH算法是一个密钥协商算法,双方最终协商出一个共同的密钥,而这个密钥不会通过网络传输";
        DhUtils.InnerKey senderKey = DhUtils.generateSenderKey();
        System.out.println("发送者公钥:" + base64.encodebase64String(senderKey.getPublicKey()));
        System.out.println("发送者私钥:" + base64.encodebase64String(senderKey.getPrivateKey()));

        DhUtils.InnerKey receiverKey = DhUtils.generateReceiverKey(senderKey.getPublicKey());
        System.out.println("接收者公钥:" + base64.encodebase64String(receiverKey.getPublicKey()));
        System.out.println("接收者私钥:" + base64.encodebase64String(receiverKey.getPrivateKey()));

        String algorithm = "DES";
        SecretKey senderSecretKey = DhUtils.computeSecretKey(receiverKey.getPublicKey(), senderKey.getPrivateKey(), algorithm);
        SecretKey receiverSecretKey = DhUtils.computeSecretKey(senderKey.getPublicKey(), receiverKey.getPrivateKey(), algorithm);
        if (Objects.equals(senderSecretKey, receiverSecretKey)) {
            System.out.println("密钥生成成功");
        } else {
            throw new RuntimeException("密钥生成失败");
        }

        // 加密
        byte[] bytes = DhUtils.encrypt(receiverKey.getPublicKey(), senderKey.getPrivateKey(), text.getBytes(), algorithm);
        System.out.println("密文:" + base64.encodebase64String(bytes));

        // 解密
        byte[] result = DhUtils.decrypt(senderKey.getPublicKey(), receiverKey.getPrivateKey(), bytes, algorithm);
        System.out.println("明文:" + new String(result));
    }

}

code

补充知识

理解 Deffie-Hellman 密钥交换算法 中关于求模公式的说明

假设 q 为素数,对于正整数 a,x,y,有:
(a^x mod p)^y mod p = a^(xy) mod p

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/781732.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号