非对称密码概念
1、与对称加密算法的主要差别在于,加密和解密的密钥不相同,一个公开(公钥),一个保密(私钥)。主要解决了对称加密算法密钥分配管理的问题,提高了算法安全性。
2、非对称加密算法的加密、解密的效率比较低。在算法设计上,非对称加密算法对待加密的数据长度有着苛刻的要求。例如RSA算法要求待加密的数据不得大于53个字节。
3、非对称加密算法主要用于 交换对称加密算法的密钥,而非数据交换
4、java6提供实现了DH和RSA两种算法。Bouncy Castle提供了E1Gamal算法支持。除了上述三种算法还有一个ECC算法,目前没有相关的开源组件提供支持
需要两个密钥进行加密或解密,分为公钥和私钥
特点:安全性高,速度慢
用途:【密钥交换(DH)】
双方在没有确定共同密钥的情况下,生成密钥,不提供加密工作,加解密还需要其他对称加密算法实现
DH算法示例
import javax.crypto.KeyAgreement; import javax.crypto.interfaces.DHPrivateKey; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DHParameterSpec; import java.security.*; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; //1 生成源密钥 //2 把源公钥交给目标,目标通过源公钥,生成目标公钥和私钥 //3 把目标公钥交给源 //4 双方使用对方的公钥和和自己的私钥,生成本地密钥 //5 如果双方生成本地密钥相同则完成密钥交换 public class DHUtil { public static final String PUBLIC_KEY = "DH_Public_Key"; public static final String PRIVATE_KEY = "DH_Private_key"; /** * 生成源密钥对 * @return * @throws Exception */ public static Map<String,Object> initSourceKey() throws Exception{ //创建KeyPairGenerator的实例,选用DH算法 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH"); //初始化密钥长度,默认1024,可选范围512-65536 & 64的倍数 keyPairGenerator.initialize(1024); //生成密钥对 KeyPair keyPair = keyPairGenerator.generateKeyPair(); DHPublicKey dhPublicKey = (DHPublicKey) keyPair.getPublic(); DHPrivateKey dhPrivateKey = (DHPrivateKey) keyPair.getPrivate(); //将密钥对放入Map Map<String,Object> keyMap = new HashMap<String, Object>(); keyMap.put(PUBLIC_KEY, dhPublicKey); keyMap.put(PRIVATE_KEY, dhPrivateKey); return keyMap; } /** * 通过源公钥 生成 目标密钥对 * @param sourcePublicKey * @return * @throws Exception */ public static Map<String,Object> initTargetKey(byte[] sourcePublicKey) throws Exception { KeyFactory keyFactory = KeyFactory.getInstance("DH"); //通过源公钥,生成keySpec,使用KeyFactory生成源PublicKey相关信息 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(sourcePublicKey); DHPublicKey sourcePublic = (DHPublicKey) keyFactory.generatePublic(keySpec); DHParameterSpec dhPublicKeyParams = sourcePublic.getParams(); KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH"); keyPairGenerator.initialize(dhPublicKeyParams); KeyPair keyPair = keyPairGenerator.generateKeyPair(); DHPublicKey dhPublicKey = (DHPublicKey) keyPair.getPublic(); DHPrivateKey dhPrivateKey = (DHPrivateKey) keyPair.getPrivate(); //将密钥对放入Map Map<String,Object> keyMap = new HashMap<String, Object>(); keyMap.put(PUBLIC_KEY, dhPublicKey); keyMap.put(PRIVATE_KEY, dhPrivateKey); return keyMap; } /** * 使用一方的公钥和另一方的私钥,生成本地密钥 * @return */ public static byte[] generateLocalSecretKey(byte[] aPublicKey, byte[] bPrivateKey) throws Exception{ KeyFactory keyFactory = KeyFactory.getInstance("DH"); //通过A公钥,生成keySpec,使用KeyFactory生成A PublicKey相关信息 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(aPublicKey); PublicKey publicKey = keyFactory.generatePublic(keySpec); //通过B私钥,生成B PrivateKey相关信息 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bPrivateKey); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); //通过KeyAgreement对A的PublicKey和B的PrivateKey进行加密 KeyAgreement keyAgreement = KeyAgreement.getInstance("DH"); keyAgreement.init(privateKey); keyAgreement.doPhase(publicKey,true); return keyAgreement.generateSecret("AES").getEncoded();//算法使用对称加密算法(DES,DESede,AES) //return keyAgreement.generateSecret(); // 也可以不选择算法,使用默认方法计算 } //获取公钥字节数组 public static byte[] getPublicKey(Map<String,Object> map){ return ((DHPublicKey) map.get(PUBLIC_KEY)).getEncoded(); } //获取私钥字节数组 public static byte[] getPrivateKey(Map<String,Object> map){ return ((DHPrivateKey) map.get(PRIVATE_KEY)).getEncoded(); } public static void main(String[] args) throws Exception { byte[] source_public_key; byte[] source_private_key; byte[] source_local_key; byte[] target_public_key; byte[] target_private_key; byte[] target_local_key; Map<String, Object> sourceKey = initSourceKey(); source_public_key = getPublicKey(sourceKey); source_private_key = getPrivateKey(sourceKey); System.out.println("源公钥:"+BytesToHex.fromBytesToHex(source_public_key)); System.out.println("源私钥:"+BytesToHex.fromBytesToHex(source_private_key)); Map<String, Object> targetKey = initTargetKey(getPublicKey(sourceKey)); target_public_key = getPublicKey(targetKey); target_private_key = getPrivateKey(targetKey); System.out.println("目标公钥:"+BytesToHex.fromBytesToHex(target_public_key)); System.out.println("目标私钥:"+BytesToHex.fromBytesToHex(target_private_key)); source_local_key = generateLocalSecretKey(target_public_key, source_private_key); target_local_key = generateLocalSecretKey(source_public_key, target_private_key); System.out.println("源本地密钥:"+BytesToHex.fromBytesToHex(source_local_key)); System.out.println("目标本地密钥:"+BytesToHex.fromBytesToHex(target_local_key)); } }
【加密/解密(RSA)】【数字签名(RSA)】
RSA算法晚于DH算法,这五个字母全都是人名首字母.DH算法是第一个非对称密码体系.
RSA算法运算速度慢,不适宜加密大量数据.一种解决方案是,将RSA跟对称加密方式混合使用,将数据使用对称加密方式加密,对称加密的密钥使用RSA算法加密,因为密钥很短,所以时间费不了太多.实际上,对称加密方式唯一的弊端就是密钥不好传递,对称加密方式也很难破解.
RSA的适用情景一:
服务器生成一个公钥和一个私钥,把公钥公开了.
客户端使用公钥把数据进行加密,上交服务器.别人是没法理解加密后的数据的.
服务器使用私钥将数据解密,查看用户提交的数据.
这种情景下,公钥像是一个信箱,每个人都可以往这个信箱里面放信,但是这个信箱里面的信只有掌握信箱钥匙的人才能开箱查看.
RSA适用情景二:
皇上生成一个公钥和一个密钥,把公钥公开了.
皇上发布了一封诏书,昭告天下.诏书右下角有两串数字,第一串数字是一个随机串,第二串数字是用私钥加密第一串数字所得的结果.
有人不相信这诏书是皇上写的,就把第二串数字使用公钥解密,解密之后发现跟第一串数字一样,说明确实是皇上写的,因为一般人没有密钥,也就没法加密那些能够用公钥解密的数据.
这种情境下,公钥用于解密,私钥用于加密,这可以用于发布公告时,证明这个公告确实是某个人发的.相当于签名.
实际上,签名没有必要特别长,一般情况下,签名是定长的,要想定长,可以使用MessageDigest算法,如MD5和SHA系列.所以就有了多种签名算法,如MD5withRSA等.
RSA 加密/解密 示例
import javax.crypto.Cipher; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.HashMap; import java.util.Map; /** * RSA加密工具 */ public class RSAUtil { public static final String PUBLIC_KEY = "RSA_Public_Key"; public static final String PRIVATE_KEY = "RSA_Private_Key"; /** * 初始化密钥 * @return * @throws Exception */ public static Map<String,Object> initKey() throws Exception{ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(1024);//512-65536 & 64的倍数 KeyPair keyPair = keyPairGenerator.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String,Object> keyMap = new HashMap<String, Object>(); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } public static RSAPublicKey getPublicKey(Map<String,Object> keyMap) { return (RSAPublicKey) keyMap.get(PUBLIC_KEY); } public static RSAPrivateKey getPrivateKey(Map<String,Object> keyMap){ return (RSAPrivateKey) keyMap.get(PRIVATE_KEY); } /** * 使用公钥对数据进行加密 * @param data * @param publicKey * @return * @throws Exception */ public static byte[] encrypt(byte[] data, RSAPublicKey publicKey) throws Exception{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE,publicKey); return cipher.doFinal(data); } /** * 使用私钥解密 * @param data * @param privateKey * @return * @throws Exception */ public static byte[] decrypt(byte[] data, RSAPrivateKey privateKey) throws Exception{ Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE,privateKey); return cipher.doFinal(data); } public static void main(String[] args) throws Exception { String data = "周杰伦-东风破"; Map<String, Object> keyMap = initKey(); byte[] miwen = encrypt(data.getBytes(),getPublicKey(keyMap)); System.out.println("加密后的内容:"+BytesToHex.fromBytesToHex(miwen)); byte[] plain = decrypt(miwen, getPrivateKey(keyMap)); System.out.println("解密后的内容:"+new String(plain)); } }
以上就是本文的全部内容,希望对大家的学习有所帮助