Как создать объект ключа Java из кодированных строк base64 для анализа PS256 с помощью JJWT

#jwt #rsa #jjwt

Вопрос:

Я использую JJWT для попытки создания и последующей проверки ключей JWT. Это не работает, когда я пытаюсь преобразовать ключи в строки и наоборот — для хранения для последующего использования.

Этот пример отлично работает:

 KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.PS256);  Key publicKey = keyPair.getPublic();  Key privateKey = keyPair.getPrivate();   Claims claims = Jwts.claims();  claims.setIssuedAt(new Date());   String jws = Jwts.builder().setSubject("Joe").claim("Hello", "World").signWith(privateKey).compact();   boolean result = Jwts.parserBuilder().setSigningKey(publicKey).build().parseClaimsJws(jws).getBody().getSubject().equals("Joe");   System.out.println("Verified:"   result);  return "";  

Однако, когда я преобразую ключи в кодированные строки BASE64 как таковые:

 String base64Public = Encoders.BASE64.encode(publicKey.getEncoded());  String base64Private = Encoders.BASE64.encode(privateKey.getEncoded());  

Как загрузить открытый ключ (из строки) обратно в алгоритм и проверить JWS с помощью открытого ключа?

 String base64Public = Encoders.BASE64.encode(publicKey.getEncoded()); boolean result2 = Jwts.parserBuilder().setSigningKey(base64Public).build().parseClaimsJws(jws).getBody().getSubject().equals("Joe");  

терпит неудачу с:

Ключевые байты могут быть указаны только для подписей HMAC. Пожалуйста, укажите экземпляр PublicKey или PrivateKey.

Ответ №1:

Экспортированный открытый ключ имеет формат X. 509/SPKI и должен быть импортирован соответствующим образом:

 import java.security.KeyFactory; import java.security.spec.X509EncodedKeySpec; import java.security.PublicKey; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.io.Encoders; import io.jsonwebtoken.io.Decoders;  ...  // Export String base64Public = Encoders.BASE64.encode(publicKey.getEncoded());   // Import KeyFactory keyFactory = KeyFactory.getInstance("RSA"); X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Decoders.BASE64.decode(base64Public)); PublicKey publicKeyReloaded = (PublicKey)keyFactory.generatePublic(x509EncodedKeySpec);  // Verification  boolean result = Jwts.parserBuilder().setSigningKey(publicKeyReloaded).build().parseClaimsJws(jws).getBody().getSubject().equals("Joe"); System.out.println("Verified:"   result); // Verified:true  

Редактировать:

Закрытый ключ имеет формат PKCS#8 и импортируется следующим образом:

 import java.security.KeyFactory; import java.security.spec.PKCS8EncodedKeySpec; import java.security.PrivateKey;  ...  // Export String base64Private = Encoders.BASE64.encode(privateKey.getEncoded());  // Import KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(base64Private)); PrivateKey privateKeyReloaded = (PrivateKey)keyFactory.generatePrivate(pkcs8EncodedKeySpec);  // Sign String jws = Jwts.builder().setSubject("Joe").claim("Hello", "World").signWith(privateKeyReloaded).compact(); System.out.println("JWS:"   jws); // e.g. JWS:eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJKb2UiLCJIZWxsbyI6IldvcmxkIn0.bk9EtxqRU3cfn7nMyn7MsDSKTlFUUwxjkWXVXqbpjVacEd6lEVG2jmkLSQ2oAoiA8fmKTlSXnULUKhv4XvDbvG2_BIx22JpceuYVdFhbvzkxv3EffPYrsYXftqws0vo-Wg05ubXk7qfeyIs9S-oq_Jf-5w_2oe6GLlcBqnNu-wLy8gAMiKNQPtuE7PmCT9ZEE7ALg_aGMBl2ttOEYN6bQcgxkbJLiS9pWm_RQbPsRCF34Q7alrETQPFltVJOPXd34aMPTaWSkYlyccj-0gVv8p5-BRpsGc3M9XaZWnwLm5CYzZ7tpfcd0BhKtkEO5mSFU7jo4P_T8BWCbEn2jYyzPA  

Комментарии:

1. Работает ли это так же для закрытого ключа?

2. @sparkyspider — Импорт закрытого ключа аналогичен. Я добавил эту часть к ответу.