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日)