我使用Ubuntu sub-Linux系统来生成密钥
firerose@DESKTOP-84LARLB:~$ openssl genrsa -out jwtRSA256-private.pem 2048
firerose@DESKTOP-84LARLB:~$ openssl rsa -in jwtRSA256-private.pem -pubout -outform PEM -out jwtRSA256-public.pem
writing RSA key
firerose@DESKTOP-84LARLB:~$ echo -n '{"alg":"RS256","typ":"JWT"}' | base64 | sed s/\+/-/ | sed -E s/=+$//
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9
firerose@DESKTOP-84LARLB:~$ echo -n '{"sub":"RS256inOTA","name":"John Doe"}' | base64 | sed s/\+/-/ | sed -E s/=+$//
eyJzdWIiOiJSUzI1NmluT1RBIiwibmFtZSI6IkpvaG4gRG9lIn0
firerose@DESKTOP-84LARLB:~$ echo -n "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJSUzI1NmluT1RBIiwibmFtZSI6IkpvaG4gRG9lIn0" | openssl dgst -sha256 -binary -sign jwtRSA256-private.pem | openssl enc -base64 | tr -d '\n=' | tr -- '+/' '-_'
Gim84zxX_4SjTojJq9BU_ivSBkpIAkhJeU8uhv6wUGYxhXK-8-VwLs-WmrDjNM-fIxVtQ_I1Nnz_cgHUSj0G9PtIxJ3zv818D-npzIgcAhWwmv4WWdATtU7UXHGfpKw1pkLOKMlGr8bJ_ooK9yWU49BuaKc1HHH4GizO9hn3IJwMNPeYw7P371aMgshBF3T_gyhGNYippwCE177e_VfdATMibN6S4So-8BKBaLf8uGAtgwcBPc5Qe-CkhAQsnVDy_Rm_l14kEch_ogVQKPrVnDnR4GPYOQSlCi8Q9fZ7rBCTvomw_fANBC7qfLZw3HgkTBE-NEbh0SmSBmzb7BiiYw
firerose@DESKTOP-84LARLB:~$
我的 JWT 令牌
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJSUzI1NmluT1RBIiwibmFtZSI6IkpvaG4gRG9lIn0.Gim84zxX_4SjTojJq9BU_ivSBkpIAkhJeU8uhv6wUGYxhXK-8-VwLs-WmrDjNM-fIxVtQ_I1Nnz_cgHUSj0G9PtIxJ3zv818D-npzIgcAhWwmv4WWdATtU7UXHGfpKw1pkLOKMlGr8bJ_ooK9yWU49BuaKc1HHH4GizO9hn3IJwMNPeYw7P371aMgshBF3T_gyhGNYippwCE177e_VfdATMibN6S4So-8BKBaLf8uGAtgwcBPc5Qe-CkhAQsnVDy_Rm_l14kEch_ogVQKPrVnDnR4GPYOQSlCi8Q9fZ7rBCTvomw_fANBC7qfLZw3HgkTBE-NEbh0SmSBmzb7BiiYw
我的公钥和私钥对 https://drive.google.com/drive/folders/1TMCKH77IBIMv0bZGE4gydbwkqNq-H3uC?usp=sharing
我在 Windows 11 中将文件
jwtRSA256-private.pem
和 jwtRSA256-public.pem
复制到 C:\
。
我的Java代码,文件
CryptoUtils.java
有内容
package com.example.cryptology;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import javax.crypto.Cipher;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* RSA.
*/
public class CryptoUtils {
private static String getKey(String filename) throws IOException {
// Read key from file.
String strKeyPEM = "";
BufferedReader br = new BufferedReader(new FileReader(filename));
String line;
while ((line = br.readLine()) != null) {
strKeyPEM += line + "\n";
}
br.close();
return strKeyPEM;
}
public static RSAPrivateKey getPrivateKey(String filename) throws IOException, GeneralSecurityException {
String privateKeyPEM = getKey(filename);
return getPrivateKeyFromString(privateKeyPEM);
}
public static RSAPrivateKey getPrivateKeyFromString(String key) throws IOException, GeneralSecurityException {
String privateKeyPEM = key;
privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----\n", "");
privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.decodeBase64(privateKeyPEM);
KeyFactory kf = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(keySpec);
return privKey;
}
public static RSAPublicKey getPublicKey(String filename) throws IOException, GeneralSecurityException {
String publicKeyPEM = getKey(filename);
return getPublicKeyFromString(publicKeyPEM);
}
public static RSAPublicKey getPublicKeyFromString(String key) throws IOException, GeneralSecurityException {
String publicKeyPEM = key;
publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", "");
publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", "");
byte[] encoded = Base64.decodeBase64(publicKeyPEM);
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
return pubKey;
}
public static String sign(PrivateKey privateKey, String message) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
Signature sign = Signature.getInstance("SHA1withRSA");
sign.initSign(privateKey);
sign.update(message.getBytes("UTF-8"));
return new String(Base64.encodeBase64(sign.sign()), "UTF-8");
}
public static boolean verify(PublicKey publicKey, String message, String signature) throws SignatureException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException {
Signature sign = Signature.getInstance("SHA1withRSA");
sign.initVerify(publicKey);
sign.update(message.getBytes("UTF-8"));
return sign.verify(Base64.decodeBase64(signature.getBytes("UTF-8")));
}
public static String encrypt(String rawText, PublicKey publicKey) throws IOException, GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.encodeBase64String(cipher.doFinal(rawText.getBytes("UTF-8")));
}
public static String decrypt(String cipherText, PrivateKey privateKey) throws IOException, GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(Base64.decodeBase64(cipherText)), "UTF-8");
}
/**
* Get public key from file.
*
* @param file
* @return
* @throws Exception
*/
public static RSAPublicKey readPublicKey(File file) throws Exception {
String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
String publicKeyPEM = key.replace("-----BEGIN PUBLIC KEY-----", "").replaceAll(System.lineSeparator(), "").replace("-----END PUBLIC KEY-----", "");
byte[] encoded = Base64.decodeBase64(publicKeyPEM);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
/**
* Get private key from file.
*
* @param file
* @return
* @throws Exception
*/
public static RSAPrivateKey readPrivateKey(File file) throws Exception {
String key = new String(Files.readAllBytes(file.toPath()), Charset.defaultCharset());
String privateKeyPEM = key.replace("-----BEGIN PRIVATE KEY-----", "").replaceAll(System.lineSeparator(), "").replace("-----END PRIVATE KEY-----", "");
byte[] encoded = Base64.decodeBase64(privateKeyPEM);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
public static RSAPublicKey readPublicKeySecondApproach(File file) throws IOException {
try (FileReader keyReader = new FileReader(file)) {
PEMParser pemParser = new PEMParser(keyReader);
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(pemParser.readObject());
return (RSAPublicKey) converter.getPublicKey(publicKeyInfo);
}
}
public static RSAPrivateKey readPrivateKeySecondWay(File file) throws Exception {
KeyFactory factory = KeyFactory.getInstance("RSA");
try (FileReader keyReader = new FileReader(file);
PemReader pemReader = new PemReader(keyReader)) {
PemObject pemObject = pemReader.readPemObject();
byte[] content = pemObject.getContent();
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
return (RSAPrivateKey) factory.generatePrivate(privKeySpec);
}
}
}
文件
SampleController.java
package com.example.controller;
//import org.springframework.security.core.Authentication;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
@RestController
@RequestMapping("/sample")
public class SampleController {
@Autowired
public AuthPartnerRepository authPartnerRepository;
/**
* GET http://localhost:8084/sample/login
* JWT token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0aW1lc3RhbXAiOiIyMDIzLTA3LTI0VDA5OjQyOjE4Ljc4NloiLCJpYXQiOjE2OTAxOTE3Mzh9.g3iTwX1n-y8G9k0yzJj36x2nOuWItuWI1qXTEG95CyHf6krpdpbrgVZ7QFsWqXYkYfR_S44s9_vTt49FZ1Bqxw6K7h-T-fpfG77uZHVDU80Y2cZuIDUYLoyGHUqHNHrLcfGjWyAf0knIpJVzD8eWAIewk7fGvbdBjoTaj9dE0wKpa1itMSbnS3G7S2SKlnRH0x2583FgMSQ76yIFl9B4J510_06MljjNKmUJiu2XlyZGEpj0WzYgyDuJfsnuJgz6y847FNtcfxt7IoakMzHRtHrtAYM_pgJaW7uAFWvEta1mEOZEbTy6RB7hnz5i0gYjEuuK3yF4JmSUGtcGGatCvg"
*
*
* @return
*/
@GetMapping("/login")
public String foo(@RequestHeader("Authorization") String authorization) throws Exception {
//AuthPartner authPartner = authPartnerRepository.getOne(1L);
//String foo = authPartner.getPublicKey();
//System.out.println(foo);
String token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJSUzI1NmluT1RBIiwibmFtZSI6IkpvaG4gRG9lIn0.Gim84zxX_4SjTojJq9BU_ivSBkpIAkhJeU8uhv6wUGYxhXK-8-VwLs-WmrDjNM-fIxVtQ_I1Nnz_cgHUSj0G9PtIxJ3zv818D-npzIgcAhWwmv4WWdATtU7UXHGfpKw1pkLOKMlGr8bJ_ooK9yWU49BuaKc1HHH4GizO9hn3IJwMNPeYw7P371aMgshBF3T_gyhGNYippwCE177e_VfdATMibN6S4So-8BKBaLf8uGAtgwcBPc5Qe-CkhAQsnVDy_Rm_l14kEch_ogVQKPrVnDnR4GPYOQSlCi8Q9fZ7rBCTvomw_fANBC7qfLZw3HgkTBE-NEbh0SmSBmzb7BiiYw";
DecodedJWT decodedJWT;
File publicFile = new File("C:\\jwtRSA256-public.pem");
// RSAPublicKey rsaPublic = CryptoUtils.readPublicKey(publicFile);
RSAPublicKey rsaPublic = CryptoUtils.readPublicKeySecondApproach(publicFile);
File privateFile = new File("C:\\jwtRSA256-private.pem");
// RSAPrivateKey rsaPrivate = CryptoUtils.readPrivateKey(privateFile);
RSAPrivateKey rsaPrivate = CryptoUtils.readPrivateKeySecondWay(privateFile);
try {
Algorithm algorithm = Algorithm.RSA256(rsaPublic, rsaPrivate);
JWTVerifier verifier = JWT.require(algorithm).withIssuer("auth0").build();
decodedJWT = verifier.verify(token);
} catch (JWTVerificationException exception){
// Invalid signature/claims.
}
Signature signature1 = Signature.getInstance("SHA256WithRSA");
//signature1.initVerify(publicKey);
// String message = "z2c6l34OiHCRbdwHOhowjycqKhrM6HOBWcHOZXeNxHg5ACELiFfZDx8wNXKJVKQv";
//byte[] messageBytes = authorization.getBytes("UTF8");
//boolean result = signature1.verify(messageBytes);
//if(result == true){
// return "Xac thuc ok";
//}else {
// return "Xac thuc that bai";
//}
return "Xac thuc ok";
}
}
我的错误
java.security.InvalidKeyException: IOException : algid parse error, not a sequence
at java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:350) ~[na:na]
at java.base/sun.security.pkcs.PKCS8Key.decode(PKCS8Key.java:355) ~[na:na]
at java.base/sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.java:130) ~[na:na]
at java.base/sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.java:80) ~[na:na]
at java.base/sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.java:356) ~[na:na]
at java.base/sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.java:247) ~[na:na]
at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390) ~[na:na]
at ati.com.example.cryptology.CryptoUtils.readPrivateKeySecondWay(CryptoUtils.java:149) ~[classes/:na]
我使用的是Java 11。我尝试了4种方法,都是错误
readPublicKey()
readPrivateKey()
readPublicKeySecondApproach()
readPrivateKeySecondWay()
如何加载私钥/公钥(
jwtRSA256-private.pem
,jwtRSA256-public.pem
)到Java对象(RSAPrivateKey
,RSAPublicKey
)成功?