package com.face.utils.rsa; import com.sun.org.apache.xml.internal.security.utils.Base64; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import java.security.*; import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; /** * RSA 非对称加密算法的理论依据:基于大数因子分解数学难题。 * * RSA数字签名中为什么不能先加密后签名? * * 用RSA给别人发送一个信息,首先要用私钥加密签名, * 然后再用对方的公钥加密信息和签名,把消息发送给对方。 * * @desc 使用要求:先签名,再加密 * * RSA算法中:公钥长度 << 远小于 私钥长度,必须遵循[公钥加密 则 私钥解密],[私钥加密 则 公钥解密]这两个原则。 * * 使用流程:data --> 签名 --> 加密 --> 解密 --> 校验签名 --> data * * 加/解密原则: */ public abstract class RSACoder { /** * 数字签名密钥算法 */ public static final String KEY_ALGORITHM = "RSA"; /** * 数字签名 - 签名/验证算法 */ public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; // 公钥 private static final String PUBLIC_KEY = "RSAPublicKey"; // 私钥 private static final String PRIVATE_KEY = "RSAPrivateKey"; /** * RSA - 密钥长度,默认1024位,密钥长度必须是64的倍数,范围在512 ~ 65536 之间。 */ private static final int keySize = 512; /** * @desc 签名(私钥) * @param data 要签名的数据 * @param privateKey 私钥 * @return byte[] 数字签名 */ public static byte[] sign(byte[] data, byte[] privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { // 转换私钥材料 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey); // 实例化密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); // 生成私钥 或者 获取已经生成保存好的私钥 PrivateKey privKey = keyFactory.generatePrivate(keySpec); // 实例化 Signature Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); // 初始化 Signature signature.initSign(privKey); // 更新 signature.update(data); // Returns the signature bytes - 返回签名字节 return signature.sign(); } /** * @desc 校验(公钥) - 验证传入的签名 * @param data 待校验的数据 * @param publicKey 公钥 * @param sign 数字签名 * @return boolean - 成功:返回 true,失败:返回 false * @throws Exception */ public static boolean verify(byte[] data, byte[] publicKey, byte[] sign) throws Exception { // 转换公钥材料 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey); // 实例化密钥工厂 KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); // 生成密钥 PublicKey pubKey = keyFactory.generatePublic(keySpec); // 实例化 Signature Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); // 初始化 Signature signature.initVerify(pubKey); // 更新 signature.update(data); // 验证 - 验证传入的签名 return signature.verify(sign); } /** * @desc 获取私钥 - 从容器Map中 * @param keyMap 密钥Map * @return byte[] 私钥 * @throws Exception */ public static byte[] getPrivateKey(Map<String,Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return key.getEncoded(); } /** * @desc 获取公钥 - 从容器Map中 * @param keyMap * @return * @throws Exception */ public static byte[] getPublicKey(Map<String,Object> keyMap) throws Exception { Key key = (Key) keyMap.get(PUBLIC_KEY); return key.getEncoded(); } /** * @desc 初始化密钥对 * @return Map - 密钥Map * @throws NoSuchAlgorithmException */ public static Map<String,Object> initKey() throws NoSuchAlgorithmException { // 实例化密钥对生成器 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); // 初始化密钥对生成器 keyPairGen.initialize(keySize); // 生成密钥对 KeyPair keyPair = keyPairGen.generateKeyPair(); // 公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 封装密钥 Map<String,Object> keyMap = new HashMap<String,Object>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; } /**********************************【加密与解密】*********************************/ // 加密 /** * @desc 公钥加密 * @param data - 待加密数据 * @param pubKey - 公钥 * @return byte[] - 加密后数据 * @throws Exception */ public static byte[] encryptByPublicKey(byte[] data, byte[] pubKey) throws Exception { // 取得公钥 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); PublicKey publicKey = keyFactory.generatePublic(x509KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] result = cipher.doFinal(data); System.out.println("加密结果:" + Base64.encode(result)); return cipher.doFinal(data); } /** * @desc 私钥加密 * @param data - 待加密数据 * @param privKey - 私钥 * @return byte[] - 加密后数据 * @throws Exception */ public static byte[] encryptByPrivateKey(byte[] data, byte[] privKey) throws Exception { // 取得私钥 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privKey); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); // 生成私钥 PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); } // 解密 /** * @desc 私钥解密 * @param data 待解密数据 * @param privKey 私钥 * @return byte[] 解密数据 * @throws Exception */ public static byte[] decryptByPrivateKey(byte[] data, byte[] privKey) throws Exception { // 取得私钥 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privKey); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); // 生成私钥 PrivateKey privateKey = keyFactory.generatePrivate(keySpec); // 解密数据 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * @desc 公钥解密 * @param data * @param pubKey - 公钥 * @return * @throws Exception */ public static byte[] decryptByPublicKey(byte[] data, byte[] pubKey) throws Exception { // 取得公钥 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKey); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); // 生成公钥 PublicKey publicKey = keyFactory.generatePublic(x509KeySpec); // 对数据解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); return cipher.doFinal(data); } }
【测试 - 签名与加/解密】
package com.test.rsa; import com.face.utils.rsa.RSACoder; import com.sun.org.apache.xml.internal.security.utils.Base64; import org.junit.Before; import org.junit.Test; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.util.Map; public class TestRSACoder { // 公钥 \ 私钥 private byte[] publicKey; private byte[] privateKey; @Before public void initKey() throws Exception { Map<String,Object> keyMap = RSACoder.initKey(); publicKey = RSACoder.getPublicKey(keyMap); privateKey = RSACoder.getPrivateKey(keyMap); System.out.println("公钥:" + Base64.encode(publicKey)); System.out.println("私钥:" + Base64.encode(privateKey)); } /** * @desc 测试签名/校验 * @throws Exception */ @Test public void testSign() throws Exception { String myData = "我的账号:accout: no-654321"; // 生成签名 byte[] sign = RSACoder.sign(myData.getBytes(), privateKey); System.out.println("生成的签名:" + Base64.encode(sign)); // 验证签名 boolean verifyResult = RSACoder.verify(myData.getBytes(), publicKey,sign); System.out.println("签名验证结果:" + verifyResult); } @Test public void testEncrypt() throws Exception { System.out.println("------------ 私钥加密 <--> 公钥解密 ------------"); String input = "RSA原始数据:密码123abc"; byte[] byteData = input.getBytes(); System.out.println("原文:" + input); // 加密 byte[] encodeData = RSACoder.encryptByPrivateKey(byteData,privateKey); System.out.println("加密后:" + Base64.encode(encodeData)); // 解密 byte[] decodeData = RSACoder.decryptByPublicKey(encodeData, publicKey); System.out.println("解密结果:" + new String(decodeData)); } }