java密码学-非对称加密算法

简介: 非对称加密算法与对称加密算法的主要区别在于非对称加密算法用于加密和解密的密钥不同,一个公开,称为公钥;一个保密,称为私钥。因此,非对称密码算法也称为双钥和公钥加密算法。非对称加密算法解决了对称加密算法密钥分配问题,并极大的提高了算法的安全性。多种B2C或B2B应用均使用非对称加密算法作为数据加密的核心算法。解决了对称加密算法的密钥存储问题。

一、简介



非对称加密算法与对称加密算法的主要区别在于非对称加密算法用于加密和解密的密钥不同,一个公开,称为公钥;一个保密,称为私钥。因此,非对称密码算法也称为双钥和公钥加密算法。


非对称加密算法解决了对称加密算法密钥分配问题,并极大的提高了算法的安全性。多种B2C或B2B应用均使用非对称加密算法作为数据加密的核心算法。解决了对称加密算法的密钥存储问题。


二、分类



非对称加密算法源于DH算法,其后主要分为两类:


「1. 基于因子分解难题:」RSA算法(可用于数字加密和数字签名)

「2. 基于离散对数难题:」DSA算法(数字签名算法)、ECC算法(椭圆曲线加密)算法以曲线方程式为基础产生密钥(传统使用大质数的积产生),可以做到更快、更小,并且更有效。


三、DH(密钥交换算法)



DH算法是一个密钥协商算法、仅能用于密钥分配,再通过这个密钥对数据进行加密和解密处理。


import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class DH {
    //非对称加密密钥算法
    public static final String KEY_ALGORITHM = "DH";
    //本地密钥算法,即对称加密算法
    public static final String SECRET_ALGORITHM = "AES";
    /**
     * 密钥长度
     * DH算法默认密钥长度为1024
     * 密钥长度必须是64的倍数,其范围在512位到1024位之间
     */
    private static final int KEY_SIZE = 512;
    //公钥
    public static final String PUBLIC_KEY = "DHPublicKey";
    //私钥
    public static final String PRIVATE_KEY = "DHPrivateKey";
    /**
     * 初始化甲方密钥
     * @return
     * @throws Exception
     */
    public static Map<String,Object> initKey() throws Exception {
        //实例化密钥生成器
        KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化密钥生成器
        keyPairGenerator.initialize(KEY_SIZE);
        //生成密钥对
        KeyPair keyPair=keyPairGenerator.generateKeyPair();
        //甲方公钥
        DHPublicKey publicKey=(DHPublicKey) keyPair.getPublic();
        //甲方私钥
        DHPrivateKey privateKey=(DHPrivateKey) keyPair.getPrivate();
        //将密钥存储在map中
        Map<String,Object> keyMap=new HashMap<String,Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }
    /**
     * 生成乙方密钥
     * @param key 甲方公钥
     * @return
     * @throws Exception
     */
    public static Map<String,Object> initKey(byte[] key) throws Exception {
        //解析甲方的公钥
        //转换公钥的材料
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
        //实例化密钥工厂
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
        //产生公钥
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
        //由甲方的公钥构造乙方密钥
        DHParameterSpec dhParamSpec=((DHPublicKey)pubKey).getParams();
        //实例化密钥生成器
        KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(keyFactory.getAlgorithm());
        //初始化密钥生成器
        keyPairGenerator.initialize(dhParamSpec);
        //产生密钥对
        KeyPair keyPair=keyPairGenerator.genKeyPair();
        //乙方公钥
        DHPublicKey publicKey=(DHPublicKey)keyPair.getPublic();
        //乙方私钥
        DHPrivateKey privateKey=(DHPrivateKey)keyPair.getPrivate();
        //将密钥存储在Map中
        Map<String,Object> keyMap=new HashMap<String,Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }
    /**
     * 加密
     * @param data 待加密数据
     * @param key 密钥
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data,byte[] key) throws Exception {
        //还原秘密密钥
        SecretKey secretKey = new SecretKeySpec(key,SECRET_ALGORITHM);
        //创建加解密对象
        Cipher cipher = Cipher.getInstance(SECRET_ALGORITHM);
        //初始化为加密模式
        cipher.init(Cipher.ENCRYPT_MODE,secretKey);
        //加密
        return cipher.doFinal(data);
    }
    /**
     *解密
     * @param data 待解密数据
     * @param key 密钥
     * @return 解密数据
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data,byte[] key) throws Exception {
        //还原秘密密钥
        SecretKey secretKey = new SecretKeySpec(key,SECRET_ALGORITHM);
        //创建加解密对象
        Cipher cipher = Cipher.getInstance(SECRET_ALGORITHM);
        //初始化为解密模式
        cipher.init(Cipher.DECRYPT_MODE,secretKey);
        //解密
        return cipher.doFinal(data);
    }
    /**
     * 生成本地密钥
     * @param publicKey 公钥
     * @param privateKey 私钥
     * @return 本地密钥
     * @throws Exception
     */
    public static byte[] getSecretKey(byte[] publicKey,byte[] privateKey) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        //实例化密钥工厂
        KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
        //初始化公钥
        //密钥材料转换
        X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(publicKey);
        //产生公钥
        PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
        //初始化私钥
        //密钥材料转换
        PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(privateKey);
        //产生私钥
        PrivateKey priKey=keyFactory.generatePrivate(pkcs8KeySpec);
        //实例化
        KeyAgreement keyAgree = KeyAgreement.getInstance(keyFactory.getAlgorithm());
        //初始化
        keyAgree.init(priKey);
        keyAgree.doPhase(pubKey, true);
        //生成本地密钥
        SecretKey secretKey = keyAgree.generateSecret(SECRET_ALGORITHM);
        return secretKey.getEncode();
    }
    /**
     * 获取密钥
     * @param keys 存储密钥的map对象
     * @param keyType 密钥类型
     * @return
     * @throws Exception
     */
    public  static  byte[] getKey(Map<String,Object> keys,String keyType) throws Exception {
        Key key = (Key) keys.get(keyType);
        return key.getEncoded();
    }
    /**
     * 转换为Base64String
     * @param data 待加密数据
     * @return
     */
    public static String toBase64String(byte[] data){
        return Base64.encodeBase64String(data);
    }
    @Test
    public void test() throws Exception {
         //生成甲方密钥对
        Map<String,Object> keys = DH.initKey();
        //甲方公钥
        byte[] pubKey1 = DH.getKey(keys,DH.PUBLIC_KEY);
        //甲方私钥
        byte[] priKey1 = DH.getKey(keys, DH.PRIVATE_KEY);
        System.out.println("甲方公钥:"+DH.toBase64String(pubKey1));
        System.out.println("甲方私钥:"+DH.toBase64String(priKey1));
        //生成乙方密钥对
        Map<String,Object> keys1 = DH.initKey(pubKey1);
        //乙方公钥
        byte[] pubKey2 = DH.getKey(keys1,DH.PUBLIC_KEY);
        //乙方私钥
        byte[] priKey2 = DH.getKey(keys1, DH.PRIVATE_KEY);
        System.out.println("乙方公钥:"+DH.toBase64String(pubKey2));
        System.out.println("乙方私钥:"+DH.toBase64String(priKey2));
        //甲方本地密钥
        byte[] secret1 = DH.getSecretKey(pubKey2,priKey1);
        //乙方本地密钥
        byte[] secret2 = DH.getSecretKey(pubKey1,priKey2);
        System.out.println("甲方本地密钥:"+DH.toBase64String(secret1));
        System.out.println("乙方本地密钥:"+DH.toBase64String(secret2));
        String text1 = "算法怎么没用";
        byte[] data = DH.encrypt(text1.getBytes("utf-8"),secret1);
        System.out.println(DH.toBase64String(DH.decrypt(data,secret2)));
    }
    //输出结果
    甲方公钥:MIHgMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANEAAJBAJXzgB2MZ/GD3nfiwsfXy45+VAHYRuoYvzWbUCUtba+M82ec2VYK/t/dr5NH89KitK5WKD6TvpBwGui5OY8WjOM=
    甲方私钥:MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEAtG2dpvIXfNObwStWvopwppUmekkDtfUPX3Pg+xpiL0DoiVIFVQvP/UTijB+laO64
    乙方公钥:MIHgMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgANEAAJBANpVJymcJssw3O8xcSeWZyPmjBBoPwHMJOln0eOsW+FFyKHzNO9GIysuMkE1GrEVqA0b6uQ+gRmku4/8oA183i0=
    乙方私钥:MIHSAgEAMIGXBgkqhkiG9w0BAwEwgYkCQQD8poLOjhLKuibvzPcRDlJtsHiwXt7LzR60ogjzrhYXrgHzW5Gkfm32NBPF4S7QiZvNEyrNUNmRUb3EPuc3WS4XAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykAgIBgAQzAjEAvBjOMSA4FKWc1d6JPy2wEXT7f5Kpu9WuJbmwL7DGa+b39pScBVCebXf3lJy1+yBW
    甲方本地密钥:Oe6gr0aq4fVIeO5/yUVcnPVLlv1jYcmG4ntEm3fAMBcn6CrpM4OnJX3DX4vxaYR9GVIOWhL8CEA+Z6Z7hP3Vpg==
    乙方本地密钥:Oe6gr0aq4fVIeO5/yUVcnPVLlv1jYcmG4ntEm3fAMBcn6CrpM4OnJX3DX4vxaYR9GVIOWhL8CEA+Z6Z7hP3Vpg==
    算法怎么没用


四、RSA算法



RSA算法可以用来数据加密和数字签名,使用一套密钥对,公钥长度远小于私钥长度,并遵循"公钥加密,私钥解密"和"私钥加密,公钥解密"这两项原则。


package algorithm;
import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
public class RSADecoder {
    //公钥
    public static final String PUBLIC_KEY = "PublicKey";
    //私钥
    public static final String PRIVATE_KEY = "PrivateKey";
    //非对称加密密钥算法
    public static final String KEY_ALGORITHM = "RSA";
    //密钥长度
    private static final int KEY_SIZE = 512;
    /**
     * 私钥解密
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data,byte[] key) throws  Exception {
        PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(encodedKeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE,privateKey);
        return cipher.doFinal(data);
    }
    /**
     * 公钥加密
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data,byte[] key) throws Exception {
        X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(encodedKeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE,publicKey);
        return cipher.doFinal(data);
    }
    /**
     * 私钥加密
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data,byte[] key) throws Exception {
        PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey privateKey = keyFactory.generatePrivate(encodedKeySpec);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE,privateKey);
        return cipher.doFinal(data);
    }
    /**
     * 公钥加密
     * @param data
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception {
        X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(key);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey publicKey = keyFactory.generatePublic(encodedKeySpec);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        return cipher.doFinal(data);
    }
    /**
     * 生成密钥
     * @return
     * @throws Exception
     */
    public static Map<String,Object> initKey() throws Exception {
        //实例化密钥生成器
        KeyPairGenerator keyPairGenerator=KeyPairGenerator.getInstance(KEY_ALGORITHM);
        //初始化密钥生成器
        keyPairGenerator.initialize(KEY_SIZE);
        //生成密钥对
        KeyPair keyPair=keyPairGenerator.generateKeyPair();
        PublicKey publicKey= keyPair.getPublic();
        PrivateKey privateKey= keyPair.getPrivate();
        Map<String,Object> keyMap=new HashMap<String,Object>();
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }
    /**
     * 获取密钥
     * @param keys
     * @param keyType
     * @return
     * @throws Exception
     */
    public  static  byte[] getKey(Map<String,Object> keys,String keyType) throws Exception {
        Key key = (Key) keys.get(keyType);
        return key.getEncoded();
    }
}
@Test
public void test() throws Exception {
    Map<String, Object> stringObjectMap = RSADecoder.initKey();
        byte[] pubKey = RSADecoder.getKey(stringObjectMap,RSADecoder.PUBLIC_KEY);
        byte[] priKey = RSADecoder.getKey(stringObjectMap,RSADecoder.PRIVATE_KEY);
        System.out.println("公钥:"+Base64.encodeBase64String(pubKey));
        System.out.println("私钥:"+Base64.encodeBase64String(priKey));
        //公钥加密,私钥解密
        String str = "公钥加密,私钥解密";
        byte[] data = RSADecoder.encryptByPublicKey(str.getBytes("utf-8"),pubKey);
        System.out.println(new String(RSADecoder.decryptByPrivateKey(data,priKey),"utf-8"));
        //私钥加密,公钥解密
        str = "私钥加密,公钥解密";
        data = RSADecoder.encryptByPrivateKey(str.getBytes("utf-8"),priKey);
        System.out.println(new String(RSADecoder.decryptByPublicKey(data,pubKey),"utf-8"));
}
//输出结果
公钥:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI/0dZZmoODkEFXqFnrjAlY1OdKjO2G1tHorC3trUU7zMKuAtlOO3yzdO5sFqpnaHQInOfYYcAalbxosUNjqjL8CAwEAAQ==
私钥:MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAj/R1lmag4OQQVeoWeuMCVjU50qM7YbW0eisLe2tRTvMwq4C2U47fLN07mwWqmdodAic59hhwBqVvGixQ2OqMvwIDAQABAkAqA2e6IHO9jvIxkONEtDI/ZMNedWNkTfrBWQS93YFab/ETsyv14EUuEjzobMuvDvKnSUZOQ/kGh6c4oozvrEn5AiEAz5S26Rjv12SUjlLdV7/n65f2mVfRY8G4tZf4W8TSD/MCIQCxiHGarRfnDal/pWw4Z/UkM5HlYRFYtpMNvrq9/9sPBQIgHWCjnkucLfSbHaVWlAOh0/LWwI7wIFkbRf/y8zHgtMcCIBwmnp0ARYIF0JLFEFwBYAXVh5Tvx2hhyv+q9sGaCIphAiAcSXumoKYNBzEUFROwQNnSeWre4wGWP5V96+7AuDhqNQ==
公钥加密,私钥解密
私钥加密,公钥解密


五、ElGamal算法



ElGamal算法是一种基于离散对数问题的非对称加密算法,该算法既可以用于加密,又可以用于数字签名,是除了RSA算法最具有代表性的公钥加密算法之一。遵循"公钥加密,私钥解密"的部分。


//简单的实现
        Security.addProvider(new BouncyCastleProvider());
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ElGamal");
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        PrivateKey privateKey = keyPair.getPrivate();
        PublicKey publicKey = keyPair.getPublic();
        //加密
        Cipher cipher = Cipher.getInstance(keyPairGenerator.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE,publicKey);
        byte[] data = cipher.doFinal("公钥加密,私钥解密".getBytes("utf-8"));
        System.out.println("加密后数据:"+new String(data,"utf-8"));
        Cipher cipher1 = Cipher.getInstance(keyPairGenerator.getAlgorithm());
        cipher1.init(Cipher.DECRYPT_MODE,privateKey);
        System.out.println("解密后数据:"+new String(cipher1.doFinal(data),"utf-8"));
        //输出结果
        加密后数据:???'??|$L?*a????BC?#C?!r=????B=??K??????VQ??J;??FE?s^?????5????!Ok?p?? 5?c?vj*&6BM???F"??O?;K?|???`?Eo?,??????;>?????U?+?m?u?a&??'? Y2??N?`????b?l7??O'????/??l???f;o?a[???????????&??
        解密后数据:公钥加密,私钥解密
目录
相关文章
|
6天前
|
算法 安全 网络安全
非对称加密算法RSA
RSA是一种基于数论的非对称加密算法,依赖大整数质因数分解的困难性保证安全性。它生成公钥和私钥,公钥加密,私钥解密,适用于数据加密、数字签名和互联网安全等领域。尽管计算效率低、适合小量数据处理,但由于其兼容性、安全性和广泛应用于SSL/TLS、数字签名等,RSA仍是主流加密算法之一。
12 2
|
8天前
|
算法 数据安全/隐私保护
对称密钥加密算法和公开密钥加密算法有什么区别
【4月更文挑战第19天】对称密钥和公开密钥加密算法各有特点:对称密钥加密速度快,适用于大量数据,但密钥管理困难;公开密钥加密安全性高,密钥管理方便,但速度慢,常用于数字签名和身份验证。两者在不同场景下有不同优势。
25 6
|
1月前
|
算法 Java
Java使用Cipher.getInstance(“AES/ECB/PKCS5Padding“);加解密算法工具类实现
Java使用Cipher.getInstance(“AES/ECB/PKCS5Padding“);加解密算法工具类实现
33 0
|
1月前
|
存储 算法 Java
Java数据结构与算法-java数据结构与算法(二)
Java数据结构与算法-java数据结构与算法
98 1
|
4天前
|
安全 算法 网络安全
|
6天前
|
设计模式 算法 Java
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式
|
11天前
|
机器学习/深度学习 数据采集 算法
使用 Java 实现机器学习算法
【4月更文挑战第19天】Java在数据驱动时代为机器学习提供支持,具备丰富的数学和数据结构库,适用于实现线性回归、决策树、SVM和随机森林等算法。实现时注意数据预处理、模型选择、评估指标和可视化。利用Java的库和编程能力可构建高效模型,但需按问题需求选择合适技术和优化方法。
|
15天前
|
安全 算法 网络安全
软件体系结构 - 非对称加密算法
软件体系结构 - 非对称加密算法
13 0
|
21天前
|
算法 安全 Java
java代码 实现AES_CMAC 算法测试
该代码实现了一个AES-CMAC算法的简单测试,使用Bouncy Castle作为安全提供者。静态变量K定义了固定密钥。`Aes_Cmac`函数接受密钥和消息,返回AES-CMAC生成的MAC值。在`main`方法中,程序对给定的消息进行AES-CMAC加密,然后模拟接收ECU的加密结果并进行比较。如果两者匹配,输出&quot;验证成功&quot;,否则输出&quot;验证失败&quot;。辅助方法包括将字节转为16进制字符串和将16进制字符串转为字节。
|
22天前
|
Java 数据安全/隐私保护
java base64 加密 解密
java base64 加密 解密