Java读取OpenSSL生成的PEM公钥文件操作

网友投稿 438 2022-11-18


Java读取OpenSSL生成的PEM公钥文件操作

JDK8的JCE是不支持读取PEM文件的。需要使用bouncycastle。

项目需求,使用SHA1WithRSA算法,对接口数据做签名。

代码如下:

@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 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));

证明,内容没有被篡改。

其中,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. 读取公私钥文件内容

// 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);

KeyFactoryZGnmDjx keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);

return publicKey;

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:解决对接JAVA SM2加密遇到的坑
下一篇:Java 并行数据处理和性能分析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~