前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JSON 网络加密(JWE)说明

JSON 网络加密(JWE)说明

作者头像
阿东
发布2024-03-22 17:21:22
1970
发布2024-03-22 17:21:22
举报
文章被收录于专栏:公众号:懒时小窝

Source

JSON Web Encryption (JWE) の解説 #JWT - Qiita

-------------- GPT 翻译 --------------

JSON Web Encryption(JWE)解释

我之前在工作中研究了一下JWE,现在将整理的资料修改后发布到 Qiita 上。

JWE是什么

JSON Web Encryption(JWE)是一种将加密数据与解密所需的元数据一起打包成 JSON 格式的数据表示形式。此外,它还具有通过 AEAD 提供的完整性(防篡改)保证功能。该规范已被 IETF 制定为 RFC 标准。 JWE 是 JSON Web Signature(JWS)用于签名和打包消息以确保防篡改性,以及用于在各方之间交换认证令牌的 JSON Web Token(JWT)等规范中的一部分。JWT可以利用JWSJWE

RFC 7516 - JSON Web Encryption(JWE)。

序列化格式

JWE 定义了两种序列化形式,分别是JWE Compact SerializationJWE JSON Serialization

JWE Compact Serialization

JWE Compact Serialization是一种通过.(点)连接5个经过 BASE64URL 编码的组件的序列化方式。由于是 Web 安全的,因此可以在 URL 或 HTTP 头值中使用。 以下是JWE Compact Serialization的示例。换行仅为了方便显示。

代码语言:javascript
复制
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ
.
AAG-Mxcoy3qHgYNZTGC8IzLhTkQOv7Iku5JI_gGm1Ev1GaqlbwdWT5x0rtvNSIxbvGOA
KFoTnPygByBcvXVkD0SnkPotkjXqKXocozG9zT9vaHdDUtth4ySKMs9huVXWqglZTkSA
QvZSpxSU6Gu0ZUB5yuUO2XZEeIwuRiG9F0hlAuQDokNvqWS69NfDxoiRN6Qp7Ud67LF8
FH75JA_eSuJsrW1JWWcB8bHQgrbB0WU-z5IVbyN7VPGNm1GGdENSh963iRTb0DlvADF-
KbU5yIHRomvJxEjOQDS2LYyswy6zAv7rrJeTO4dzgWYo7lcf07F19U8mGFfiimFXD5Lw
.
HtGmVwOnLfsVZmp1
.
cHUwotN3V05o4sHRhA
.
NGmNkNr5QyuVYGh93zknlA

上面的 JWE 令牌由以下组件组成。

代码语言:javascript
复制
base64url(JWE Header)
.
base64url(JWE Encrypted)
.
base64url(JWE Initialization Vector)
.
base64url(JWE Ciphertext)
.
base64url(JWE Authentication Tag)

每个组件的作用如下

  • JWE 标头
    • JOSE 标头,一串 JSON 对象,包含用于解释 JWE 标记的信息。需要两个密钥:algenc
  • JWE 加密密钥
    • 用于加密内容的密钥(CEK),用另一个密钥加密。
  • JWE 初始化向量
    • 用于加密内容的初始化向量。
  • JWE 密码文本
    • 加密后的内容正文。
  • JWE验证标签
    • 保证 JWE 令牌完整性的验证标签,用于验证 JWE 令牌是否被篡改。

JWE JSON序列化

JWE JSON序列化 是一种将整个数据表示为单个JSON对象的序列化方式,其中每个组件都以JSON键值对的形式表示。可以指定多个接收者(Recipient),并且可以为每个接收者指定不同的算法和加密密钥。 以下是JWE紧凑序列化的示例。换行仅为了显示方便。

代码语言:javascript
复制
{
  "protected": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ",
  "encrypted_key": "KJpOWsV4gN-3tPaEoEd_Ae0UE6KI4gvWdt6Vuc_mOUmeWX2L9QYvi_CeCNZaiWoQoAT-pE4oiewGufT-7xgkILILvSoomrFD0xJlmWkJcGUoSZSUZr7nmOJa6V0XHbA--g3F1B35Jk-qUd7tgAxb9uDJKkfr96LTe1_Zt6ADUkaPwnB_0mqSqWXVl14W1LuwPYHrE9K4tPXtn6O3uoOAACLR8X_oGr5x8uVicgOBYpitDsB30k-0o-T6a8kgpD3MHF1iYYIKrZb-QEbeTYyT9wDbMsS4FsmRqKHu6kQ94ha4wFBEJ_fUvWvXnbX5WZ67zrCg8MtqEKAibUfRKv5Zeg",
  "iv": "7ObH5owmUWQdldiQ",
  "ciphertext": "DW2iCLUFevSLloS4mg",
  "tag": "UoZ1Ljz_a7R4QhFoWwNRlQ"
}

由于这种格式并不常用,因此本文将基于JWE紧凑序列化进行解释。

JOSE头

JOSE头是一个JavaScript对象,其中包含了处理JWE令牌所需的元数据。JOSE头受到篡改的保护。在RFC中定义的参数称为JWE保护头,其中encalg头是必需的参数。

以下是一些代表性的头参数:

  • 必需头
    • 指定加密密钥(CEK)的管理方法。可用的算法在RFC 7518 - JSON Web Algorithms (JWA) section 4.1中定义。详见下文。
    • 指定用于加密内容的算法。除了RFC 7518 JWA的5.1章节中定义的算法标识符之外,还可以指定具有冲突防止前缀的未注册算法。算法必须是使用指定长度的密钥的AEAD(带认证的加密)算法。后面会详细介绍可用的算法。
    • enc头(加密算法)
    • alg头(算法)
  • 指定密钥的头
    • 对应于加密JWE的密钥的X.509 DER编码SHA-256摘要的base64url编码。可用于标识复合JWE所需的秘密密钥。
    • 对应于加密JWE的密钥的X.509 DER编码SHA-1摘要的base64url编码。可用于标识复合JWE所需的秘密密钥。
    • 用于加密JWE的X.509公钥证书或证书链。这是一个证书字符串数组。可用于标识复合JWE所需的秘密密钥。
    • 引用与加密JWE对应的PEM格式的.509公钥证书或证书链资源的URI。可用于标识复合JWE所需的秘密密钥。
    • 指示用于加密JWE的哪个密钥的提示信息。KID的结构未定义。如果与JWK一起使用,则用于匹配JWK "kid"参数值。
    • 对应于加密JWE的密钥的公钥。此密钥以JSON Web Key [JWK]格式表示。
    • 引用JSON编码的公钥集合(其中之一对应于加密JWE的密钥)的URI。已使用JWK Set格式进行编码。
    • jku头(JWK集合URL)
    • jwk头(JSON Web Key)
    • kid头(密钥ID)
    • x5u头(X.509 URL)
    • x5c头(X.509证书链)
    • x5t头(X.509证书SHA-1 Thumbprint)
    • x5t#S256头(X.509证书SHA-256 Thumbprint)
  • 其他已注册头参数
    • 枚举扩展规范和/或JWA头名称的数组,其中接收者必须理解和处理JOSE头。如果接收者未理解并执行列出的任何头,则该JWS/JWE无效。
    • 可选头,用于指示受保护的内容(有效载荷)的类型。取值为IANA Media Type。如果JWS/JWE具有多个有效载荷,则用于区分它们的类型。
    • 指示JWE对象的类型。如果需要处理不同类型的对象,则应用程序将使用JOSE对象来区分它们。
    • 可用的值
    • JOSE:使用JWS Compact Serialization的JWS或JWE
    • JOSE+JSON:使用JWS JSON Serialization的JWS或JWE
    • 其他值:应用程序可以使用其他值。(无法处理的值将被忽略)
    • 在加密内容之前,可以使用zip指定的算法对Plaintext进行压缩。可以使用表示DEFLATE压缩的DEF
    • zip头(压缩算法)
    • typ头(类型)
    • cty头(内容类型)
    • crit头(关键)

JWE生成步骤

下图展示了JWE的生成步骤。输入值为用橙色表示的密钥、头部参数和明文,输出为底部的深灰色方框中的JWE。该过程由两个步骤组成,即大致为①CEK生成和②内容加密。

image.png

① CEK生成

alg头部参数指定的算法各自具有相应的密钥管理模式,但是通过该密钥管理模式定义的方式,将生成或准备好用于加密内容的**内容加密密钥(CEK)**。共定义了以下5种密钥管理模式。

alg 参数值和密钥管理模式

  • 直接加密
    • dir
    • 使用的内容加密密钥是在参与方之间共享的秘密对称密钥值的密钥管理模式。共享的CEK本身作为参数提供。
    • 支持的算法
  • 直接密钥协商
    • ECDH-ES
    • 椭圆曲线迪菲-赫尔曼短暂静态密钥协商
    • 使用密钥协商算法就内容加密密钥达成一致的密钥管理模式。
    • 支持的算法
  • 密钥协商与密钥包装
    • ECDH-ES+A128KW, ECDS-ES+A192KW, ECDS-ES+A256KW
    • 使用Concat KDF的ECDH-ES和各个密钥长度的CEK包装
    • 使用对称密钥包装算法将内容加密密钥值加密的对称密钥用于共享密钥的密钥管理算法的密钥管理模式。
    • 支持的算法
  • 密钥加密
    • RSA1_5
    • RSA-OAEP
    • RSA-OAEP-256
    • RSAES-PKCS1-v1_5
    • 使用默认参数的RSAES OAEP
    • 使用SHA-256的RSAES OAEP和基于SHA256的MGF1
    • 使用非对称密钥加密算法(公钥加密)对内容加密密钥值进行加密的密钥管理模式。
    • 用于加密CEK的非对称密钥作为外部参数提供。
    • 支持的算法
  • 密钥包装
    • A128KW, A192KW, A256KW
    • PBES2-HS256+A128KW, PBES2-HS284+A192KW, PBES2-HS512+A256KW
    • A128GCMKW, A192GCMKW, A256GCMKW
    • 使用128、192、256位密钥的默认初始值的AES密钥包装
    • 使用HMAC SHA-256、284、512的PBES2和A128KW、A192KW、A256KW密钥包装
    • 使用128、192、256位密钥的AES GCM密钥包装
    • 使用对称密钥包装算法(共享密钥加密)对内容加密密钥值进行加密的密钥管理模式。注意:密钥包装:一种设计用于封装(加密)加密密钥的对称加密算法。参考:Key Wrap - Wikipedia
    • 用于包装CEK的目标密钥作为外部参数提供。
    • 支持的算法

在每种密钥管理模式下,按照下表的步骤生成密钥。

② 内容加密

通过enc标头参数指定的算法(见下表)对内容进行加密。

  • A128CBC-HS256
    • AES_128_CBC_HMAC_SHA256 带认证的加密算法。
  • A192CBC-HS384
    • AES_192_CBC_HMAC_SHA384 带认证的加密算法。
  • A256CBC-HS512
    • AES_256_CBC_HMAC_SHA512 带认证的加密算法。
  • A128GCM
    • 使用128位密钥的 AES GCM
  • A192GCM
    • 使用192位密钥的 AES GCM
  • A256GCM
    • 使用256位密钥的 AES GCM

来源:RFC 7518 - JSON Web Algorithms (JWA)。

加密处理的输入包括明文内容加密密钥初始化向量(IV)、附加认证数据(AAD),输出为密文和AEAD的**认证标签(Authentication Tag)**。

  • 输入
    • 由于JWE中指定的加密算法为AEAD(带认证的加密算法),可以使用附加认证数据(AAD)来生成认证标签。通过这个标签,如果JWE的AAD部分或密文部分被篡改,解密时会出现错误,从而可以检测到篡改,确保JWE的完整性。在JWE Compact Serialization中,JWE Protected Header被用作AAD。在JWE JSON Serialization中,可以指定任意参数作为AAD。
    • 在CBC模式下,使用相同密钥对相同明文进行加密会生成相同的密文,从而泄露信息。为了防止这种情况发生,每次加密都会准备一个唯一的字节序列,称为初始化向量。初始化向量本身并不需要保密,因此在JWE中会在加密时随机生成,并直接包含在最终的JWE中。
    • 用于加密内容的密钥
    • 内容加密密钥(CEK: Content Encryption Key):
    • 初始化向量(IV: Initial Vector):
    • 附加认证数据(AAD: Additional Authentication Data):

3.创建 JWE 令牌

以下五个部分用句号". 来完成 JWE 令牌。

  1. 以 UTF-8 + Base64Url 编码的 JWE 受保护标头
  2. 在 ① 中获取的 JWE 加密密钥的 Base64Url。在②中随机生成的 JWE 初始向量的 Base64Url。在②中加密的 JWE 密文的 Base64Url。JWE 验证标签的 Base64Url,即在②中加密的输出。

实现

在Go语言中,可以使用square/go-jose库来处理JWE。让我们使用go-jose.v2来创建一个JWE令牌。

代码语言:javascript
复制
package main

import (
    "crypto/rand"
    "crypto/rsa"
    "fmt"
    "log"

    jose "gopkg.in/square/go-jose.v2"
)

func main() {
    var plaintext = []byte("Lorem ipsum dolor sit amet")
    fmt.Println("Plaintext:", string(plaintext))

    //
    // RSA-OAEP で使うためのRSA鍵を生成
    //
    privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        log.Fatal(err)
    }

    //
    // enc: AES128-GCM, alg: RSA-OAEP で暗号化し、JWE Compact Serializationで出力
    //
    encrypter, err := jose.NewEncrypter(jose.A128GCM, jose.Recipient{
        Algorithm: jose.RSA_OAEP,
        Key:       privateKey.PublicKey,
    }, nil)
    if err != nil {
        log.Fatal(err)
    }
    object, err := encrypter.Encrypt(plaintext)
    if err != nil {
        log.Fatal(err)
    }
    token, err := object.CompactSerialize()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("JWE Token:", token)

    //
    // 復号化
    //
    object, err = jose.ParseEncrypted(token)
    if err != nil {
        log.Fatal(err)
    }
    decrypted, err := object.Decrypt(privateKey)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Decrypted: %s\n", decrypted)
}

执行结果

代码语言:javascript
复制
Plaintext: Lorem ipsum dolor sit amet
JWE Token: eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.YOnRGwtYnd4C4w_OEtxlHhFzJT3qUH6APt7jDXTn3ln5yt-kS1RxM29uM3NEBnop5ZcQhtqNmZ90VeyN3AqsMGDp1KkEvHOb1O405Iwk1taaI5XZfGI6dxAhnH6YonbUBpQkqgHcNQhOYxgXuOkhecCUCyKKK-RcsukQSDNWB4rjf0QRwvcjtC4uAsnplsP2gwKNof4QgV_yMoVLBYFg6YVyDeYdIVSLIeZxO0SKIDbugF698Mufrj5gjsd_ydm-kvFlLO29Bti5eaDnOetlw1QzCzHa8fjUHoRyS6L5kcKjPqs6HzIxZv53OxrAsWq2IWdmnkMfBSXIMHCCIPeBVw.RZ9qri36pOoV_5C-.bQCU4nVQ9lrEH4EgvExzTjziJ8iWTzW7BKI.iNIOEhEt9eglEX6rGXxXpw
Decrypted: Lorem ipsum dolor sit amet

JWE的批评

JWE(或JOSE)受到了安全性方面的批评。特别是Paragon的工程师指出,在许多实现中,JWS存在攻击可能性,而JWE中定义的公钥加密算法很多都是脆弱的,开发人员可能会自掘坟墓。他们认为Fernet更优秀,提出了解决JOSE问题的PASETO。

  • JOSE是一个绝对应该避免的糟糕标准 | POSTD
  • No Way, JOSE! Javascript Object Signing and Encryption is a Bad Standard That Everyone Should Avoid - Paragon Initiative Enterprises Blog
  • 带PKCS #1v1.5填充的RSA
    • "带PKCS #1v1.5填充的RSA容易受到一种称为填充预言的选择密文攻击的影响"
  • 带OAEP填充的RSA
    • 如果将RSA视为安全的话,那就是安全的,但是"安全专家建议从RSA迁移"
  • ECDH
    • 在JWT(JOSE?)中只允许使用基于椭圆曲线迪菲-赫尔曼的ECDH,但该曲线存在Invalid-Curve攻击的脆弱性。由于AES-GCM上述公钥加密模式存在疑问,应该使用预共享密钥密码模式(?)

总结

您觉得如何?我们讨论了Javascript Web Encryption的规范和创建方法。或许可以考虑使用PASETO或Branca等替代标准。辛苦了。

-------------- 原文 --------------

JSON Web Encryption (JWE) の解説

ちょっと前に業務で JWE について調べ物をしたので、その際の資料を改稿して Qiita に放流します。

JWE とは

JSON Web Encryption (JWE) とは、暗号化したデータを、復号に必要なメタデータとあわせて JSON 形式でパッケージするデータ表現形式です。また、 AEAD による完全性(改竄耐性)保証の機能も持ちます。仕様は IETF により RFC 化されています。 JWE は、メッセージを署名とパッケージして改竄耐性を保証する JSON Web Signature (JWS) や、パーティ間で認証トークンを交換するための JSON Web Token (JWT) などを含む Javascript Object Signing and Encryption (JOSE) と呼ばれる規格群のひとつです。 JWT は、 JWS または JWE を利用することができます。

RFC 7516 - JSON Web Encryption (JWE)。

シリアライゼーション形式

JWE には、JWE Compact SerializationJWE JSON Serialization の二種類のシリアライズ形式が定義されています。

JWE Compact Serialization

JWE Compact Serialization は、 BASE64URL エンコードされた5つのコンポーネントを、.(ピリオド)で結合するシリアライゼーション方式です。Web セーフなため、URL や HTTP ヘッダ値のなかで使用できます。 以下に JWE Compact Serialization の例を示します。改行は表示の都合です。

代码语言:javascript
复制
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ
.
AAG-Mxcoy3qHgYNZTGC8IzLhTkQOv7Iku5JI_gGm1Ev1GaqlbwdWT5x0rtvNSIxbvGOA
KFoTnPygByBcvXVkD0SnkPotkjXqKXocozG9zT9vaHdDUtth4ySKMs9huVXWqglZTkSA
QvZSpxSU6Gu0ZUB5yuUO2XZEeIwuRiG9F0hlAuQDokNvqWS69NfDxoiRN6Qp7Ud67LF8
FH75JA_eSuJsrW1JWWcB8bHQgrbB0WU-z5IVbyN7VPGNm1GGdENSh963iRTb0DlvADF-
KbU5yIHRomvJxEjOQDS2LYyswy6zAv7rrJeTO4dzgWYo7lcf07F19U8mGFfiimFXD5Lw
.
HtGmVwOnLfsVZmp1
.
cHUwotN3V05o4sHRhA
.
NGmNkNr5QyuVYGh93zknlA

上の JWE トークンは、以下のようなコンポーネントで構成されています。

代码语言:javascript
复制
base64url(JWE Header)
.
base64url(JWE Encrypted)
.
base64url(JWE Initialization Vector)
.
base64url(JWE Ciphertext)
.
base64url(JWE Authentication Tag)

それぞれのコンポーネントは、以下の役割を持ちます。

  • JWE Header
    • JOSEヘッダ。JWEトークンを解釈するための情報が格納されているJSONオブジェクトの文字列。algenc の2キーが必須。
  • JWE Encrypted Key
    • コンテンツの暗号化に使われた鍵(CEK)が、別の鍵で暗号化されたもの。
  • JWE Initialization Vector
    • コンテンツの暗号化に使われた初期化ベクトル。
  • JWE Ciphertext
    • 暗号化されたコンテンツ本体。
  • JWE Authentication Tag
    • JWE トークンの完全性を保証する認証タグ。JWE トークンの改竄の有無を検証するために使われる。

JWE JSON Serialization

一方の JWE JSON Serialization は、全体がひとつの JSON であるシリアライゼーション方式で、各コンポーネントが JSON のキー・バリューの形で表現されています。複数の Recipient (受信者)を指定でき、 Recipient ごとに異なるアルゴリズムや Encrypted Key を指定できます。 以下に JWE Compact Serialization の例を示します。改行は表示の都合です。

代码语言:javascript
复制
{
  "protected": "eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ",
  "encrypted_key": "KJpOWsV4gN-3tPaEoEd_Ae0UE6KI4gvWdt6Vuc_mOUmeWX2L9QYvi_CeCNZaiWoQoAT-pE4oiewGufT-7xgkILILvSoomrFD0xJlmWkJcGUoSZSUZr7nmOJa6V0XHbA--g3F1B35Jk-qUd7tgAxb9uDJKkfr96LTe1_Zt6ADUkaPwnB_0mqSqWXVl14W1LuwPYHrE9K4tPXtn6O3uoOAACLR8X_oGr5x8uVicgOBYpitDsB30k-0o-T6a8kgpD3MHF1iYYIKrZb-QEbeTYyT9wDbMsS4FsmRqKHu6kQ94ha4wFBEJ_fUvWvXnbX5WZ67zrCg8MtqEKAibUfRKv5Zeg",
  "iv": "7ObH5owmUWQdldiQ",
  "ciphertext": "DW2iCLUFevSLloS4mg",
  "tag": "UoZ1Ljz_a7R4QhFoWwNRlQ"
}

この形式はあまり使われないため、本稿では JWE Compact Serialization を前提に解説を進めます。

JOSEヘッダ

JOSEヘッダ は、JWEトークンを適切に扱うためのメタ情報が格納された JavaScript オブジェクトです。 JOSEヘッダ は改竄に対して保護されます。JOSEヘッダ のうち、RFCで定義されたパラメータは JWE Protected Header と定義され、そのうち、encalg ヘッダは必須パラメータです。

以下に、代表的なヘッダパラメータを紹介します。

  • 必須ヘッダ
    • コンテンツを暗号化した鍵(CEK)の管理方法 を指定します。使用可能なアルゴリズムは、RFC 7518 - JSON Web Algorithms (JWA) section 4.1 に定義されています。詳細は後述。
    • コンテンツを暗号するためのアルゴリズム を指定します。RFC 7518 JWAの5.1章で定義されたアルゴリズム識別子 のほか、衝突防止プレフィックスをもつ未登録アルゴリズムを指定できます。アルゴリズムは、指定された長さのキーを使うAEAD(認証付き暗号化)アルゴリズムである必要がります。使用可能なアルゴリズムについては後述します。
    • enc ヘッダ (Encryption Algorithm)
    • alg ヘッダ (algorithm)
  • 鍵を指定するヘッダ
    • JWEを暗号化した鍵に相当するX.509のDERエンコードのSHA-256サムプリント(ダイジェスト)をbase64urlエンコードしたもの。JWEの復号に必要な秘密鍵を特定するために使うことができます。
    • JWEを暗号化した鍵に相当するX.509のDERエンコードのSHA-1サムプリント(ダイジェスト)をbase64urlエンコードしたもの。JWEの復号に必要な秘密鍵を特定するために使うことができます。
    • JWEを暗号化するために用いるX.509公開鍵証明書または証明書チェーン。証明書文字列の配列です。JWEの複合に必要な秘密鍵を特定するために使うことができます。
    • JWEを暗号化した鍵に対応する、PEM形式の.509公開鍵証明書もしくは証明書チェーンリソースを参照するURI. JWEの複合に必要な秘密鍵を特定するために使うことができます。
    • JWEを暗号化するためにどの鍵が使用されたかを示すヒント情報。KIDの構造は定義されていない。JWKとともに使われた場合、JWK "kid" パラメータ値を照合するために用いられます。
    • JWEを暗号化した鍵に対応する公開鍵。このキーはJSON Web Key[JWK]の形式で表現されます。
    • JSONエンコードされた公開鍵のセット(そのうちひとつはJWEを暗号化した鍵に相当する)を参照するURI。JWK Set形式でエンコードされています。
    • jku ヘッダ (JWK Set URL)
    • jwk ヘッダ (JSON Web Key)
    • kid ヘッダ (Key ID)
    • x5u ヘッダ (X.509 URL)
    • x5c ヘッダ (X.509 Certificate Chain)
    • x5t ヘッダ (X.509 Certificate SHA-1 Thumbprint)
    • x5t#S256 ヘッダ (X.509 Certificate SHA-256 Thumbprint)
  • その他の Registered Header Parameters
    • JOSEヘッダのうち、受信者によって理解して処理されなければいけない拡張仕様および/またはJWAヘッダ名を列挙した配列。もしも列挙されたいずれかのヘッダが受信者によって理解され実行されなかった場合、そのJWS/JWEは不正です。
    • 保護されたコンテンツ(ペイロード)のタイプを示すために、アプリケーションにより使われるオプショナルヘッダ。IANA Media Typeの値をとります。JWS/JWEにペイロードが複数ある場合、種類を区別するために使うためのもの。
    • JWEオブジェクトの種類を示します。異なる種類のオブジェクトも扱う必要がある場合に、アプリケーションがJOSEオブジェクトを他のものと区別するために使うためのもの。
    • 使用可能な値
    • JOSE: JWS Compact Serialization を用いたJWSまたはJWE
    • JOSE+JSON: JWS JSON Serialization を用いたJWSまたはJWE
    • その他の値: アプリケーションはその他の値を使っても良い。(扱えない値は無視される)
    • コンテンツを暗号化する前に、zipで指定したアルゴリズムでPlaintextを圧縮できます。DEFLATE圧縮を示す DEF が使用できます。
    • zip ヘッダ (Compression Algorithm)
    • typ ヘッダ (Type)
    • cty ヘッダ (Content Type)
    • crit ヘッダ (Critical)

JWE生成の手順

JWEの作成手順を図に示します。オレンジ色で示した , ヘッダパラメータPlaintext が入力値で、下部の濃い灰色のボックスが出力されるJWEです。手順は大きく ①CEK生成②コンテンツ暗号化 の2ステップで構成されます。

image.png

① CEK生成

alg ヘッダパラメータによって指定されるアルゴリズムは、それぞれ対応する 鍵管理モード を持ちますが、この鍵管理モードにより定義される方法で、コンテンツを暗号化する コンテンツ暗号化キー(CEK) が生成または用意されます。鍵管理モードとして、以下の5種類のモードが定義されています。

alg パラメータ値と鍵管理モード

  • Direct Encryption
    • dir
    • 使用さているコンテンツ暗号化キーがパーティ間で共有されている秘密の対称的なキー値であるキー管理モード。共有されたCEKそのものが外部からパラメータとして与えられます。
    • 対応アルゴリズム
  • Direct key Agreement
    • ECDH-ES
    • Elliptic Curve Diffie-Hellman Ephemeral Static 鍵共有
    • 鍵共有(Key Agreement) アルゴリズムを使ってコンテンツ暗号化キーについて同意するキー管理モード。
    • 対応アルゴリズム
  • Key Agreement with Key Wrapping
    • ECDH-ES+A128KW, ECDS-ES+A192KW, ECDS-ES+A256KW
    • Concat KDFを使ったECDH-ES と 各キー長でのCEKラップ
    • 対称的な鍵ラップアルゴリズムを使ってコンテンツ暗号化キー値を暗号化するのに使われている対称的キーを共有するためにキーマネジメントアルゴリズムが使われているキー管理モード。
    • 対応アルゴリズム
  • Key Encryption
    • RSA1_5
    • RSA-OAEP
    • RSA-OAEP-256
    • RSAES-PKCS1-v1_5
    • デフォルトパラメータを使ったRSAES OAEP
    • SHA-256 を使った RSAES OAEP と SHA256 による MGF1
    • コンテンツ暗号化キーの値が非対称鍵を使った鍵暗号化アルゴリズム(公開鍵暗号)を用いて暗号化されるキー管理モード。
    • CEKを暗号化するための非対称鍵が外部からパラメータとして与えられます。
    • 対応アルゴリズム
  • Key Wrapping
    • A128KW, A192KW, A256KW
    • PBES2-HS256+A128KW, PBES2-HS284+A192KW, PBES2-HS512+A256KW
    • A128GCMKW, A192GCMKW, A256GCMKW
    • 128, 192, 256ビットキーを使ったデフォルト初期値による AES 鍵ラップ
    • HMAC SHA-256, 284, 512 による PBES2 と A128KW, A192KW, A256KW 鍵ラップ
    • 128, 192, 256キーを使ったAES GCMによる鍵ラップ
    • コンテンツ暗号化キーの値が対称鍵を使った鍵ラップアルゴリズム(共通鍵暗号)を用いて暗号化されるキー管理モード。NOTE: 鍵ラップ:暗号鍵をカプセル化(暗号化)するためにデザインされた対称的暗号アルゴリズムの種類。Ref: Key Wrap - Wikipedia
    • CEKをラップするための対象鍵が外部からパラメータとして与えられる
    • 対応アルゴリズム

各鍵管理モードでは、次の表な手順で鍵を生成します。

② コンテンツ暗号化

enc ヘッダパラメータにより指定されたアルゴリズム(下表)でコンテンツを暗号化します。

  • A128CBC-HS256
    • AES_128_CBC_HMAC_SHA256 認証付き暗号化アルゴリズム.
  • A192CBC-HS384
    • AES_192_CBC_HMAC_SHA384 認証付き暗号化アルゴリズム.
  • A256CBC-HS512
    • AES_256_CBC_HMAC_SHA512 認証付き暗号化アルゴリズム.
  • A128GCM
    • 128ビットキーを使った AES GCM
  • A192GCM
    • 192ビットキーを使った AES GCM
  • A256GCM
    • 256ビットキーを使った AES GCM

RFC 7518 - JSON Web Algorithms (JWA) より。

暗号処理の入力は 平文, コンテンツ暗号化キー, 初期化ベクトル(Initial Vector), 追加暗号化データ(AAD) で、出力は Ciphertext とAEADの認証タグ(Authentication Tag) です。

  • 入力
    • JWEで指定可能な暗号化アルゴリズムはAEAD(認証付き暗号化アルゴリズム)なので、追加の認証データ(AAD)を使い、 Authentication Tag を生成することができます。このタグにより、JWEのAAD部とCiphertext部のどちらかが改竄されると復号時にエラーになり、改竄されたことがわかるため、JWEは完全性が得られます。JWE Compact Serialization では、AADとしてJWE Protected HeaderがAADとして使われます。JWE JSON Serialization では、AAEとして任意のパラメータを指定できます。
    • CBCモードで同じ鍵を使って同じ平文を暗号化すると、同じ暗号文が生成され、同じ内容であることがわかってしまう。これを防ぐため、暗号化ごとに用意されるユニークなバイト列のこと。暗号化した出力をランダム化するために用いられます。IV自体は秘匿すべき情報ではないため、JWEでは暗号化の際にランダムに生成され、最終的なJWEにそのまま表現されます。
    • コンテンツを暗号化するためのキー
    • コンテンツ暗号化キー(CEK: Content Encryption Key):
    • 初期化ベクトル(IV: Initial Vector):
    • 追加認証データ(AAD: Additional Authentication Data):

3. JWE トークンを構築する

以下の5コンポーネントをピリオド'.'で連結し、JWEトークンの完成です。

  1. JWE Protected HeaderをUTF-8エンコード+Base64Urlしたもの
  2. ① で求めたJWE Encryption Key をBase64Urlしたもの
  3. ② でランダムに生成したJWE Initial Vector を Base64Urlしたもの
  4. ② で暗号化した出力であるJWE Ciphertext を Base64Urlしたもの
  5. ② で暗号化した出力であるJWE Authentication Tag をBase64Urlしたもの

実装

GoでJWEを使用するライブラリには、square/go-jose が挙げられます。go-jose.v2 を使ってJWEトークンを作成してみましょう。

代码语言:javascript
复制
package main

import (
    "crypto/rand"
    "crypto/rsa"
    "fmt"
    "log"

    jose "gopkg.in/square/go-jose.v2"
)

func main() {
    var plaintext = []byte("Lorem ipsum dolor sit amet")
    fmt.Println("Plaintext:", string(plaintext))

    //
    // RSA-OAEP で使うためのRSA鍵を生成
    //
    privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
    if err != nil {
        log.Fatal(err)
    }

    //
    // enc: AES128-GCM, alg: RSA-OAEP で暗号化し、JWE Compact Serializationで出力
    //
    encrypter, err := jose.NewEncrypter(jose.A128GCM, jose.Recipient{
        Algorithm: jose.RSA_OAEP,
        Key:       privateKey.PublicKey,
    }, nil)
    if err != nil {
        log.Fatal(err)
    }
    object, err := encrypter.Encrypt(plaintext)
    if err != nil {
        log.Fatal(err)
    }
    token, err := object.CompactSerialize()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("JWE Token:", token)

    //
    // 復号化
    //
    object, err = jose.ParseEncrypted(token)
    if err != nil {
        log.Fatal(err)
    }
    decrypted, err := object.Decrypt(privateKey)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Decrypted: %s\n", decrypted)
}

実行結果

代码语言:javascript
复制
Plaintext: Lorem ipsum dolor sit amet
JWE Token: eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkExMjhHQ00ifQ.YOnRGwtYnd4C4w_OEtxlHhFzJT3qUH6APt7jDXTn3ln5yt-kS1RxM29uM3NEBnop5ZcQhtqNmZ90VeyN3AqsMGDp1KkEvHOb1O405Iwk1taaI5XZfGI6dxAhnH6YonbUBpQkqgHcNQhOYxgXuOkhecCUCyKKK-RcsukQSDNWB4rjf0QRwvcjtC4uAsnplsP2gwKNof4QgV_yMoVLBYFg6YVyDeYdIVSLIeZxO0SKIDbugF698Mufrj5gjsd_ydm-kvFlLO29Bti5eaDnOetlw1QzCzHa8fjUHoRyS6L5kcKjPqs6HzIxZv53OxrAsWq2IWdmnkMfBSXIMHCCIPeBVw.RZ9qri36pOoV_5C-.bQCU4nVQ9lrEH4EgvExzTjziJ8iWTzW7BKI.iNIOEhEt9eglEX6rGXxXpw
Decrypted: Lorem ipsum dolor sit amet

JWEへの批判

JWE(またはJOSE)はセキュリティ上の批判に晒されていいます。特にParagonのエンジニアは、JWSでは多くの実装で攻撃が可能で、JWEは定義されている公開鍵暗号アルゴリズムは脆弱なものが多く、開発者が自分の足を撃つリスクが高いと主張しています。Fernetの方が優れており、さらにJOSEの問題を解決したPASETOを提案しています。

  • JOSEは、絶対に避けるべき悪い標準規格である | POSTD
  • No Way, JOSE! Javascript Object Signing and Encryption is a Bad Standard That Everyone Should Avoid - Paragon Initiative Enterprises Blog
  • PKCS #1v1.5パティング付きRSA
    • "PKCS #1v1.5パディング付きRSAは、パディングオラクルと呼ばれる一種の選択暗号文攻撃に対して脆弱"
  • OAEPパディング付きRSA
    • RSAを安全だとみなすなら安全だが、"セキュリティの専門家はRSAから移行するように勧めている"
  • ECDH
    • JWT(JOSE?)では楕円曲線ディフィー・ヘルマンを使ったECDHのみ許されているが、この曲線は Invalid-Curve攻撃 の脆弱性があります。AES-GCM 上記の公開鍵暗号モードは疑わしいので、事前に鍵を共有する共有鍵暗号モードをつかうべき(?)

まとめ

いかがでしたか?コンテンツの暗号表現であるJavascript Web Encription の仕様、作成方法について解説しました。PASETO や Branca などの代替規格を検討してもいいかもしれませんね。お疲れ様でした。

欢迎关注公众号

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-03-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 懒时小窝 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Source
  • -------------- GPT 翻译 --------------
  • JSON Web Encryption(JWE)解释
  • JWE是什么
    • 序列化格式
      • JWE Compact Serialization
      • JWE JSON序列化
  • JOSE头
  • JWE生成步骤
    • ① CEK生成
      • alg 参数值和密钥管理模式
    • ② 内容加密
      • 3.创建 JWE 令牌
      • 实现
      • JWE的批评
      • 总结
      • -------------- 原文 --------------
      • JSON Web Encryption (JWE) の解説
      • JWE とは
        • シリアライゼーション形式
          • JWE Compact Serialization
          • JWE JSON Serialization
      • JOSEヘッダ
      • JWE生成の手順
        • ① CEK生成
          • alg パラメータ値と鍵管理モード
        • ② コンテンツ暗号化
          • 3. JWE トークンを構築する
          • 実装
          • JWEへの批判
          • まとめ
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档