一、简介
非对称加密算法与对称加密算法的主要区别在于非对称加密算法用于加密和解密的密钥不同,一个公开,称为公钥;一个保密,称为私钥。因此,非对称密码算法也称为双钥和公钥加密算法。
非对称加密算法解决了对称加密算法密钥分配问题,并极大的提高了算法的安全性。多种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[???????????&?? 解密后数据:公钥加密,私钥解密