[译]Dart 强大的加密解密库 pointycastle

1,938 阅读7分钟

原文:pointycastle | Dart Package (pub.dev)

译时版本:3.6.2


Pointy Castle

加密解密的 Dart 库。 该发布版中,大部分类是 Bouncy Castle 的 Java 移植到了 Dart 中。 几乎都直接移植的,除了一些为了便于使用低级数据而添加的类。

为了保证不会有任何失败,对于每个算法都提供了测试和性能指标。 预期结果取自 Bouncy Castle 的 Java 版本和标准,并与 Pointy Castle 的结果相匹配。

该库是根据作者的请求,采用了github.com/PointyCastl… 的原始工程,以帮助支持正在进行中的开发。 主要贡献者的列表在 contributors.md 提供。

该库现在的移植是默认不可空,这是 Dart 团队发布的一个破坏性语言特性! 参考 dart.cn/null-safety 和 dart.cn/null-safety… 了解更多详情。 请注意 空安全和非空安全都可用(v3.x.x-nullsafety 为空安全, v2.x.x 为非空安全)。 尽管如此,该库只有空安全的版本会持续维护。

算法

Pointycastle 实现了大量的算法。
它们必须使用参数进行实例化和初始化。
不同的算法有不同的参数类,它们代表着对应算法。
相关的参数类型会提供给自有的算法。
要初始化一个算法,需要调用初始化方法:

var algorithmVar = /* 在这里使用注册实例化算法 */ ;
var parameter = /* 在这里实例化相关参数类 */ ;
algorithmVar.init(parameter);

一些算法会在初始化步骤需要多于一个的参数对象。
一旦在工程中指定了想要使用的类,建议参考 pub.flutter-io.cn/documentati… 的文档来查找对应类的方法的使用说明。

在该发布版中,下面的算法会被实现:

(下面的绝大多数都是算法的关键字,可以直接用来注册。在 PointyCastle 中注册是一个实例化类的简单方式。参考 "使用注册" 了解更多)。

AEAD 密文:  要使用该注册,可用 AEADCipher('ChaCha20-Poly1305') 的方式实例化。 Cipher 使用 AEADParameters 初始化。

  • 'ChaCha20-Poly1305'

块密文:  要使用该注册,可用  PaddedBlockCipher('AES/SomeBlockModeHere/SomePaddingHere') 或 StreamCipher('AES/SomeStreamModeHere') 的方式注册。参考下面的部分设置模式和补齐。

  • 'AES'
  • 注意块密文可用于流处理的密文模式

块处理模式:  大多数模式使用 ParametersWithIV 初始化。ECB 使用 KeyParameter , GCM 使用 AEADParameters

  • 'CBC' (密文分组链接)

  • 'ECB' (电子密码本模式)

  • 'CFB-64' (密码反馈模式,使用块)

  • 'GCTR' (GOST 28147 OFB 计数器模式,使用块)

  • 'OFB-64' (输出反馈模式,使用块)

  • 'CTR'/'SIC' (计数器模式,使用块)

  • 'IGE' (无限乱码扩展)

  • 授权的块处理模式

    • 'GCM' (伽罗瓦计数器模式)
    • 'CCM' (使用CBC-MAC的计数器)

流处理模式: 所有模式使用 ParametersWithIV 来初始化。

  • 'CTR'/'SIC' (计数器模式,作为一个传统的流)

补齐:

  • 'PKCS7'
  • 'ISO7816-4'

非对称块密文:  使用 AsymmetricBlockCipher('RSA/SomeEncodingHere') 的注册方式实例化。初始化需要一个 RSAPrivateKey 或 RSAPublicKey` 。

  • 'RSA'

非对称块密文编码:

  • 'PKCS1'
  • 'OAEP'

流密文:  使用 StreamCipher('ChaCha20/20') 的注册方式实例化。初始化需要一个 ParametersWithIV

  • 'Salsa20'
  • 'ChaCha20/(# / 回合)' (原始实现)
  • 'ChaCha7539/(# / 回合)' (RFC-7539实现)
  • 如果不知道使用ChaCha的多少回合,使用20。

Digest:  使用 Digest('Keccak/384') 的注册方式实例化。不需要初始化。

  • 'Blake2b'
  • 'MD2'
  • 'MD4'
  • 'MD5'
  • 'RIPEMD-128|160|256|320'
  • 'SHA-1'
  • 'SHA-224|256|384|512'
  • 'SHA-512/t' (t=8 到 376 和 392 到 504 中的 8 的倍数)
  • 'Keccak/224|256|384|512'
  • 'SHA3-224|256|384|512'
  • 'Tiger'
  • 'Whirlpool'
  • 'SM3'

MAC:  使用 Mac('SomeBlockCipher/CMAC') 或 Mac('SomeDigest/HMAC) 或 Mac(SomeBlockCipher/Poly1305) 的注册方式初始化。 CMAC 和 HMAC 需要一个 KeyParameter ,Poly1305 需要一个 ParametersWithIV

  • 'HMAC'
  • 'CMAC'
  • 'Poly1305'

签名:  使用 Signer('SomeDigestHere/(DET-)ECDSA') 或 Signer('SomeDigestHere/RSA') 的注册方式实例化

  • '(DET-)ECDSA'
  • 'RSA'

基于密码的衍生键:  使用 KeyDerivator('SomeDigestHere/HMAC/PBKDF2') 或 KeyDerivator('scrypt/argon2') 的注册方式实例化。初始化需要一个 Pbkdf2Parameters、 ScryptParameters、或 Argon2Parameters

  • 'PBKDF2'
  • 'scrypt'
  • 'argon2'

基于 HMAC 的衍生键:  使用 KeyDerivator('SomeDigestHere/HKDF') 的注册方式实例化。初始化需要使用一个 HkdfParameters

  • 'HKDF'

非对称键生成器 使用 KeyDerivator('RSA') 的注册方式实例化。要初始化,使用 ECKeyGeneratorParameters 或 RSAKeyGeneratorParameters

  • 'ECDSA'
  • 'RSA'

安全 PRNG :

  • CTR 模式下基于块密文
  • CTR 模式下基于块密码,带自动再播种(用于更高阶的安全)
  • 基于 Fortuna 算法

实例化实现的对象

有两个方式可以实例化实现算法的对象:

  • 使用注册,或
  • 不使用注册

使用注册

使用注册,算法名会提供给高级的类工厂。

当算法涉及要实现多个算法实现类时特别方便。 所有必须的类都能用单个名称实例化(例,"SHA-256/HMAC" 或 "SHA-1/HMAC/PBKDF2" 或 "AES/CBC/PKCS7"),然后它们会自动和正确的值绑定在一起。

示例,

final sha256 = Digest("SHA-256");
final sha1 = Digest("SHA-1");
final md5 = Digest("MD5");

final hmacSha256 = Mac("SHA-256/HMAC");
final hmacSha1 = Mac("SHA-1/HMAC");
final hmacMd5 = Mac("MD5/HMAC");

final derivator = KeyDerivator("SHA-1/HMAC/PBKDF2");

final signer = Signer("SHA-256/RSA");

不使用注册

不使用注册时,每个实现类必须使用它的构造函数实例化。

如果一个算法涉及多个算法实现类,它们必须各自实例化并和正确的值绑定在一起。

示例,

final sha256 = SHA256Digest();
final sha1 = SHA1Digest();
final md5 = MD5Digest();

final hmacSha256 = HMac(SHA256Digest(), 64);
final hmacSha512 = HMac(SHA512Digest(), 128);
final hmacMd5 = HMac(MD5Digest(), 64);

final derivator = PBKDF2KeyDerivator(HMac(SHA256Digest(), 64));

final signer = RSASigner(SHA256Digest(), '0609608648016503040201');

使用注册 vs 不使用注册

使用注册意味着所有的算法会默认导入,这会增加编译后程序的大小。

要避免这一点,可使用构造函数直接实例化所有类。 但是哪个类会在它的构造函数中会被实例化取决于已经导入了哪个库。

导入库

程序可通过下面三个途径其中之一导入 Point Castle 库:

  • 只导入 pointycastle.dart;
  • 只导入 exports.dart; 或
  • 导入 api.dart 和所需的单独库。

只导入 pointycastle.dart

"pointycastle.dart" 文件导出:

  • 高级 API ;和
  • 接口的实现。

但是这不会导出任何算法的实现类。

import "package:pointycastle/pointycastle.dart";

使用该导入, 不会有 任何实现类会被直接实例化。程序只使用注册。

示例,

final sha256 = Digest("SHA-256");
// final md5 = MD5Digest(); // 不可用
final p = Padding("PKCS7");
// final s = FortunaRandom(); // 不可用

只导入 exports.dart

"export.dart" 文件导出:

  • 高级 API,
  • 接口的实现;和
  • 每个算法实现类。

也就是,所有!

import "package:pointycastle/export.dart";

使用该导入,所有的实现类会被直接实例化。程序也会使用注册。

例如,不带任何附加的导入也能正常运行:

final sha256 = Digest("SHA-256");
final md5 = MD5Digest();
final p = Padding("PKCS7");
final s = FortunaRandom();

导入 api.dart 和各自的库

"api.dart" 只导出:

  • 高级API

它不包含任何接口的实现,也不包含任何算法实现类。

import "package:pointycastle/api.dart";
// 需要额外的导入

使用该导入,只有 一些 实现类能被直接实例化(例,明确导入的那些)。程序也会使用注册。

例如,由于附加的导入,下面的代码也能正常运行:

// 作为 "package:pointycastle/api.dart" 的补充:
import "package:pointycastle/digests/sha256.dart";
import "package:pointycastle/digests/md5.dart"
import 'package:pointycastle/paddings/pkcs7.dart';

final sha256 = Digest("SHA-256");
final md5 = MD5Digest();
final p = Padding("PKCS7");
// final s = FortunaRandom(); // 没有 'package:pointycastle/random/fortuna_random.dart' 的话,是不可用的。

指南

可以在代码的 tutorials 目录中找到一些关于如何使用 Pointy Castle 特性的文章。

  • 计算 digest - 计算哈希或 digest (例 SHA-256、 SHA-1、 MD5)
  • 计算 HMAC - 计算基于哈希的消息授权码 (例 HMAC-SHA256、 HMAC-SHA1)
  • 使用 AES-CBC - 使用AES-CBC进行块加密和块解密
  • 使用 RSA - 键生成、签名/验证、和加密/解密
  • 使用 Pointy Castle 的一些 技巧

*注意:上面的链接是GitHub上master分支的最新版本。可能和 pub.flutter-io.cn 上的版本不同。 *