package org.java.se.security.rsa; import java.io.IOException; import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import org.java.se.security.base64.Base64; import org.junit.Before; import org.junit.Test; /** * RSA加密解密和签名的实现 * @author xianglj */ public class RSACodec { /** * RSA的签名算法 */ private static final String ALGORITHM_RSA = "RSA"; /** * 签名算法 */ private static final String ALGORITHM_SIGNATURE = "MD5withRSA"; private static final String RSA_PRIVATE_KEY = "RSAPrivateKey"; private static final String RSA_PUBLIC_KEY = "RSAPublicKey"; /** * 生成私钥和私钥对 * @return * @throws NoSuchAlgorithmException */ public static Map<String, Key> generateKeyPair() throws NoSuchAlgorithmException { KeyPairGenerator generator = KeyPairGenerator.getInstance(ALGORITHM_RSA); KeyPair keyPair = generator.generateKeyPair(); PublicKey pk = keyPair.getPublic(); PrivateKey prK = keyPair.getPrivate(); Map<String, Key> keyMap = new HashMap<String, Key>(); keyMap.put(RSA_PRIVATE_KEY, prK); keyMap.put(RSA_PUBLIC_KEY, pk); return keyMap; } /** * 签名。运用私钥进行签名 * @param data 需要加密的数据 * @param secretKey 私钥字符串-base64加密字符串 * @return * @throws IOException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws InvalidKeyException * @throws SignatureException */ public static String sign(byte[] data, String secretKey) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { byte[] bytes = Base64.decript(secretKey); //获取私钥 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA); PrivateKey pk = keyFactory.generatePrivate(keySpec); //进行签名 Signature signnature = Signature.getInstance(ALGORITHM_SIGNATURE); signnature.initSign(pk); signnature.update(data); return Base64.encript(signnature.sign()); } /** * 验证签名 * @return * @throws IOException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws InvalidKeyException * @throws SignatureException */ public static boolean verify(byte[] data, String publicKey, String sign) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { //生成公钥 byte[] bytes = Base64.decript(publicKey); //构造X509EncodedKeySpec对象 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA); PublicKey pk = keyFactory.generatePublic(keySpec); //验证签名 Signature signature = Signature.getInstance(ALGORITHM_SIGNATURE); signature.initVerify(pk); signature.update(data); return signature.verify(Base64.decript(sign)); } /** * 采用私钥对数据进行加密 * * @param data * @param privateKey * @throws IOException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws BadPaddingException * @throws IllegalBlockSizeException */ public static String encriptByPrivateKey(byte[] data, String privateKey) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { //获取privateKey byte[] bytes = Base64.decript(privateKey); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA); PrivateKey pk = keyFactory.generatePrivate(keySpec); //对数据进行加密 Cipher cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, pk); cipher.update(data); return Base64.encript(cipher.doFinal()); } /** * 通过公钥加密 * * @param data * @param publicKey * @return * @throws IOException * @throws InvalidKeySpecException * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws BadPaddingException * @throws IllegalBlockSizeException */ public static String encriptByPublicKey(byte[] data, String publicKey) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { byte[] bytes = Base64.decript(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes); PublicKey pk = KeyFactory.getInstance(ALGORITHM_RSA).generatePublic(keySpec); Cipher cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.ENCRYPT_MODE, pk); cipher.update(data); return Base64.encript(cipher.doFinal()); } /** * 使用私钥进行解密。 * @param data 采用PublicKey进行加密的字节数组 * @param privateKey 私钥的Base64字符串。 * @return 采用私钥解密后的byte数组 * @throws IOException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws BadPaddingException * @throws IllegalBlockSizeException */ public static byte[] decriptByPrivateKey(byte[] data, String privateKey) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { //获取私钥 byte[] pkBytes = Base64.decript(privateKey); //构造PKCS8EncodedKeySpec对象 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkBytes); PrivateKey pk = KeyFactory.getInstance(ALGORITHM_RSA).generatePrivate(keySpec); //进行解密 Cipher cipher = Cipher.getInstance(ALGORITHM_RSA); //构建Cipher对象 //设置cipher的模式 cipher.init(Cipher.DECRYPT_MODE, pk); //解密数据 cipher.update(data); return cipher.doFinal(); } /** * 根据公钥进行解密 * * @param data 经过私钥加密的字节数组 * @param publicKey 公钥字符串 * @return 解密后的字节数组 * @throws IOException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws BadPaddingException * @throws IllegalBlockSizeException */ public static byte[] decriptByPublicKey(byte[] data, String publicKey) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { //获取公钥 byte[] pkBytes = Base64.decript(publicKey); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(pkBytes); PublicKey pk = KeyFactory.getInstance(ALGORITHM_RSA).generatePublic(keySpec); Cipher cipher = Cipher.getInstance(ALGORITHM_RSA); cipher.init(Cipher.DECRYPT_MODE, pk); cipher.update(data); return cipher.doFinal(); } /** * 获取公钥字符串 */ public static String getPublicKey() { Key publicKey = keyMap.get(RSA_PUBLIC_KEY); return Base64.encript(publicKey.getEncoded()); } /** * 获取私钥 * @return */ public static String getPrivateKey() { Key privateKey = keyMap.get(RSA_PRIVATE_KEY); return Base64.encript(privateKey.getEncoded()); } private static Map<String, Key> keyMap ; @Before public void setUp() throws NoSuchAlgorithmException { keyMap = generateKeyPair(); } @Test public void testSign() throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, SignatureException, IOException { String privateKey = getPrivateKey(); String publicKey = getPublicKey(); System.out.println("私钥:" + privateKey); System.out.println("公钥:" + publicKey); //需要签名的数据 String data = "这个数据需要签名"; String signData = sign(data.getBytes(), privateKey); System.out.println("签名的数据为:" + signData); //验证签名 boolean isSuc = verify(data.getBytes(), publicKey, signData); System.out.println("签名是否成功:" + isSuc); } /** * 测试使用公钥加密,私钥解密 * @throws IOException * @throws BadPaddingException * @throws IllegalBlockSizeException * @throws NoSuchPaddingException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws InvalidKeyException */ @Test public void testCript() throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, IOException { String privateKey = getPrivateKey(); String publicKey = getPublicKey(); //设置需要加密的字符串 String str = "我将要被公钥加密,私钥解密哦。。。。"; System.out.println("明文为:\r\n" + str); //利用公钥加密 String encriptStr = encriptByPublicKey(str.getBytes(), publicKey); System.out.println("采用公钥加密后的密文为:\r\n" + encriptStr); //采用私钥解密 byte[] pkBytes = decriptByPrivateKey(Base64.decript(encriptStr), privateKey); String decriptStr = new String(pkBytes); System.out.println("采用公钥解密后的明文为:\r\n" + decriptStr); //比较 System.out.println("明文和密文是否一致:\r\n" + (str.equals(decriptStr))); } /** * 测试采用私钥加密,公钥解密 * * @throws InvalidKeyException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws NoSuchPaddingException * @throws IllegalBlockSizeException * @throws BadPaddingException * @throws IOException */ @Test public void encriptTest() throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, IOException { String privateKey = getPrivateKey(); String publicKey = getPublicKey(); //设置需要加密的字符串 String str = "我将要被私钥加密,用公钥解密...."; System.out.println("明文:" + str); //利用私钥加密 String ecriptStr = encriptByPrivateKey(str.getBytes(), privateKey); System.out.println("利用公钥加密后的密文为:" + ecriptStr); //利用公钥解密 byte[] pkBytes = decriptByPublicKey(Base64.decript(ecriptStr), publicKey); String decriptStr = new String(pkBytes); System.out.println("解密后的明文为:" + decriptStr); //比较 System.out.println("是否一致:" + (str.equals(decriptStr))); } }
RSA为非对称加密算法,主要实现步骤:
1. 生成密钥对。私钥和公钥。公钥可以对外公布,或者发布于客户端使用。
2. RSA的加密和解密,都需要密钥的参与。如果采用PublicKey进行加密,则需要对应的 PrivateKey 进行解密。如果采用PrivateKey加密,则需要PublicKey进行解密。因此为了数据的安全性,需要妥善保管密钥