Java从jks文件中获取RSA的公钥和私钥,以及加密和解密

官方文档:

https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html


首先生成证书文件

#生成RSA证书
keytool -genkey -v -alias rsa_key -keyalg RSA -keystore rsa_key.jks -validity 36500
#导出公钥文件,可以在java程序中直接读取这个文件
keytool -export -alias rsa_key -keystore rsa_key.jks -storepass 123456 -rfc -file rsa_key_public.cer
#也可以把公钥导入到jks文件中,在java程序中使用也能顺利读取从公钥
keytool -import -v -alias rsa_public -file ras_key_public.cer -keystore rsa_key_public.jks


测试类如下:

package test;

import java.io.FileInputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;

import javax.crypto.Cipher;

import org.apache.commons.codec.binary.Base64;

public class RSATest {
	
	/**
	 * 公钥加密
	 * @param text
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static byte[] encrypt(String text,Key key) throws Exception {
		Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
		// Cipher.PUBLIC_KEY 或 Cipher.ENCRYPT_MODE 经测试对结果没有影响
		cipher.init(Cipher.PUBLIC_KEY, key);
		byte[] v = cipher.doFinal(text.getBytes());
		return v;
	}
	
	/**
	 * 私钥解密
	 * @param bs
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static String decrypt(byte[] bs,Key key) throws Exception {
		Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
		// Cipher.PRIVATE_KEY 或 Cipher.DECRYPT_MODE 经测试对结果没有影响
		cipher.init(Cipher.PRIVATE_KEY, key);
		byte[] bts = cipher.doFinal(bs);
		return new String(bts);
	}
	
	/**
	 * 获取私钥的对象
	 * @return
	 * @throws Exception
	 */
	public static Key getPrivateKey() throws Exception {
		KeyStore ks = KeyStore.getInstance("JKS");
		ks.load(new FileInputStream("C:\\Users\\Administrator\\Desktop\\test\\rsa_key.jks"), "123456".toCharArray());
		Key key = ks.getKey("rsa_key", "123456".toCharArray());
		return key;
	}
	
	/**
	 * 获取公钥对象的方法一:从JKS文件中获取公钥的对象
	 * @return
	 * @throws Exception
	 */
	public static Key getPublicKey() throws Exception {
		KeyStore ks = KeyStore.getInstance("JKS");
		ks.load(new FileInputStream("C:\\Users\\Administrator\\Desktop\\test\\rsa_key_public.jks"), "123456".toCharArray());
		return ks.getCertificate("rsa_public").getPublicKey();
	}
	
	/**
	 * 获取公钥对象的方法二:从导出的公钥cer文件中获取公钥的对象
	 * @return
	 * @throws Exception
	 */
	public static Key getPublicKey2() throws Exception {
		CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
		Certificate cert = certFactory.generateCertificate(new FileInputStream("C:\\Users\\Administrator\\Desktop\\test\\rsa_key_public.cer"));
		return cert.getPublicKey();
	}
	
	/**
	 * 公钥的内容
	 * @return
	 * @throws Exception
	 */
	public static String getPublicKeyText() throws Exception {
		return new String(Base64.encodeBase64(getPublicKey().getEncoded(), true));
	}

	public static void main(String[] args) throws Exception {
		byte[] enbs = encrypt("中英文sdfs混{}合加密sdf测试1232",getPublicKey());
		System.out.println(Base64.encodeBase64String(enbs));
		
//		String t = "bSbvAmVQtoINVma0JfPy58xAvqKtZ2e0GTwwz5okFvVIPF3kU0L803UarWRs4hzgiCvppasoqF825zAI6n7keDCBhMkKKuDBMfeAgbHCVRM+SnvEeWioDbkNVuily67Z5VzY7HvLFrolFH9g99f1CQxhFi/Z1xzTIRTGYp9GsZrYrNGBsvsvqir3R3YEKzlJ+UM/KK1B1xE30toLz6So/D9Bim9fdsJDoXZc/jFJRhn1LZqBn3glhkFBu6g88n/ry9d9o5xINjB+BDVJA7KuKYNiHImz6ZOGiMLw6eRgICjfAajfRbQMGMvBCxFADy0ESMM7p/BXpigr6Z36HtBU3A==";
//		byte[] enbs = Base64.decodeBase64(t);
		
		String text = decrypt(enbs, getPrivateKey());
		System.out.println(text);
	}

}


经过测试确认了如下问题:

1.Cipher.getInstance("RSA")等价于Cipher.getInstance("RSA/ECB/PKCS1Padding"),不过为了避免出现不兼容尽量使用后一种形式。

2.Cipher.PUBLIC_KEY 和 Cipher.ENCRYPT_MODE的区别是前一个只接受公钥加密私钥解密,后一个支持私钥加密公钥解密。

提交评论