Elim的博客

用来记录一些原创性的总结


Elim

RSA签名与验签

RSA算法除了可以进行加解密以外,还可以用来签名与验签。RSA用来进行签名与验签时是使用私钥进行签名,公钥进行验签的。这点与加解密的时候刚好相反。加解密时使用公钥加密,私钥解密。签名和验签是通过Signature对象进行的。

签名

以下是一个使用Signature进行签名的示例。初始化Signature时指定将使用的签名算法是MD5withRSA,除了该算法外,Signature还支持很多其它的算法,如SHA256withRSA,更多的算法可以参考官方文档

	/**
	 * 测试签名
	 * @throws Exception
	 */
	@Test
	public void testSign() throws Exception {
		byte[] sign = this.sign("Hello World");
		String result = Base64.getEncoder().encodeToString(sign);
		System.out.println(result);
	}
	
	/**
	 * 私钥签名
	 * @param data
	 * @return
	 * @throws Exception
	 */
	private byte[] sign(String data) throws Exception {
		//读取储存的私钥字节数组
		byte[] privateKeyCode = Files.readAllBytes(Paths.get(PRIVATE_KEY_PATH));
		//包装私钥字节数组为一个KeySpec
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyCode);
		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
		//通过KeyFactory生成私钥
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		Signature signature = Signature.getInstance("MD5withRSA");//签名的算法
		//通过私钥初始化Signature,签名时用
		signature.initSign(privateKey);
		//指定需要进行签名的内容
		signature.update(data.getBytes());
		//签名
		byte[] result = signature.sign();
		return result;
	}

验签

以下是一个利用Signature进行验签的示例。验签时使用的是公钥。在初始化Signature时使用的是initVerify,而签名时使用的是initSign,这跟Cipher进行加解密有点类似。

	/**
	 * 测试公钥验签
	 * @throws Exception
	 */
	@Test
	public void testVerifySign() throws Exception {
		String data = "Hello World";
		byte[] sign = this.sign(data);
		Signature signature = Signature.getInstance("MD5withRSA");
		byte[] publicKeyCode = Files.readAllBytes(Paths.get(PUBLIC_KEY_PATH));
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyCode);
		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		//以验签的方式初始化Signature
		signature.initVerify(publicKey);
		//指定需要验证的签名
		signature.update(data.getBytes());
		//进行验签,返回验签结果
		boolean result = signature.verify(sign);
		Assert.assertTrue(result);
	}

完整代码 以下是上述示例的完整代码。

public class RSATest {

	private static final String ALGORITHM = "RSA";
	private static final String PRIVATE_KEY_PATH = "D:\\rsa_private.isa";
	private static final String PUBLIC_KEY_PATH = "D:\\rsa_public.isa";
	
	/**
	 * 测试签名
	 * @throws Exception
	 */
	@Test
	public void testSign() throws Exception {
		byte[] sign = this.sign("Hello World");
		String result = Base64.getEncoder().encodeToString(sign);
		System.out.println(result);
	}
	
	/**
	 * 私钥签名
	 * @param data
	 * @return
	 * @throws Exception
	 */
	private byte[] sign(String data) throws Exception {
		//读取储存的私钥字节数组
		byte[] privateKeyCode = Files.readAllBytes(Paths.get(PRIVATE_KEY_PATH));
		//包装私钥字节数组为一个KeySpec
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyCode);
		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
		//通过KeyFactory生成私钥
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		Signature signature = Signature.getInstance("MD5withRSA");//签名的算法
		//通过私钥初始化Signature,签名时用
		signature.initSign(privateKey);
		//指定需要进行签名的内容
		signature.update(data.getBytes());
		//签名
		byte[] result = signature.sign();
		return result;
	}
	
	/**
	 * 测试公钥验签
	 * @throws Exception
	 */
	@Test
	public void testVerifySign() throws Exception {
		String data = "Hello World";
		byte[] sign = this.sign(data);
		Signature signature = Signature.getInstance("MD5withRSA");
		byte[] publicKeyCode = Files.readAllBytes(Paths.get(PUBLIC_KEY_PATH));
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyCode);
		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
		PublicKey publicKey = keyFactory.generatePublic(keySpec);
		//以验签的方式初始化Signature
		signature.initVerify(publicKey);
		//指定需要验证的签名
		signature.update(data.getBytes());
		//进行验签,返回验签结果
		boolean result = signature.verify(sign);
		Assert.assertTrue(result);
	}
	
}

(注:本文由Elim写于2017年5月22日)