在 golang 中解密 JWE 令牌

Posted

技术标签:

【中文标题】在 golang 中解密 JWE 令牌【英文标题】:Decrypting JWE token in golang 【发布时间】:2020-09-22 04:39:44 【问题描述】:

我有这个问题,我在node.js中使用node-jose这样创建了一个JWE:

const keystore = [
  
    kty: 'oct',
    kid: 'QLdRkgyMx_po0fPo5XnOzQQB4iTcyay36m_PA62SBiw',
    k: 'A-OAikjssQZeLkj8N_2Xb9qPBG6lSq10YeLbiTF-kQuM_qKy08jwFqQwsLzn9fmNPkayM9uRg1lHBrPoK_fGtQ'
  
]

const ks = await jose.JWK.asKeyStore(keystore);
const rawKey = ks.get(keystore[0].kid)
const key = await jose.JWK.asKey(rawKey);
const jwe = await jose.JWE
      .createEncrypt(format: 'compact', key)
      .update(payload)
      .final();

根据文档,它是用"alg": "PBES2-HS256+A128KW", "enc": "A128CBC-HS256", 创建的,如果我在 jwt.io 中检查它,它就是。

然后,我需要在 golang 中解密,所以我喜欢使用 go-jose.v2:

package main

import (
    "fmt"
    "gopkg.in/square/go-jose.v2"
)

const jweRaw string = "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2Iiwia2lkIjoiUUxkUmtneU14X3BvMGZQbzVYbk96UVFCNGlUY3lheTM2bV9QQTYyU0JpdyIsInAyYyI6ODE5MiwicDJzIjoiaVktZEdKaWtYbUZCdXMwRFp5eHdIQSJ9.QkuIGmPojLDX-wpTVTjZRnA093fJRVM6OHkpmoQeyLubahOABg62WQ.z6dm86nWHcWgzmPXiuk0kg.7mOgYF6d9hgfXtTj9RUv7BNuYH-jBAs8px0boOFj1mke_JPetIT44yY7ceffFRfS2QYc6RQMtTvb7vdMArkqeB483g3-tcoCGWxafOb0VfVQHrPTdjpGMLF-9uIJw9z5.RA0Dn-B_Y3kvXYRvVTiNFQ"
const kid string = "QLdRkgyMx_po0fPo5XnOzQQB4iTcyay36m_PA62SBiw"
const k string = "A-OAikjssQZeLkj8N_2Xb9qPBG6lSq10YeLbiTF-kQuM_qKy08jwFqQwsLzn9fmNPkayM9uRg1lHBrPoK_fGtQ"

func main() 
    jwe, err1 := jose.ParseEncrypted(jweRaw)
    if err1 != nil 
        panic(err1)
    
    fmt.Println("jwe", jwe)
    bytes, err2 := jwe.Decrypt(jose.JSONWebKeyAlgorithm: "PBES2-HS256+A128KW", Use: "A128CBC-HS256", KeyID: kid, Key: k)
    if err2 != nil 
        panic(err2)
    
    fmt.Println("bytes", string(bytes))

但它会恐慌“恐慌:square/go-jose:密码原语中的错误” 你可以在这里查看:https://play.golang.org/p/qB3QNtGwBsK

我已经尝试过https://github.com/lestrrat-go/jwx,但是它不支持PBES2-HS256+A128KW算法

谢谢。

更新:这里有更多信息:

他们在节点中的键是用这个创建的:

const keystore = await jose.JWK.createKeyStore()
const key = await a.generate('oct', 512)
console.log(key.toJSON(true))

然后输出保存在这个数组中:

const keystore = [
  
    kty: 'oct',
    kid: 'QLdRkgyMx_po0fPo5XnOzQQB4iTcyay36m_PA62SBiw',
    k: 'A-OAikjssQZeLkj8N_2Xb9qPBG6lSq10YeLbiTF-kQuM_qKy08jwFqQwsLzn9fmNPkayM9uRg1lHBrPoK_fGtQ'
  
]

我一直在尝试在 golang 中使用相同的 JWK 创建相同的 JWE,我可以在 golang 中解密,但在节点中都没有(我收到“未找到密钥”错误)...所以,交叉解密不会为我工作。我做错了什么?

【问题讨论】:

试试godoc.org/github.com/square/go-jose 同样的错误。那是第 3 版。如果我在 golang 中创建 JWE 并尝试使用 node-jose 解密,则会出现“找不到密钥”错误 【参考方案1】:

k 是八位字节密钥的 base64url 编码表示,除非 go 接口特别提到以 JWK 格式传递密钥,否则您需要提供原始密钥。 base64url.decode()k 获取原始密钥字节。

另外,作为旁注,PBES2-HS256+A128KW 旨在用于密码,而不是密钥,因为它的计算量很大,我建议使用不同的密钥包装算法(不是基于对称密码短语的算法)。您可以使用非对称加密为收件人加密。如果你还想实现消息的认证,根本不要使用密钥包装,而是使用来自JWE的直接密钥协议。

【讨论】:

和 FWIW,node-jose 包做错了,因为我也无法解密 JWE,而且你说它无法解密它自己的加密 JWE,这很奇怪这使用完全对称的算法。 是的,就是这样。非常感谢! 对不起,如果说错了,但是node-jose可以解密的是自己的JWE。只有交叉解密失败。 这是我成功的测试:play.golang.org/p/AwvHKIZCdKB

以上是关于在 golang 中解密 JWE 令牌的主要内容,如果未能解决你的问题,请参考以下文章

golang 在golang中使用AES256 GCM解密文本

用于以JWE JSON序列化格式解析JWT令牌的Java库

RSA OAEP、Golang 加密、Java 解密 -BadPaddingException:解密错误

golang协程调度模式解密

是否可以在 Php 中加密 JWT 令牌并在 Javascript 中解密?

golang golang gpg / openpgp加密/解密示例