JAVA加密算法- 非对称加密算法(DH,RSA)的详细介绍
非对称密码概念
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的适用情景一:
(1)服务器生成一个公钥和一个私钥,把公钥公开了.
(2)客户端使用公钥把数据进行加密,上交服务器.别人是没法理解加密后的数据的.
(3)服务器使用私钥将数据解密,查看用户提交的数据.
这种情景下,公钥像是一个信箱,每个人都可以往这个信箱里面放信,但是这个信箱里面的信只有掌握信箱钥匙的人才能开箱查看.
rsa适用情景二:
(1)皇上生成一个公钥和一个密钥,把公钥公开了.
(2)皇上发布了一封诏书,昭告天下.诏书右下角有两串数字,第一串数字是一个随机串,第二串数字是用私钥加密第一串数字所得的结果.
(3)有人不相信这诏书是皇上写的,就把第二串数字使用公钥解密,解密之后发现跟第一串数字一样,说明确实是皇上写的,因为一般人没有密钥,也就没法加密那些能够用公钥解密的数据.
这种情境下,公钥用于解密,私钥用于加密,这可以用于发布公告时,证明这个公告确实是某个人发的.相当于签名.
实际上,签名没有必要特别长,一般情况下,签名是定长的,要想定长,可以使用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)); } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Java并发编程总结——慎用CAS详解
下一篇: MyBatis传入参数的实例代码