证书生成以及签名验签流程
私钥证书
私钥证书生成
//生成4096位的RSA私钥
openssl genrsa -out pkcs1_private.pem 4096
java读取私钥
public PrivateKey generatePrivateKeyWithPKCS8PEM() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
byte[] bytes = Files.readAllBytes(Paths.get("D:\\test\\RSA_pkcs8.der"));
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
System.out.println(privateKey.getFormat());
return privateKey;
}
- 此时会出现异常
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
问题原因:Java自带的security包不支持直接读取PEM格式文件。
解决方法:需要将PEM格式转为DER格式再进行读取。
// 把pem格式转化成der格式,使用outform指定der格式
openssl rsa -in RSA.pem -outform der -out RSA.der
- 修改读取私钥路径,执行代码,也会出现异常
java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : algid parse error, not a sequence
问题原因:OpenSSL生成的私钥是PKCS#1格式的,而Java自带的security包使用PKCS8EncodedKeySpec来实现私钥,私钥信息是以PKCS#8标准定义的。
解决方法:OpenSSL生成密钥之后在Java环境中使用要先转为PKCS#8格式。
关于PKCS#1与PKCS#8,简单理解两者都是非对称加密私钥信息的标准定义,区别是PKCS#1是针对RSA算法的,而PKCS#8是通用的,两者在格式定义上有些许区别。
提取PCKS8格式的私钥
openssl pkcs8 -topk8 -inform DER -in RSA.der -outform DER -nocrypt -out RSA_pkcs8.der
公钥证书
根据生成的私钥生成公钥证书
// 提取公钥
openssl rsa -in RSA.pem -pubout -out pub.pem
// 把pem格式转化成der格式,使用outform指定der格式
openssl rsa -pubin -in pub.pem -outform der -out pub.der
Java读取公钥
public PublicKey generatePublicKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
byte[] bytes = Files.readAllBytes(Paths.get("D:\\test\\pub.der"));
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
System.out.println(publicKey.getFormat());
return publicKey;
}
java私钥签名,公钥验签
私钥签名
public String signByPrivateKey(String signData) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, InvalidKeyException, SignatureException {
byte[] bytes = Base64.decodeBase64(signData);
PrivateKey privateKey = generatePrivateKeyWithPKCS8PEM();
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(privateKey);
signature.update(bytes);
byte[] sign = signature.sign();
String resultSign = Base64.encodeBase64String(sign);
System.out.println(resultSign);
return resultSign;
}
公钥验签
public void verifyByPublicKey() throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, SignatureException, InvalidKeyException {
String signData="testSign";
PublicKey publicKey = generatePublicKey();
String resultSignData = signByPrivateKey(signData);
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(publicKey);
signature.update(Base64.decodeBase64(signData));
boolean verify = signature.verify(Base64.decodeBase64(resultSignData));
System.out.println(verify);
}
完整代码
import org.apache.commons.codec.binary.Base64;
import org.junit.Test;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class TestSecurity {
public PrivateKey generatePrivateKeyWithPKCS8PEM() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
byte[] bytes = Files.readAllBytes(Paths.get("D:\\test\\RSA_pkcs8.der"));
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
System.out.println(privateKey.getFormat());
return privateKey;
}
public PublicKey generatePublicKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
byte[] bytes = Files.readAllBytes(Paths.get("D:\\test\\pub.der"));
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
System.out.println(publicKey.getFormat());
return publicKey;
}
public String signByPrivateKey(String signData) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, InvalidKeyException, SignatureException {
byte[] bytes = Base64.decodeBase64(signData);
PrivateKey privateKey = generatePrivateKeyWithPKCS8PEM();
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(privateKey);
signature.update(bytes);
byte[] sign = signature.sign();
String resultSign = Base64.encodeBase64String(sign);
System.out.println(resultSign);
return resultSign;
}
@Test
public void verifyByPublicKey() throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, SignatureException, InvalidKeyException {
String signData="testSign";
PublicKey publicKey = generatePublicKey();
String resultSignData = signByPrivateKey(signData);
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(publicKey);
signature.update(Base64.decodeBase64(signData));
boolean verify = signature.verify(Base64.decodeBase64(resultSignData));
System.out.println(verify);
}
}
评论区