RSA算法除了可以进行加解密以外,还可以用来签名与验签。RSA用来进行签名与验签时是使用私钥进行签名,公钥进行验签的。这点与加解密的时候刚好相反。加解密时使用公钥加密,私钥解密。签名和验签是通过Signature
对象进行的。
以下是一个使用Signature
进行签名的示例。初始化Signature
时指定将使用的签名算法是MD5withRSA
,除了该算法外,Signature
还支持很多其它的算法,如SHA256withRSA
,更多的算法可以参考官方文档。
class="pl-c">/** * 测试签名 * @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日)