Flutter加密解密插件jose2的使用

Flutter 加密解密插件 jose2 的使用

本指南将详细介绍如何在 Flutter 中使用 jose2 插件进行 JSON Web 签名(JWS)、JSON Web 加密(JWE)、JSON Web 密钥(JWK)和 JSON Web 令牌(JWT)的操作。

支持的 JSON Web 算法

该库支持标准定义中的许多算法。

签名算法(用于 JWS)

  • HS256 HMAC 使用 SHA-256
  • HS384 HMAC 使用 SHA-384
  • HS512 HMAC 使用 SHA-512
  • RS256 RSASSA-PKCS1-v1_5 使用 SHA-256
  • RS384 RSASSA-PKCS1-v1_5 使用 SHA-384
  • RS512 RSASSA-PKCS1-v1_5 使用 SHA-512
  • ES256 ECDSA 使用 P-256 和 SHA-256
  • ES256K ECDSA 使用 P-256K 和 SHA-256
  • ES384 ECDSA 使用 P-384 和 SHA-384
  • ES512 ECDSA 使用 P-521 和 SHA-512
  • none 无数字签名或 MAC

密钥包装算法(用于 JWE)

  • RSA1_5 RSAES-PKCS1-v1_5
  • RSA-OAEP RSAES OAEP 使用默认参数
  • RSA-OAEP-256 RSAES OAEP 使用 SHA-256 和 MGF1 使用 SHA-256
  • A128KW AES 密钥包装使用 128 位密钥
  • A192KW AES 密钥包装使用 192 位密钥
  • A256KW AES 密钥包装使用 256 位密钥
  • dir 直接使用共享对称密钥作为 CEK

加密算法(用于 JWE)

  • A128CBC-HS256 AES_128_CBC_HMAC_SHA_256 身份验证加密算法
  • A192CBC-HS384 AES_192_CBC_HMAC_SHA_384 身份验证加密算法
  • A256CBC-HS512 AES_256_CBC_HMAC_SHA_512 身份验证加密算法
  • A128GCM AES GCM 使用 128 位密钥
  • A192GCM AES GCM 使用 192 位密钥
  • A256GCM AES GCM 使用 256 位密钥

使用方法

解码并验证 JWS

main() async {
  var encoded = "eyJhbGciOiJFUzUxMiJ9."
    "UGF5bG9hZA."
    "AdwMgeerwtHoh-l192l60hp9wAHZFVJbLfD_UxMi70cwnZOYaRI1bKPWROc-mZZq"
    "wqT2SI-KGDKB34XO0aw_7XdtAG8GaSwFKdCAPZgoXD2YBJZCPEX3xKpRwcdOO8Kp"
    "EHwJjyqOgzDO7iKvU8vcnwNrmxYbSW9ERBXukOXolLzeO_Jn";
  
  // 从编码字符串创建 JsonWebSignature
  var jws = JsonWebSignature.fromCompactSerialization(encoded);
  
  // 提取载荷
  var payload = jws.unverifiedPayload;
  
  print("内容为: ${payload.stringContent}");
  print("保护参数: ${payload.protectedHeader.toJson()}");
  
  // 创建 JsonWebKey 以验证签名
  var jwk = new JsonWebKey.fromJson({
      "kty": "EC",
      "crv": "P-521",
      "x": "AekpBQ8ST8a8VcfVOTNl353vSrDCLLJXmPk06wTjxrrjcBpXp5EOnYG_"
          "NjFZ6OvLFV1jSfS9tsz4qUxcWceqwQGk",
      "y": "ADSmRA43Z1DSNx_RvcLI87cdL07l6jQyyBXMoxVg_l2Th-x3S1WDhjDl"
          "y79ajL4Kkd0AZMaZmh9ubmf63e3kyMj2",
      "d": "AY5pb7A0UFiB3RELSD64fTLOSV_jazdF7fLYyuTw8lOfRhWg6Y6rUrPA"
          "xerEzgdRhajnu0ferB0d53vM9mE15j2C"
  });
  var keyStore = new JsonWebKeyStore()..addKey(jwk);
  
  // 验证签名
  var verified = await jws.verify(keyStore);
  print("签名验证结果: $verified");
}

创建 JWS

main() async {
  // 创建一个 builder
  var builder = new JsonWebSignatureBuilder();

  // 设置内容
  builder.stringContent = "It is me";

  // 设置一些保护头
  builder.setProtectedHeader("createdAt", new DateTime.now().toIso8601String());

  // 添加一个用于签名的密钥,可以添加多个密钥以供不同接收者使用
  builder.addRecipient(
      new JsonWebKey.fromJson({
        "kty": "oct",
        "k":
            "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
      }),
      algorithm: "HS256");

  // 构建 JWS
  var jws = builder.build();

  // 输出紧凑序列化
  print("JWS 紧凑序列化: ${jws.toCompactSerialization()}");

  // 输出 JSON 序列化
  print("JWS JSON 序列化: ${jws.toJson()}");
}

解码并解密 JWE

main() async {
  var encoded = "eyJhbGciOiJSU0ExXzUiLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0."
      "UGhIOguC7IuEvf_NPVaXsGMoLOmwvc1GyqlIKOK1nN94nHPoltGRhWhw7Zx0-kFm"
      "1NJn8LE9XShH59_i8J0PH5ZZyNfGy2xGdULU7sHNF6Gp2vPLgNZ__deLKxGHZ7Pc"
      "HALUzoOegEI-8E66jX2E4zyJKx-YxzZIItRzC5hlRirb6Y5Cl_p-ko3YvkkysZIF"
      "NPccxRU7qve1WYPxqbb2Yw8kZqa2rMWI5ng8OtvzlV7elprCbuPhcCdZ6XDP0_F8"
      "rkXds2vE4X-ncOIM8hAYHHi29NX0mcKiRaD0-D-ljQTP-cFPgwCp6X-nZZd9OHBv"
      "-B3oWh2TbqmScqXMR4gp_A."
      "AxY8DCtDaGlsbGljb3RoZQ."
      "KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY."
      "9hH0vgRfYgPnAHOd8stkvw";

  // 从编码字符串创建 JsonWebEncryption
  var jwe = JsonWebEncryption.fromCompactSerialization(encoded);

  // 创建用于解密签名的 JsonWebKey
  var jwk = new JsonWebKey.fromJson(
    {
      "kty": "RSA",
      "n": "sXchDaQebHnPiGvyDOAT4saGEUetSyo9MKLOoWFsueri23bOdgWp4Dy1Wl"
          "UzewbgBHod5pcM9H95GQRV3JDXboIRROSBigeC5yjU1hGzHHyXss8UDpre"
          "cbAYxknTcQkhslANGRUZmdTOQ5qTRsLAt6BTYuyvVRdhS8exSZEy_c4gs_"
          "7svlJJQ4H9_NxsiIoLwAEk7-Q3UXERGYw_75IDrGA84-lA_-Ct4eTlXHBI"
          "Y2EaV7t7LjJaynVJCpkv4LKjTTAumiGUIuQhrNhZLuF_RJLqHpM2kgWFLU"
          "7-VTdL1VbC2tejvcI2BlMkEpk1BzBZI0KQB0GaDWFLN-aEAw3vRw",
      "e": "AQAB",
      "d": "VFCWOqXr8nvZNyaaJLXdnNPXZKRaWCjkU5Q2egQQpTBMwhprMzWzpR8Sxq"
          "1OPThh_J6MUD8Z35wky9b8eEO0pwNS8xlh1lOFRRBoNqDIKVOku0aZb-ry"
          "nq8cxjDTLZQ6Fz7jSjR1Klop-YKaUHc9GsEofQqYruPhzSA-QgajZGPbE_"
          "0ZaVDJHfyd7UUBUKunFMScbflYAAOYJqVIVwaYR5zWEEceUjNnTNo_CVSj"
          "-VvXLO5VZfCUAVLgW4dpf1SrtZjSt34YLsRarSb127reG_DUwg9Ch-Kyvj"
          "T1SkHgUWRVGcyly7uvVGRSDwsXypdrNinPA4jlhoNdizK2zF2CWQ",
      "p": "9gY2w6I6S6L0juEKsbeDAwpd9WMfgqFoeA9vEyEUuk4kLwBKcoe1x4HG68"
          "ik918hdDSE9vDQSccA3xXHOAFOPJ8R9EeIAbTi1VwBYnbTp87X-xcPWlEP"
          "krdoUKW60tgs1aNd_Nnc9LEVVPMS390zbFxt8TN_biaBgelNgbC95sM",
      "q": "uKlCKvKv_ZJMVcdIs5vVSU_6cPtYI1ljWytExV_skstvRSNi9r66jdd9-y"
          "BhVfuG4shsp2j7rGnIio901RBeHo6TPKWVVykPu1iYhQXw1jIABfw-MVsN"
          "-3bQ76WLdt2SDxsHs7q7zPyUyHXmps7ycZ5c72wGkUwNOjYelmkiNS0",
      "dp": "w0kZbV63cVRvVX6yk3C8cMxo2qCM4Y8nsq1lmMSYhG4EcL6FWbX5h9yuv"
          "ngs4iLEFk6eALoUS4vIWEwcL4txw9LsWH_zKI-hwoReoP77cOdSL4AVcra"
          "Hawlkpyd2TWjE5evgbhWtOxnZee3cXJBkAi64Ik6jZxbvk-RR3pEhnCs",
      "dq": "o_8V14SezckO6CNLKs_btPdFiO9_kC1DsuUTd2LAfIIVeMZ7jn1Gus_Ff"
          "7B7IVx3p5KuBGOVF8L-qifLb6nQnLysgHDh132NDioZkhH7mI7hPG-PYE_"
          "odApKdnqECHWw0J-F0JWnUd6D2B_1TvF9mXA2Qx-iGYn8OVV1Bsmp6qU",
      "qi": "eNho5yRBEBxhGBtQRww9QirZsB66TrfFReG_CcteI1aCneT0ELGhYlRlC"
          "tUkTRclIfuEPmNsNDPbLoLqqCVznFbvdB7x-Tl-m0l_eFTj2KiqwGqE9PZ"
          "B9nNTwMVvH3VRRSLWACvPnSiwP8N5Usy-WRXS-V7TbpxIhvepTfE0NNo"
    },
  );
  var keyStore = new JsonWebKeyStore()..addKey(jwk);

  // 解密载荷
  var payload = await jwe.getPayload(keyStore);
  print("解密后的内容: ${payload.stringContent}");
}

创建 JWE

main() async {
  // 创建一个 builder
  var builder = new JsonWebEncryptionBuilder();

  // 设置内容
  builder.stringContent = "这是我的最大秘密";

  // 设置一些保护头
  builder.setProtectedHeader("createdAt", new DateTime.now().toIso8601String());

  // 添加一个用于加密内容加密密钥的密钥
  var jwk = new JsonWebKey.fromJson(
    {
      "kty": "RSA",
      "n": "sXchDaQebHnPiGvyDOAT4saGEUetSyo9MKLOoWFsueri23bOdgWp4Dy1Wl"
          "UzewbgBHod5pcM9H95GQRV3JDXboIRROSBigeC5yjU1hGzHHyXss8UDpre"
          "cbAYxknTcQkhslANGRUZmdTOQ5qTRsLAt6BTYuyvVRdhS8exSZEy_c4gs_"
          "7svlJJQ4H9_NxsiIoLwAEk7-Q3UXERGYw_75IDrGA84-lA_-Ct4eTlXHBI"
          "Y2EaV7t7LjJaynVJCpkv4LKjTTAumiGUIuQhrNhZLuF_RJLqHpM2kgWFLU"
          "7-VTdL1VbC2tejvcI2BlMkEpk1BzBZI0KQB0GaDWFLN-aEAw3vRw",
      "e": "AQAB",
      "d": "VFCWOqXr8nvZNyaaJLXdnNPXZKRaWCjkU5Q2egQQpTBMwhprMzWzpR8Sxq"
          "1OPThh_J6MUD8Z35wky9b8eEO0pwNS8xlh1lOFRRBoNqDIKVOku0aZb-ry"
          "nq8cxjDTLZQ6Fz7jSjR1Klop-YKaUHc9GsEofQqYruPhzSA-QgajZGPbE_"
          "0ZaVDJHfyd7UUBUKunFMScbflYAAOYJqVIVwaYR5zWEEceUjNnTNo_CVSj"
          "-VvXLO5VZfCUAVLgW4dpf1SrtZjSt34YLsRarSb127reG_DUwg9Ch-Kyvj"
          "T1SkHgUWRVGcyly7uvVGRSDwsXypdrNinPA4jlhoNdizK2zF2CWQ",
      "p": "9gY2w6I6S6L0juEKsbeDAwpd9WMfgqFoeA9vEyEUuk4kLwBKcoe1x4HG68"
          "ik918hdDSE9vDQSccA3xXHOAFOPJ8R9EeIAbTi1VwBYnbTp87X-xcPWlEP"
          "krdoUKW60tgs1aNd_Nnc9LEVVPMS390zbFxt8TN_biaBgelNgbC95sM",
      "q": "uKlCKvKv_ZJMVcdIs5vVSU_6cPtYI1ljWytExV_skstvRSNi9r66jdd9-y"
          "BhVfuG4shsp2j7rGnIio901RBeHo6TPKWVVykPu1iYhQXw1jIABfw-MVsN"
          "-3bQ76WLdt2SDxsHs7q7zPyUyHXmps7ycZ5c72wGkUwNOjYelmkiNS0",
      "dp": "w0kZbV63cVRvVX6yk3C8cMxo2qCM4Y8nsq1lmMSYhG4EcL6FWbX5h9yuv"
          "ngs4iLEFk6eALoUS4vIWEwcL4txw9LsWH_zKI-hwoReoP77cOdSL4AVcra"
          "Hawlkpyd2TWjE5evgbhWtOxnZee3cXJBkAi64Ik6jZxbvk-RR3pEhnCs",
      "dq": "o_8V14SezckO6CNLKs_btPdFiO9_kC1DsuUTd2LAfIIVeMZ7jn1Gus_Ff"
          "7B7IVx3p5KuBGOVF8L-qifLb6nQnLysgHDh132NDioZkhH7mI7hPG-PYE_"
          "odApKdnqECHWw0J-F0JWnUd6D2B_1TvF9mXA2Qx-iGYn8OVV1Bsmp6qU",
      "qi": "eNho5yRBEBxhGBtQRww9QirZsB66TrfFReG_CcteI1aCneT0ELGhYlRlC"
          "tUkTRclIfuEPmNsNDPbLoLqqCVznFbvdB7x-Tl-m0l_eFTj2KiqwGqE9PZ"
          "B9nNTwMVvH3VRRSLWACvPnSiwP8N5Usy-WRXS-V7TbpxIhvepTfE0NNo"
    },
  );
  builder.addRecipient(jwk, algorithm: "RSA1_5");

  // 设置要使用的内容加密算法
  builder.encryptionAlgorithm = "A128CBC-HS256";

  // 构建 JWE
  var jwe = builder.build();

  // 输出紧凑序列化
  print("JWE 紧凑序列化: ${jwe.toCompactSerialization()}");

  // 输出 JSON 序列化
  print("JWE JSON 序列化: ${jwe.toJson()}");
}

解码、验证和验证 JWT

main() async {
  var encoded = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9."
      "eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt"
      "cGxlLmNvbS9pc19yb290Ijp0cnVlfQ."
      "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk";

  // 解码 JWT,注意:此构造函数只能用于 JWS 结构内的 JWT
  var jwt = new JsonWebToken.unverified(encoded);

  // 输出声明
  print("声明: ${jwt.claims}");

  // 创建 Key Store 以验证签名
  var keyStore = new JsonWebKeyStore()
    ..addKey(new JsonWebKey.fromJson({
      "kty": "oct",
      "k":
          "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
    }));

  var verified = await jwt.verify(keyStore);
  print("验证结果: $verified");

  // 另外,一起创建并验证 JsonWebToken,这同样适用于 JWE 内的 JWT
  jwt = await JsonWebToken.decodeAndVerify(encoded, keyStore);

  // 验证声明
  var violations = jwt.claims.validate(issuer: Uri.parse("alice"));
  print("违反: $violations");
}

创建 JWT

main() async {
  var claims = new JsonWebTokenClaims.fromJson({
    "exp": new Duration(hours: 4).inSeconds,
    "iss": "alice",
  });

  // 创建一个 builder,解码 JWT 在 JWS 中,所以使用 JsonWebSignatureBuilder
  var builder = new JsonWebSignatureBuilder();

  // 设置内容
  builder.jsonContent = claims.toJson();

  // 添加一个用于签名的密钥,只能添加一个用于 JWT
  builder.addRecipient(
      new JsonWebKey.fromJson({
        "kty": "oct",
        "k":
            "AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
      }),
      algorithm: "HS256");

  // 构建 JWS
  var jws = builder.build();

  // 输出紧凑序列化
  print("JWT 紧凑序列化: ${jws.toCompactSerialization()}");
}

更多关于Flutter加密解密插件jose2的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter加密解密插件jose2的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用jose2插件进行加密和解密的示例代码。jose2是一个用于处理JSON Web Tokens (JWT)、JSON Web Encryption (JWE) 和 JSON Web Signatures (JWS) 的Flutter插件。

首先,确保你已经在pubspec.yaml文件中添加了jose2依赖:

dependencies:
  flutter:
    sdk: flutter
  jose2: ^0.5.0  # 请检查最新版本号并替换

然后运行flutter pub get来安装依赖。

接下来,下面是一个示例代码,展示如何使用jose2进行加密和解密操作。这个示例假设你使用对称密钥(例如AES)进行加密和解密。

import 'package:flutter/material.dart';
import 'package:jose2/jose2.dart';
import 'dart:typed_data';
import 'dart:convert';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String? decryptedMessage;

  @override
  void initState() {
    super.initState();
    _performEncryptionAndDecryption();
  }

  Future<void> _performEncryptionAndDecryption() async {
    // 对称密钥(请确保在实际应用中安全存储密钥)
    final Uint8List key = Uint8List.fromList(List.generate(32, (i) => i % 256));

    // 要加密的消息
    final String plainTextMessage = "Hello, Flutter and JOSE!";
    final Uint8List plainTextBytes = Uint8List.fromList(utf8.encode(plainTextMessage));

    // 创建JWE加密器
    final jweEncryptor = JweEncryptor(
      alg: 'dir',
      enc: 'A256GCM',
      key: key,
    );

    // 加密消息
    final jweEncrypted = await jweEncryptor.encrypt(plainTextBytes);
    print("Encrypted message: ${base64Url.encode(jweEncrypted)}");

    // 创建JWE解密器
    final jweDecryptor = JweDecryptor(
      alg: 'dir',
      enc: 'A256GCM',
      key: key,
    );

    // 解密消息
    final jweDecryptedBytes = await jweDecryptor.decrypt(jweEncrypted);
    final decryptedMessage = utf8.decode(jweDecryptedBytes);

    // 更新UI
    setState(() {
      this.decryptedMessage = decryptedMessage;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('JOSE2 Encryption/Decryption Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                decryptedMessage ?? 'Decrypting...',
                style: TextStyle(fontSize: 24),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

代码说明:

  1. 依赖导入:导入jose2和其他必要的包。
  2. 密钥生成:生成一个32字节的对称密钥(AES-256需要32字节的密钥)。在实际应用中,密钥应该从安全存储中加载。
  3. 消息加密:将要加密的消息转换为字节数组,然后使用JweEncryptor进行加密。
  4. 消息解密:使用JweDecryptor对加密后的消息进行解密,并将结果转换回字符串。
  5. UI更新:在Flutter UI中显示解密后的消息。

注意事项:

  • 密钥管理:在实际应用中,密钥管理非常重要。密钥应存储在安全的地方,例如Android的KeyStore或iOS的Keychain。
  • 异常处理:在实际应用中,应添加异常处理来捕获并处理加密和解密过程中可能发生的错误。
  • 最新版本:确保使用jose2插件的最新版本,并查阅其文档以获取最新的API和用法。

希望这个示例能帮助你在Flutter项目中使用jose2进行加密和解密操作。

回到顶部