1.对称加密与非对称加密概述

关于对称加密与非对称加密的概念这里不再多说,感兴趣可以看下我之前的几篇文章,下面说一说两者的主要区别。

对称加密算法数据安全,密钥管理复杂,密钥传递过程复杂,存在密钥泄露问题。

非对称加密算法强度复杂、安全性依赖于算法与密钥。但是由于算法复杂,使得非对称算法加解密速度没有对称算法加解密的速度快。

对称密钥体制中只有一种密钥,并且是非公开的。如果要解密就得让对方知道密钥。所以保证其安全性就是保证密钥的安全。

非对称密钥体制有两种密钥,其中一个是公开的,这样就可以不需要像对称密码那样向对方传输密钥了。因此安全性就大了很多。

对称加密 非对称加密
算法复杂度
加解密速度
安全性
常见算法 DES、3DES、Blowfish、IDEA、RC4、RC5、RC6、AES RSA、DSA、ECC、Diffie-Hellman、El Gamal

2.DH算法实现过程及相关类详解

Diffie-Hellman算法(D-H算法),密钥一致协议。是由公开密钥密码体制的奠基人Diffie和Hellman所提出的一种思想。简单的说就是允许两名用户在公开媒体上交换信息以生成"一致"的、可以共享的密钥。换句话说,就是由甲方产出一对密钥(公钥、私钥),乙方依照甲方公钥产生乙方密钥对(公钥、私钥)。以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥(SecretKey)对数据加密。这样,在互通了本地密钥(SecretKey)算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以使用对方的公钥和自己的私钥对数据解密。不单单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯!该算法源于中国的同余定理——中国馀数定理。

流程分析:

1.甲方构建密钥对儿,将公钥公布给乙方,将私钥保留;双方约定数据加密算法;乙方通过甲方公钥构建密钥对儿,将公钥公布给甲方,将私钥保留。

2.甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给乙方加密后的数据;乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。

3.乙方使用私钥、甲方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥加密数据,发送给甲方加密后的数据;甲方使用私钥、乙方公钥、约定数据加密算法构建本地密钥,然后通过本地密钥对数据解密。

Java代码:

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Objects;

public class DH {
    private static final String src = "dh test";

    public static void main(String[] args) {
        jdkDH();
    }

    // jdk实现:
    public static void jdkDH() {
        try {
            // 1.发送方初始化密钥,将公钥给接收方
            KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance("DH");
            senderKeyPairGenerator.initialize(512);
            KeyPair senderKeyPair = senderKeyPairGenerator.generateKeyPair();
            // 发送方公钥,发送给接收方(通过网络或文件的形式)
            PublicKey senderPublicKey = senderKeyPair.getPublic(); // 公钥
            PrivateKey senderPrivateKey = senderKeyPair.getPrivate(); // 私钥

            // 接收方还原发送方公钥
            KeyFactory receiverKeyFactory = KeyFactory.getInstance("DH");
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(senderPublicKey.getEncoded());
            senderPublicKey = receiverKeyFactory.generatePublic(x509EncodedKeySpec);

            // 2.接收方通过发送方的公钥构建密钥,将公钥给发送方
            DHParameterSpec dhParameterSpec = ((DHPublicKey) senderPublicKey).getParams();
            KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance("DH");
            receiverKeyPairGenerator.initialize(dhParameterSpec);
            KeyPair receiverKeypair = receiverKeyPairGenerator.generateKeyPair();
            PrivateKey receiverPrivateKey = receiverKeypair.getPrivate(); // 私钥
            PublicKey receiverPublicKey = receiverKeypair.getPublic(); // 公钥

            // 3.接收方使用自己的私钥和发送方的公钥构建本地密钥
            KeyAgreement receiverKeyAgreement = KeyAgreement.getInstance("DH");
            receiverKeyAgreement.init(receiverPrivateKey);
            receiverKeyAgreement.doPhase(senderPublicKey, true);
            SecretKey receiverDesKey = receiverKeyAgreement.generateSecret("DES");

            // 发送方还原接收方公钥
            KeyFactory senderKeyFactory = KeyFactory.getInstance("DH");
            x509EncodedKeySpec = new X509EncodedKeySpec(receiverPublicKey.getEncoded());
            receiverPublicKey = senderKeyFactory.generatePublic(x509EncodedKeySpec);

            // 4.发送方使用自己的私钥和接收方的公钥构建本地密钥
            KeyAgreement senderKeyAgreement = KeyAgreement.getInstance("DH");
            senderKeyAgreement.init(senderPrivateKey);
            senderKeyAgreement.doPhase(receiverPublicKey, true);
            SecretKey senderDesKey = senderKeyAgreement.generateSecret("DES");

            if (Objects.equals(receiverDesKey, senderDesKey)) {
                System.out.println("双方密钥相同");
            }

            // 5.发送方使用本地密钥加密
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, senderDesKey);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("bc dh encrypt:" + Base64.getEncoder().encodeToString(result));

            // 6.接收方使用本地密钥解密
            cipher.init(Cipher.DECRYPT_MODE, receiverDesKey);
            result = cipher.doFinal(result);
            System.out.println("bc dh decrypt:" + new String(result));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

注意:因为JDK的版本问题,如果遇到异常java.security.NoSuchAlgorithmException: Unsupported secret key algorithm: DES,可以在运行的时候追加JVM参数-Djdk.crypto.KeyAgreement.legacyKDF=true

3.RSA算法实现及应用

RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。

RSA算法支持公钥加密、私钥解密以及私钥加密、公钥解密。既可以用于加密也可用于数字签名。

关于更多RSA算法的实现原理等,本文不再讨论。

Java代码:

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class RSA {
    public static final String src = "rsa test";

    public static void main(String[] args) {
        jdkRSA();
    }

    // jdk实现:
    public static void jdkRSA() {
        try {
            // 1.生成公钥和私钥
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(512);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
            System.out.println("Public Key:" + Base64.getEncoder().encodeToString(rsaPublicKey.getEncoded()));
            System.out.println("Private Key:" + Base64.getEncoder().encodeToString(rsaPrivateKey.getEncoded()));

            // 2.私钥加密、公钥解密 ---- 加密
            //PKCS8EncodedKeySpec类表示私钥的ASN.1编码。
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] result = cipher.doFinal(src.getBytes());
            System.out.println("私钥加密、公钥解密 ---- 加密:" + Base64.getEncoder().encodeToString(result));

            // 3.私钥加密、公钥解密 ---- 解密
            //X509EncodedKeySpec类表示根据ASN.1类型SubjectPublicKeyInfo编码的公钥的ASN.1编码。
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
            keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            result = cipher.doFinal(result);
            System.out.println("私钥加密、公钥解密 ---- 解密:" + new String(result));

            // 4.公钥加密、私钥解密 ---- 加密
            //X509EncodedKeySpec类表示根据ASN.1类型SubjectPublicKeyInfo编码的公钥的ASN.1编码。
            X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
            KeyFactory keyFactory2 = KeyFactory.getInstance("RSA");
            PublicKey publicKey2 = keyFactory2.generatePublic(x509EncodedKeySpec2);

            Cipher cipher2 = Cipher.getInstance("RSA");
            cipher2.init(Cipher.ENCRYPT_MODE, publicKey2);
            byte[] result2 = cipher2.doFinal(src.getBytes());
            System.out.println("公钥加密、私钥解密 ---- 加密:" + Base64.getEncoder().encodeToString(result2));

            // 5.私钥解密、公钥加密 ---- 解密
            //PKCS8EncodedKeySpec类表示私钥的ASN.1编码。
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
            KeyFactory keyFactory5 = KeyFactory.getInstance("RSA");
            PrivateKey privateKey5 = keyFactory5.generatePrivate(pkcs8EncodedKeySpec5);
            Cipher cipher5 = Cipher.getInstance("RSA");
            cipher5.init(Cipher.DECRYPT_MODE, privateKey5);
            byte[] result5 = cipher5.doFinal(result2);
            System.out.println("公钥加密、私钥解密 ---- 解密:" + new String(result5));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

图解流程:

4.ElGamal算法

在密码学中,ElGamal加密算法是一个基于迪菲-赫尔曼密钥交换的非对称加密算法。它在1985年由塔希尔·盖莫尔提出。GnuPG和PGP等很多密码学系统中都应用到了ElGamal算法。

ElGamal算法只提供了公钥加密,私钥解密形式,Jdk中没有实现,Bouncy Castle中对其进行了实现。

导入Bouncy Castle依赖:

<dependency>
     <groupId>org.bouncycastle</groupId>
     <artifactId>bcprov-jdk15</artifactId>
     <version>1.46</version>
</dependency>

Java代码:

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.DHParameterSpec;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class ElGamal {
    //非对称密钥算法
    public static final String EL_GAMAL = "ElGamal";
    /**
     * 密钥长度,DH算法的默认密钥长度是1024
     * 密钥长度必须是8的倍数,在160到16384位之间
     */
    private static final int KEY_SIZE = 256;

    public static void main(String[] args) throws Exception {
        System.out.println("=============接收方构建密钥对=============");
        // 加入对BouncyCastle支持
        Security.addProvider(new BouncyCastleProvider());
        AlgorithmParameterGenerator apg = AlgorithmParameterGenerator.getInstance(EL_GAMAL);
        //初始化参数生成器
        apg.init(KEY_SIZE);
        //生成算法参数
        AlgorithmParameters params = apg.generateParameters();
        //构建参数材料
        DHParameterSpec elParams = params.getParameterSpec(DHParameterSpec.class);
        //实例化密钥生成器
        KeyPairGenerator kpg = KeyPairGenerator.getInstance(EL_GAMAL);
        //初始化密钥对生成器
        kpg.initialize(elParams, new SecureRandom());
        KeyPair keyPair = kpg.generateKeyPair();
        //甲方公钥
        PublicKey publicKey = keyPair.getPublic();
        //甲方私钥
        PrivateKey privateKey = keyPair.getPrivate();
        System.out.println("公钥:" + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
        System.out.println("私钥:" + Base64.getEncoder().encodeToString(privateKey.getEncoded()));
        System.out.println("=============密钥对构造完毕,接收方将公钥公布给发送方=============");
        String str = "ElGamal密码交换算法";
        System.out.println("原文:" + str);
        System.out.println("=============发送方还原接收方公钥,并使用公钥对数据进行加密=============");
        //还原公钥
        KeyFactory keyFactory = KeyFactory.getInstance(EL_GAMAL);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey.getEncoded());
        publicKey = keyFactory.generatePublic(x509KeySpec);
        System.out.println("公钥:" + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
        //数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] bytes = cipher.doFinal(str.getBytes());
        System.out.println("加密后的数据:" + Base64.getEncoder().encodeToString(bytes));
        System.out.println("=============接收方使用私钥对数据进行解密===========");
        //还原私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
        keyFactory = KeyFactory.getInstance(EL_GAMAL);
        privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        //数据解密
        cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] bytes1 = cipher.doFinal(bytes);
        System.out.println("解密后的数据:" + new String(bytes1));
    }
}

图解流程:

DH、RSA与ElGamal非对称加密算法实现及应用的更多相关文章

  1. Java进阶(七)Java加密技术之非对称加密算法RSA

    Java加密技术(四)--非对称加密算法RSA 非对称加密算法--RSA 基本概念 非对称加密算法是一种密钥的保密方法. 非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(priv ...

  2. 非对称加密RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等。使用最广泛的是RSA算法

          非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey).公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密:如果用私 ...

  3. 加密算法大全图解 :密码体系,对称加密算法,非对称加密算法,消息摘要, Base64,数字签名,RSA,DES,MD5,AES,SHA,ElGamal,

    1. 加密算法大全: ***************************************************************************************** ...

  4. 非对称加密算法--DH

    注意:本节内容主要参考自<Java加密与解密的艺术(第2版)>第8章“高等加密算法--非对称加密算法” 11.1.非对称加密算法 特点: 发送方和接收方均有一个密钥对(公钥+私钥),其中公 ...

  5. Java 加密解密 对称加密算法 非对称加密算法 MD5 BASE64 AES RSA

    版权声明:本文为博主原创文章,未经博主允许不得转载. [前言] 本文简单的介绍了加密技术相关概念,最后总结了java中现有的加密技术以及使用方法和例子 [最简单的加密] 1.简单的概念 明文:加密前的 ...

  6. java-信息安全(五)-非对称加密算法RSA

    概述 信息安全基本概念: RSA算法(Ron Rivest.Adi Shamir.Leonard Adleman,人名组合) RSA RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rive ...

  7. 第十一章 非对称加密算法--DH

    注意:本节内容主要参考自<Java加密与解密的艺术(第2版)>第8章“高等加密算法--非对称加密算法” 11.1.非对称加密算法 特点: 发送方和接收方均有一个密钥对(公钥+私钥),其中公 ...

  8. 非对称加密算法DH

    特点: 发送方和接收方均有一个密钥对(公钥+私钥),其中公钥传播,私钥自己保存,不需要传播 私钥不需要传播的特性解决了对称加密算法中密钥传播的困难(这个困难一般通过线下传递可以解决) 加密安全性极高, ...

  9. 非对称加密算法-RSA

    注意:本节内容主要参考自<Java加密与解密的艺术(第2版)>第8章“高等加密算法--非对称加密算法” 12.1.RSA(最经典的非对称加密算法) 特点: 使用一套密钥即可完成加解密(与D ...

随机推荐

  1. 通过OSG实现对模型的日照模拟

    目录 1. 加载模型 2. 光照 1) 环境反射 2) 漫反射 3) 日照方向 (1) 太阳高度角和太阳方位角 (2) 计算过程 4) 改进实现 3. 阴影 4. 太阳高度角与太阳方位角的计算 1) ...

  2. 求你了,再问你Java内存模型的时候别再给我讲堆栈方法区了…

    GitHub 4.1k Star 的Java工程师成神之路 ,不来了解一下吗? GitHub 4.1k Star 的Java工程师成神之路 ,真的不来了解一下吗? GitHub 4.1k Star 的 ...

  3. IM推送保障及网络优化详解(一):如何实现不影响用户体验的后台保活

    对于移动APP来说,IM功能正变得越来越重要,它能够创建起人与人之间的连接.社交类产品中,用户与用户之间的沟通可以产生出更好的用户粘性. 在复杂的 Android 生态环境下,多种因素都会造成消息推送 ...

  4. 曹工说Tomcat3:深入理解 Tomcat Digester

    一.前言 我写博客主要靠自己实战,理论知识不是很强,要全面介绍Tomcat Digester,还是需要一定的理论功底.翻阅了一些介绍 Digester 的书籍.博客,发现不是很系统,最后发现还是官方文 ...

  5. php函数引用

    //在自定义函数中,前面加一个&符号,是对返回静态变量的引用 function &test(){ static $a; $a += 1; echo $a; return $a; } / ...

  6. wireshark数据包分析实战 第一章

    1,数据包分析工具:tcpdump.wireshark.前者是命令行的,后者是图形界面的. 分析过程:收集数据.转换数据(二进制数据转换为可读形式).分析数据.tcpdump不提供分析数据,只将最原始 ...

  7. 设计模式-桥接模式(Bridge)

    桥接模式是构造型模式之一.把抽象(Abstraction)与行为实现(Implementor)分离开来,从而可以保持各部分的独立性以及应对它们的功能扩展. 角色和职责: 1.抽象类(Abstracti ...

  8. 004-python-列表、元组、字典

    1. 什么是列表 列表是一个可变的数据类型 列表由[]来表示, 每一项元素使用逗号隔开. 列表什么都能装. 能装对象的对象. 列表可以装大量的数据 2. 列表的索引和切片 列表和字符串一样. 也有索引 ...

  9. 源码阅读 - java.util.concurrent (二)CAS

    背景 在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题. ...

  10. JDK1.8集合之HashMap

    目录 简介 内部实现 类的属性 Node数组 重要方法 put()和putVal()方法 get()和getNode()方法 resize()方法 容量设置为2的幂的优点 计算Hash时候 扩容时候 ...