RSA加密

2/22/2017来源:ASP.NET技巧人气:1972

最近一直在和保险公司做对接,发现保险公司为了数据的安全一直都在用非对称加密算法(RSA)来保证数据的安全,以前也了解过RSA的原理,就是文字的理解,但是时间一长就忘了,这次正好重新整理一下,顺便一个demo 奉献上。

为什么要有RSA

为什么呢,因为他相对安全呀,既然说到相对,就有相对不安全的,以前大家为了加密数据,都是用的对称加密,意思就是进行数据交互的书双方用一套规则,甲方用这个规则来加密,把加密的数据给乙方,乙方根据这个规则反推,把数据解密出来,但是有一个问题,其中一方把这个规则丢了,数据就不再安全。 那么为什么RSA可以呢,RSA在1977年就又三个大神Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密,他的大致思想就是把以前的一套规则转而去用两套规则生成两个秘钥,一个称为公钥,一个称为私钥公钥可以给任何人,但是私钥自己留着,这样只要私钥不丢,数据就是安全的,迄今为止还没有能破解2048位的秘钥,所以来说相对安全。具体私钥和公钥是如何生成的,大家可以看这篇博客RSA算法原理,讲的很详细,我就不粘贴了。

如何用java实现

工具类如下

package com.algor; import org.apache.commons.codec.binary.Base64; import org.apache.commons.collections.map.HashedMap; 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.Map; /** * Created by menghaibin on 2017/2/19. */ public class RSATest { private static final String KEY_ALGORITHM = "RSA"; private static final String SIGNATURE_ALGORITHM = "md5withRSA"; private static final String PUBLIC_KEY = "RSAPublicKey"; private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * 初始化公钥和私钥 * @return * @throws Exception */ public static Map<String,Object> initKey() throws Exception{ KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM); pairGenerator.initialize(1024); KeyPair keyPair = pairGenerator.generateKeyPair(); RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); Map<String,Object> map = new HashedMap(2); map.put(PUBLIC_KEY,publicKey); map.put(PRIVATE_KEY,privateKey); return map; } public static String encryptBASE64(byte[] key) throws Exception { //return (new BASE64Encoder()).encodeBuffer(key); return Base64.encodeBase64String(key); } public static byte[] decryptBASE64(String key) throws Exception { //return (new BASE64Decoder()).decodeBuffer(key); return Base64.decodeBase64(key); } /** * 获取公钥 * @param map * @return */ public static String getPublicKey(Map<String,Object> map){ Key key = (Key) map.get(PUBLIC_KEY); try { return encryptBASE64(key.getEncoded()); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 获取私钥 * @param map * @return */ public static String getPrivateKey(Map<String,Object> map){ Key key = (Key) map.get(PRIVATE_KEY); try { return encryptBASE64(key.getEncoded()); } catch (Exception e) { e.printStackTrace(); } return null; } /** * 用私钥加密 * @param data 数据 * @param key 私钥 * * @return */ public static byte[] encryptByPrivateKey(byte[] data,String key) throws Exception { //对秘钥解密 byte[] keyBytes = decryptBASE64(key); //取得私钥 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); //对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE,privateKey); return cipher.doFinal(data); } /** * 用公钥加密数据 * @param data 数据 * @param key 公钥 * @return 返回加密的数据 * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data,String key) throws Exception{ byte[] keyBytes = decryptBASE64(key); //取得公钥 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicKey = factory.generatePublic(x509EncodedKeySpec); //对数据加密 Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE,publicKey); return cipher.doFinal(data); } /** * 用公钥解密 * @param data * @param key * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] data,String key) throws Exception{ byte[] keyBytes = decryptBASE64(key); //取得公钥 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicKey = factory.generatePublic(x509EncodedKeySpec); //对数据解密 Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE,publicKey); return cipher.doFinal(data); } /** * 用公钥解密 * @param data * @param key * @return * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] data,String key) throws Exception{ byte[] keyBytes = decryptBASE64(key); //取得私钥 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateKey = factory.generatePrivate(pkcs8EncodedKeySpec); //用私钥解密 Cipher cipher = Cipher.getInstance(factory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE,privateKey); return cipher.doFinal(data); } public static boolean verify(byte[] data,String publicKey,String sign) throws Exception { //解密由64编码的公钥 byte[] keyBytes = decryptBASE64(publicKey); //构造X509EncodedKeySpec的方法 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes); //KEY_ALGORITHM指定的加密算法 KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM); //取公钥对象 PublicKey pubKey = factory.generatePublic(x509EncodedKeySpec); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initVerify(pubKey); signature.update(data); return signature.verify(decryptBASE64(sign)); } /** * 用私钥对信息生成数字签名 * * @param data * 加密数据 * @param privateKey * 私钥 * * @return * @throws Exception */ public static String sign(byte[] data, String privateKey) throws Exception { // 解密由base64编码的私钥 byte[] keyBytes = decryptBASE64(privateKey); // 构造PKCS8EncodedKeySpec对象 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); // KEY_ALGORITHM 指定的加密算法 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); // 取私钥匙对象 PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec); // 用私钥对信息生成数字签名 Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(priKey); signature.update(data); return encryptBASE64(signature.sign()); } }

如何使用

甲方构建密钥对儿,将公钥公布给乙方,将私钥保留。 甲方使用私钥加密数据,然后用私钥对加密后的数据签名,发送给乙方签名以及加密后的数据;乙方使用公钥、签名来验证待解密数据是否有效,如果有效使用公钥对数据解密。 乙方使用公钥加密数据,向甲方发送经过加密后的数据;甲方获得加密数据,通过私钥解密。 RSA流程

public String publicKey; public String privateKey; /** * 获取privateKey和publicKey * @throws Exception */ @Before public void setUp() throws Exception { Map<String,Object> map = RSATest.initKey(); publicKey = RSATest.getPublicKey(map); privateKey =RSATest.getPrivateKey(map); System.out.println("publicKey-----"+publicKey); System.out.println("privateKey--------"+privateKey); } /** * 甲方用私钥加密数据,并签名给乙方,乙方验证,通过公钥则进行解密 * @throws Exception */ @Test public void testA2B() throws Exception { //1.甲方用私钥加密数据 String inputStr = "menghaibin"; byte[] encryptByPrivate = RSATest.encryptByPrivateKey(inputStr.getBytes(),privateKey); //2.甲方用私钥进行签名 String sign = RSATest.sign(encryptByPrivate,privateKey); //3.乙方用甲方的加密数据和签名来验证数据是否有效 boolean flag = RSATest.verify(encryptByPrivate,publicKey,sign); System.out.println(flag); //如果有效,则乙方使用公钥进行解密 byte[] decryptCode = RSATest.decryptByPublicKey(encryptByPrivate,publicKey); String menghaibin = new String(decryptCode); System.out.println(menghaibin); } /** * 乙方讲加密的书给甲方,甲方用私钥解密 * @throws Exception */ @Test public void testb2a() throws Exception { //1.乙方用公钥进行加密 String inputStr = "menghaibin2号"; byte[] encryByPublic = RSATest.encryptByPublicKey(inputStr.getBytes(),publicKey); byte[] decryptByPrivate = RSATest.decryptByPrivateKey(encryByPublic,privateKey); System.out.println("outputstr---------" + new String(decryptByPrivate)); }

结果如下 乙方解密甲方的加密数据 乙方解密甲方的加密数据 甲方解密乙方的数据结果 这里写图片描述

小结

简单总结一下,甲方通过私钥加密数据给乙方和签名给乙方,乙方用公钥验证,然后可以的话,就公钥解密。 乙方通过公钥加密,甲方可以用私钥解密,其他的不能解密。