Java讀取OpenSSL生成的PEM公鑰文件操作
JDK8的JCE是不支持讀取PEM文件的。需要使用bouncycastle。
項目需求,使用SHA1WithRSA算法,對接口數(shù)據(jù)做簽名。
代碼如下:
@Service
class SignService {
private static Logger LOG = LoggerFactory.getLogger(SignService.class);
@Autowired
private Config config;
private Signature signature;
@PostConstruct
private void init() {
try {
PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
getDecoder().decode(config.getPrivateKey().getBytes(ISO_8859_1)));
KeyFactory factory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = factory.generatePrivate(priKeySpec);
signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(privateKey);
} catch (NoSuchAlgorithmException |
/*InvalidAlgorithmParameterException |*/
InvalidKeySpecException |
InvalidKeyException ex) {
LOG.warn("RSA init error: {}.", ex);
}
}
String signAndEncode(String source) {
if (Objects.isNull(source)) {
return null;
} else {
return sign(source)
.map(this::encode)
.orElse("");
}
}
private String encode(byte[] source) {
return getEncoder()
.encodeToString(source);
}
private synchronized Optional<byte[]> sign(String source) {
try {
signature.update(source.getBytes(ISO_8859_1));
return Optional.of(signature.sign());
} catch (SignatureException e) {
LOG.warn("SHA1WithRSA {} error: {}.", source, e);
return Optional.empty();
}
}
}
單元測試,驗證簽名是否正確。先初始化Signature:
private Signature signature;
@Before
public void init() {
try {
byte[] key = Files.readAllBytes(Paths.get("/home/ls", "ras_public_key.pem"));
Security.addProvider(new BouncyCastleProvider());
final PemObject pemObject;
try (PemReader pemReader = new PemReader(new InputStreamReader(
new ByteArrayInputStream(key)))) {
pemObject = pemReader.readPemObject();
}
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pemObject.getContent());
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(pubKeySpec);
signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(publicKey);
} catch (Exception e) {
e.printStackTrace();
}
}
驗證方法
private boolean verify(String source, String sign) {
byte[] data = getDecoder().decode(sign);
try {
signature.update(source.getBytes());
return signature.verify(data);
} catch (SignatureException e) {
e.printStackTrace();
return false;
}
}
測試
String source = service.signature(request); String sign = signService.signAndEncode(source); System.out.println(sign); assertTrue(verify(source, sign));
證明,內(nèi)容沒有被篡改。
其中,ras_public_key.pem文件由openSSL生成。
ls@LS-8500:~$ openssl genrsa -out rsa_private_key.pem 1024 Generating RSA private key, 1024 bit long modulus (2 primes) ...+++++ ...............+++++ e is 65537 (0x010001) ls@LS-8500:~$ openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt -----BEGIN PRIVATE KEY----- MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAOk4nqif4LtwfePZ IeGgUc5XYbWk8FpT6UEgO/43i0uprf2RXs3j9eDjOyRwkW2iMCF6S3bNxYuiyJv4 eNc+8w87PJ9bOMRq9WH+ISWIfnPu2x6A1oNOeNkAL7v3ztmpcAn2bNMJ5VscSKp8 S1U02LbHpOErPjvnEul9a/e8xb7TAgMBAAECgYEAvpMeyuoCKQiORo6aqhVoY7Vx yY2jPhyNYUNm4qAeulBINgkBMDtUI1VrcaZun+jFbcXSPp19DFKTnSgYDsOItt04 VLRSZm5yU1EfL21ZvbxIQjjSMv4BxndjdfdoGh5Gve0p1vqtnXtMivkNNI/HdCrx R2CpcGNo4Uqg+zgvwzECQQD1yULuH1sMTEGqLHZaBXVVt1ny+oF+3CnDz2ZdQTWj SLFfBSKplCL8TuEakauUiYf6BVtOjrpzKHRs7hDuZLW5AkEA8umwPbO09ijQdg5e /nkEnJnG5C4krXZuIcsYnf1wrBCLAoOImgDSvVzRrXHMGNvvP0D3gTIxwZSNPt57 1OFe6wJBAJmcOm9WO3IZKqTvetxSMv3qRJY+B7bAZH3TXleEDMDLCsenDv3K7n6f 0cHoLsL7nXcd5+3V+CNGslTuCLjlSkkCQQCM1fqNu5xmwAElAW4IIkgPN4U+FJbF T43I4ATUzPU/fZPrEDHqACIvEhqrcfgATbuns9YMPPrmHmfKFJo9MbGjAkEAzmbW IsDQP4S8TJVd6PvyNZgNrTZvtlMT8/v4MytaEErrljhAR/YLKLcWFxLmQNAL9g4M SsHT8KunE5YrBmkXkg== -----END PRIVATE KEY----- ls@LS-8500:~$ openssl rsa -in rsa_private_key.pem -pubout -out ras_public_key.pem writing RSA key
補充知識:Java導入OpenSSL生成的公私鑰文件
1. 生成2048-bit RSA私鑰
$ openssl genrsa -out private_key.pem 2048
2. 導出RSA公鑰
$ openssl rsa -in private_key.pem -pubout -out public_key.pem
3. 將公私鑰文件private_key.pem和public_key.pem的頭尾注釋去掉
即:
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
4. 讀取公私鑰文件內(nèi)容
// filePath即為private_key.pem和public_key.pem
public static String getKeyFromFile(String filePath) throws Exception {
File file = new File(filePath);
InputStream ins = new FileInputStream(file);
BufferedReader br = new BufferedReader(new InputStreamReader(ins));
String readLine = null;
StringBuffer sb = new StringBuffer();
while ((readLine = br.readLine()) != null) {
sb.append(readLine);
}
br.close();
ins.close();
return new String(sb);
}
5. 讀取私鑰
public static PrivateKey getPrivateKey(String privateKey) throws Exception {
// 解碼由base64編碼的私鑰
byte[] keyBytes = decryptBASE64(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
// 取得私鑰
PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
return priKey;
}
6. 讀取公鑰
public static PublicKey getPublicKey(String publicKeyStr) throws Exception {
// 解碼由base64編碼的公鑰
byte[] keyBytes = decryptBASE64(publicKeyStr);
// 取得公鑰
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
return publicKey;
}
以上這篇Java讀取OpenSSL生成的PEM公鑰文件操作就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java貪心算法之Prime算法原理與實現(xiàn)方法詳解
這篇文章主要介紹了Java貪心算法之Prime算法原理與實現(xiàn)方法,簡單描述了Prime算法的概念、原理、實現(xiàn)與使用技巧,需要的朋友可以參考下2017-09-09
@Async導致controller?404及失效原因解決分析
這篇文章主要為大家介紹了@Async導致controller?404失效問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07
Mybatis使用注解實現(xiàn)復(fù)雜動態(tài)SQL的方法詳解
當使用 MyBatis 注解方式執(zhí)行復(fù)雜 SQL 時,你可以使用 @Select、@Update、@Insert、@Delete 注解直接在接口方法上編寫 SQL,本文給大家介紹了Mybatis如何使用注解實現(xiàn)復(fù)雜動態(tài)SQL,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下2023-12-12

