JDK8的JCE是不支持读取PEM文件的。需要使用bouncycastle。
项目需求,使用SHA1WithRSA算法,对接口数据做签名。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
@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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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();
}
}
|
验证方法
1
2
3
4
5
6
7
8
9
10
|
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 ;
}
}
|
测试
1
2
3
4
|
String source = service.signature(request);
String sign = signService.signAndEncode(source);
System.out.println(sign);
assertTrue(verify(source, sign));
|
证明,内容没有被篡改。
其中,ras_public_key.pem文件由openSSL生成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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. 读取公私钥文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// 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. 读取私钥
1
2
3
4
5
6
7
8
9
|
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. 读取公钥
1
2
3
4
5
6
7
8
9
|
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公钥文件操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/weixin_43364172/article/details/90401648