由于RSA算法是不对称加密算法,所以每次加密得到的数据都不相同,同理加签得到的数据每次也不一样。
简单的说下不对称算法,就是两把不同,但是完全匹配的秘钥,去进行加解密,公钥对外提供进行数据加密,私钥自己保存,对加密的数据进行解密。所以私钥不要泄露。
RSA算法原理:
1、任意互质的两个质数p,q。
2、得到连个质数的乘积n。
3、得到两个质数的欧元函数f(n)=(p-1) * (q-1)。
4、任取一个小于f(n)并与其互质的质数e。
5、存在一个数d,使得e^d % f(n) = 1。
6、则(n,e)为公钥,(n,d)为私钥。
加密:待加密数据t:
t^te% n = m(m为加密后的数据);
解密:m^d % n = t(t为原数据)
Java实现RSA算法加密解密,加签以及验签代码如下:
1、Base64工具类:
//Base64加密 public static String encryptBase64(byte[] key){ return new String(Base64.encodeBase64(key)); } //Base64解密 public static byte[] decryptBase64(String key) throws IOException { return new BASE64Decoder().decodeBuffer(key); }
2、获取RSA秘钥对:
public static Map3、获取RSA公钥以及私钥分别保存到文件中:keyMap()throws Exception{ KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); keyPairGenerator.initialize(1024); KeyPair keyPair = keyPairGenerator.generateKeyPair(); PublicKey publicKey = keyPair.getPublic(); PrivateKey privateKey = keyPair.getPrivate(); Map keyMap = new HashMap<>(2); keyMap.put(PUBLIC_KEY, publicKey); keyMap.put(PRIVATE_KEY, privateKey); return keyMap; }
public static void keyToFile(Map keymap)throws Exception{ PublicKey publicKey = (PublicKey) keymap.get(PUBLIC_KEY); PrivateKey privateKey = (PrivateKey)keymap.get(PRIVATE_KEY); String encryptBase64PublicKey = encryptBase64(publicKey.getEncoded()); String encryptBase64PrivateKey = encryptBase64(privateKey.getEncoded()); FileWriter fw = new FileWriter("src/main/resources/pubKey.txt");//按需要保存路径,下同
FileWriter fw1 = new FileWriter("src/main/resources/priKey.txt"); fw.write(encryptBase64PublicKey); fw.flush(); fw.close(); fw1.write(encryptBase64PrivateKey); fw1.flush(); fw1.close(); }4、从文件中获取公钥:
public static RSAPublicKey getPublicKeyForFile() throws Exception { File file = new File("src/main/resources/pubKey.txt"); FileInputStream fis = new FileInputStream(file); BufferedReader br = new BufferedReader(new InputStreamReader(fis)); String readLine = null; StringBuffer sb = new StringBuffer(); while ((readLine = br.readLine()) != null) { sb.append(readLine); } String publicKeyStr = sb.toString(); System.out.println("从文件获取到的公钥:" + publicKeyStr); //Base64解密 byte[] decryptBase64 = GetKey.decryptBase64(publicKeyStr); //选取密钥编码规则 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decryptBase64); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPublicKey rsaPublicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec); return rsaPublicKey; }
5、从文件中获取私钥:
//从文件中获取私钥 public static RSAPrivateKey getPrivateKeyForFile() throws Exception { FileInputStream fis = new FileInputStream("src/main/resources/priKey.keyStore"); BufferedReader br = new BufferedReader(new InputStreamReader(fis)); String readLine = null; StringBuffer sb = new StringBuffer(); while ((readLine = br.readLine()) != null) { sb.append(readLine); } String privateKey = sb.toString(); System.out.println("从文件获取到的私钥:" + privateKey); //Base64解密 byte[] bytes = GetKey.decryptBase64(privateKey); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8EncodedKeySpec); return rsaPrivateKey; }
6.公钥加密/私钥解密:
public static byte[] encryptOrDecrypt(Key key, byte[] data, int mode) throws Exception { //加密算法:RSA/ECB/PKCS1Padding
ByteArrayOutputStream out = new ByteArrayOutputStream();
//提供者 Provider provider = new BouncyCastleProvider(); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider); cipher.init(mode, key); int blockSize = cipher.getBlockSize(); int length = data.length; int num = length / blockSize + 1; int cache = blockSize; byte[] bytes = null; for (int i = 0; i < num; i++) { if (i == num - 1) { cache = length % blockSize; if (cache == 0) { return out.toByteArray(); } } bytes = cipher.doFinal(data, i * blockSize, cache); out.write(bytes); } return out.toByteArray(); }7.RSA私钥加签:
public static String addSign(PrivateKey privateKey, String context)throws Exception{ //加签算法:SHA1WithRSA
Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initSign(privateKey); signature.update(context.getBytes("utf-8")); byte[] sign = signature.sign(); return encryptBase64(sign); }8.RSA公钥验签:
public static boolean verifySign(PublicKey publicKey, String context, String signData)throws Exception{ Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initVerify(publicKey); byte[] bytes = decryptBase64(signData); signature.update(context.getBytes("utf-8")); boolean verify = signature.verify(bytes); return verify; }9.主测试类:
public class Sign {
private final static String PUBLIC_KEY = "PUBLIC_KEY"; private final static String PRIVATE_KEY = "PRIVATE_KEY";public static void main(String[] args) { try {
Mapmap = keyMap(); keyToFile(map);
RSAPublicKey rsaPublicKey = getPublicKeyForFile();
System.out.println("rsaPublicKey公钥是:" + rsaPublicKey);
RSAPrivateKey rsaPrivateKey = getPrivateKeyForFile();
System.out.println("rsaPublicKey私钥是:" + rsaPrivateKey);
String data = "这是一个加密字符串"
//加密
byte[] encrypt = encryptOrDecrypt(rsaPublicKey, data.getBytes("utf-8"), Cipher.ENCRYPT_MODE);
String s = encryptBase64(encrypt); System.out.println("加密后的数据:" + s);//解密 byte[] decrypt = encryptOrDecrypt (rsaPrivateKey, decryptBase64( s ) , Cipher. DECRYPT_MODE );
//加签
String signData = addSign(rsaPrivateKey, data);
System.out.println("加签后的数据:" + signData);
//验签
boolean b = verifySign(rsaPublicKey, data, signData); System.out.println("验签得到的布尔值为:" + b);
} catch (Exception e) { e.printStackTrace(); } }最后要说明的是要导入这个包:
<dependency> <groupId>org.bouncycastlegroupId> <artifactId>bcprov-jdk16artifactId> <version>1.46version> dependency>