如何解决无法使用椭圆曲线EC加密签署JWT
我已经使用椭圆曲线密码生成了私钥:
openssl ecparam -genkey -name secp521r1 -noout | openssl pkcs8 -topk8 -nocrypt
我已经使用以下Java代码对JWT进行了签名:
String privateKeyPEM = "MIHtAgEAMBAGByqGSM49AgEGBSuBBAAjBIHVMIHSAgEBBEEmSOGpmkjzKM+uWhya"
+ "Cl6sbSsmROUol4HaDbORnOI6klbEjbCkPEyxKRnrrtrGFShhu7TPPlGDK39f+K3G"
+ "IZhbYKGBiQOBhgAEAJQiOIKV7YmIVI30Y3y1UZIvgZFRviHFWvSiTXEG4IqzHKpF"
+ "jOIYs0rzn1F2zrFHKpmMtZ0Kh5OzyfJsGeu1GZPzANYLZQ9m13Joi3fhGFUgHLNL"
+ "0hsz/HQP89aTa9Qr8QqEP7r/vCvrcoKn9cKPGwRxOFkRgG4FWGv76F/hv+1Cj2Z7";
byte[] encoded = Base64.decodeBase64(privateKeyPEM);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
ECPrivateKey privateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
final JwtBuilder jwtBuilder = Jwts.builder()
.setSubject("713f42c9-7df5-4271-8b53-112f30936c56")
.signWith(SignatureAlgorithm.ES512,privateKey)
.setHeaderParam("typ","JWT");
System.out.println(jwtBuilder.compact());
但是,生成的JWT始终具有无效的签名:
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJzdWIiOiI3MTNmNDJjOS03ZGY1LTQyNzetoGI1My0xMTJmMzA5MzZjNTYifQ.MIGHAkFvCPq_BeXvATTN1duKjEf3K_Fja0ueoTuPQHC9kBc828wem7YO0vnlK6PVYXSkBk4gBaD0-OIMY_r-HS7-4-HaBwJCAMbj0k5YsBywMzme_adKTQq7YUsVvyZwGp8aVgX7vxsMhf-WNvQJSg7AG_zQiUaQ4jqtT9ZKzNoU4P5NZIGMDRCh
我不知道自己的代码出了什么问题。
解决方法
发布的私钥是PKCS#8密钥。由此可以得出以下X.509公用密钥:
-----BEGIN PUBLIC KEY-----
MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQAlCI4gpXtiYhUjfRjfLVRki+BkVG+
IcVa9KJNcQbgirMcqkWM4hizSvOfUXbOsUcqmYy1nQqHk7PJ8mwZ67UZk/MA1gtl
D2bXcmiLd+EYVSAcs0vSGzP8dA/z1pNr1CvxCoQ/uv+8K+tygqf1wo8bBHE4WRGA
bgVYa/voX+G/7UKPZns=
-----END PUBLIC KEY-----
如果使用发布的代码创建了JWT,例如:
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJzdWIiOiI3MTNmNDJjOS03ZGY1LTQyNzEtOGI1My0xMTJmMzA5MzZjNTYifQ.AE0sx6wHk2xBPkbam24n8NE39qkB0YX4j65DhrWyBKtaQXRMZjuzV78vFir3scfXVolFOf2gpo2K6x_hu0jPz-0IAIMbYQsglePQHQ9OZMSb2XAxKCVXccdvW27QeBov-VGUxxlL-CFNviaPaAGbNny_sc8cRjIF97pDD4KjOPBKkZzt
然后可以使用此公钥对此没有问题进行验证,例如进行检查here,即发布的代码产生有效的签名。
另一方面,JWT发表了一个问题:
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJzdWIiOiI3MTNmNDJjOS03ZGY1LTQyNzEtOGI1My0xMTJmMzA5MzZjNTYifQ.MIGHAkFvCPq_BeXvATTN1duKjEf3K_Fja0ueoTuPQHC9kBc828wem7YO0vnlK6PVYXSkBk4gBaD0-OIMY_r-HS7-4-HaBwJCAMbj0k5YsBywMzme_adKTQq7YUsVvyZwGp8aVgX7vxsMhf-WNvQJSg7AG_zQiUaQ4jqtT9ZKzNoU4P5NZIGMDRCh
确实无法验证。该JWT的签名已通过Base64url解码:
30818702416f08fabf05e5ef0134cdd5db8a8c47f72bf1636b4b9ea13b8f4070bd90173cdbcc1e9bb60ed2f9e52ba3d56174a4064e2005a0f4f8e20c63fafe1d2efee3e1da07024200c6e3d24e58b01cb033399efda74a4d0abb614b15bf26701a9f1a5605fbbf1b0c85ff9636f4094a0ec01bfcd0894690e23aad4fd64accda14e0fe4d64818c0d10a1
,因此 ASN.1编码, here和here。但是,JWT使用编码为 r | s 的签名,例如,参见here。如果将签名转换为这种编码,则结果为:
6f08fabf05e5ef0134cdd5db8a8c47f72bf1636b4b9ea13b8f4070bd90173cdbcc1e9bb60ed2f9e52ba3d56174a4064e2005a0f4f8e20c63fafe1d2efee3e1da07c6e3d24e58b01cb033399efda74a4d0abb614b15bf26701a9f1a5605fbbf1b0c85ff9636f4094a0ec01bfcd0894690e23aad4fd64accda14e0fe4d64818c0d10a1
如果这是Base64url编码并用于发布的JWT(而不是旧签名),则为:
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJzdWIiOiI3MTNmNDJjOS03ZGY1LTQyNzEtOGI1My0xMTJmMzA5MzZjNTYifQ.bwj6vwXl7wE0zdXbioxH9yvxY2tLnqE7j0BwvZAXPNvMHpu2DtL55Suj1WF0pAZOIAWg9PjiDGP6_h0u_uPh2gfG49JOWLAcsDM5nv2nSk0Ku2FLFb8mcBqfGlYF-78bDIX_ljb0CUoOwBv80IlGkOI6rU_WSszaFOD-TWSBjA0QoQ
JWT可以成功验证。
由于发布的代码生成的是RFC兼容的JWT(具有 r | s 签名),因此问题中发布的JWT可能不是通过发布的代码生成的(由于 ASN)。 1 签名)。
更新:根据 jjwt bugtracker,存在一个错误(#125),该错误导致签名未使用ASN.1正确签名。该错误应该用 jjwt 0.7 修复,并且可以合理地解释您的问题,前提是您使用的是受影响的版本(该错误来自05.2016)。
我已经测试了您的代码使用 jjwt 0.9.1 (自2018年7月起)生成有效的签名,即表示有效。
当前版本为 jjwt 0.11.2 (自06.2020起) ,它也可以根据other answer使用。
因此,如果您使用的是受影响的版本,最好使用较新的/当前的 jjwt 版本。如果由于某些原因无法实现,您当然可以手动将签名从 ASN.1 转换为 r | s 编码。
我的IntelliJ声称“ signWith”行已过时。
因此更改代码
final JwtBuilder jwtBuilder = Jwts.builder()
.setSubject("713f42c9-7df5-4271-8b53-112f30936c56")
.signWith(SignatureAlgorithm.ES512,privateKey)
.setHeaderParam("typ","JWT");
到
final JwtBuilder jwtBuilder = Jwts.builder()
.setSubject("713f42c9-7df5-4271-8b53-112f30936c56")
.signWith(privateKey,SignatureAlgorithm.ES512)
.setHeaderParam("typ","JWT");
正在给这个JWT:
eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzUxMiJ9.eyJzdWIiOiI3MTNmNDJjOS03ZGY1LTQyNzEtOGI1My0xMTJmMzA5MzZjNTYifQ.ALFk_BGerAstughF4ssl5eGQmx0mu5jvWb13QB228hAD5g8dwM-NvBsyevCuYUXLBJKzIUdPL-LVwQoPkwIbYrKhACzKwUwRN_v3IX2GIPW2ctTcRGPwA7gUaDWrOtwqcHALSfk20QZXT2TQfOnXX8tv0vhXLK_SnnHH5o1b96sa_HSR
由于仅提供ec私钥,所以我使用OpenSSL生成了EC公钥,并将JWT和公钥传递给Online JWT验证程序https://jwt.io/ 并得到结果“ 签名已验证”。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。