Flutter加密解密插件jose2的使用

发布于 1周前 作者 eggper 来自 Flutter

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进行加密和解密操作。

回到顶部