如何从 base64 编码字符串创建 Java Key 对象,以便使用 JJWT 进行 PS256 解析

Posted

技术标签:

【中文标题】如何从 base64 编码字符串创建 Java Key 对象,以便使用 JJWT 进行 PS256 解析【英文标题】:How to create a Java Key object from a base64 endoded strings for PS256 parsing with JJWT 【发布时间】:2021-12-27 11:32:18 【问题描述】:

我正在使用 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 "";

但是,当我将键转换为 Base64Encoded 字符串时:

    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

【讨论】:

私钥是否也一样? @sparkyspider - 导入私钥是类似的。我将那部分添加到答案中。

以上是关于如何从 base64 编码字符串创建 Java Key 对象,以便使用 JJWT 进行 PS256 解析的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PHP 从 base64 编码的数据/字符串创建图像并将其保存到网站文件夹

如何使用 javascript 获取 base64 编码图像的地址

从 DER 格式的字符串 base64 编码创建 PrivateKey 和 PublicKey

如何在 ios 中将 Base64 编码的 NSString 转换为字节数组(Java)?

如何在 Swift 3 中从 Base64 编码的字符串创建图像? [复制]

如何从 base 64 编码字符串中获取十六进制块?