- 文档
- 知识库
- 教程
- OpenHarmony
【免费下载链接】CangjieCorpus
本仓库为仓颉编程语言语料库,聚焦 仓颉编程语言 核心知识体系,整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源,经结构化处理与专业标注,构建为支持 RAG(检索增强生成)技术 的高质量知识基座,适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用,推动鸿蒙开发生态智能化升级!
导读
本文以仓颉标准扩展库stdx.crypto.keys中的两个核心枚举——Curve(ECDSA 椭圆曲线选择)与PadOption(RSA 填充模式)为主线,完整讲解每个枚举值的语义、适用场景与安全取舍,并串联OAEPOption、PSSOption参数结构体及密钥类方法,最终通过可运行的仓颉代码示例演示如何在实际项目中选择曲线与填充模式完成密钥生成、加解密与签名验证。读完本文,你将能准确为 ECDSA/RSA/SM2 场景选择枚举参数,并规避 RSA PKCS1 v1.5 填充的历史安全风险。
一、枚举在 keys 包中的定位
stdx.crypto.keys包提供非对称加密与签名算法能力,覆盖RSA、SM2非对称加密算法以及ECDSA签名算法(见 keys_package_overview.md)。该包公开了 6 个密钥类(ECDSAPrivateKey、ECDSAPublicKey、RSAPrivateKey、RSAPublicKey、SM2PrivateKey、SM2PublicKey)、2 个枚举和 2 个参数结构体:
| 类别 | 名称 | 功能 |
|---|---|---|
| 枚举 | Curve | 选择生成 ECDSA 密钥时使用的椭圆曲线类型 |
| 枚举 | PadOption | 设置 RSA 的填充模式 |
| 结构体 | OAEPOption | 最优非对称加密填充(OAEP)所需参数 |
| 结构体 | PSSOption | 概率签名方案(PSS)所需参数 |
其中Curve直接作为ECDSAPrivateKey构造函数的入参决定密钥安全强度,PadOption则贯穿 RSA 密钥的加解密与签名验证方法(encrypt、decrypt、sign、verify),是整个非对称加密体系中"选型"层面的两个关键开关。
依赖前提:使用本包需要外部依赖 OpenSSL 3 的 crypto 动态库文件,且相关类在初始化、编解码、加解密失败时会抛出 CryptoException。
二、Curve 枚举:为 ECDSA 密钥选择椭圆曲线
2.1 枚举定义
Curve是仓颉中的枚举类型,用于选择生成 ECDSA 密钥时使用的椭圆曲线:
public enum Curve { | P224 | P256 | P384 | P521 | BP256 | BP320 | BP384 | BP512 }椭圆曲线密码学(ECC)的基本思想是利用椭圆曲线上点集构成的"计算困难性"(即椭圆曲线离散对数问题)来实现公钥密码的安全性。与 RSA 相比,ECC 可以在更短的密钥长度下提供相当的安全强度。Curve枚举覆盖了两个主流标准家族共 8 种曲线:
- NIST 系列:P-224、P-256、P-384、P-521(对应 FIPS 186 中定义的 NIST 素数域曲线);
- Brainpool 系列:P-256、P-320、P-384、P-512(对应 RFC 5639 定义的 Brainpool 曲线)。
2.2 枚举值对照表
| 枚举值 | 曲线标准 | 模数位数 | 定位与特点 |
|---|---|---|---|
P224 | NIST P-224 | 224 位 | 安全性较高,适用于轻量级应用 |
P256 | NIST P-256 | 256 位 | 安全性较高,适用于中等级应用 |
P384 | NIST P-384 | 384 位 | 安全性非常高,适用于高级别应用 |
P521 | NIST P-521 | 521 位 | 安全性非常高,适用于极高级别应用 |
BP256 | Brainpool P-256 | 256 位 | 安全性较高,但比 NIST P-256 更快 |
BP320 | Brainpool P-320 | 320 位 | 安全性非常高,但比 NIST P-384 更快 |
BP384 | Brainpool P-384 | 384 位 | 安全性非常高,但比 NIST P-384 更快 |
BP512 | Brainpool P-512 | 512 位 | 安全性非常高,但比 NIST P-521 更快 |
2.3 枚举值逐个说明
每个枚举值都用于以对应曲线初始化Curve实例:
BP256:使用 Brainpool P-256 椭圆曲线初始化Curve实例;BP320:使用 Brainpool P-320 椭圆曲线初始化Curve实例;BP384:使用 Brainpool P-384 椭圆曲线初始化Curve实例;BP512:使用 Brainpool P-512 椭圆曲线初始化Curve实例;P224:使用 NIST P-224 椭圆曲线初始化Curve实例;P256:使用 NIST P-256 椭圆曲线初始化Curve实例;P384:使用 NIST P-384 椭圆曲线初始化Curve实例;P521:使用 NIST P-521 椭圆曲线初始化Curve实例。
选型建议:曲线位数越高,安全强度越高,但密钥生成与签名计算的代价也越大。轻量级/嵌入式或对性能敏感的场景可选择P224/P256等较短曲线;涉及高价值数据或长期有效密钥的场景,应优先选择P384、P521或BP512等更长曲线。Brainpool 系列在同等安全级别下提供了速度优势,适合对签名吞吐有要求的场景。
2.4 在 ECDSA 密钥生成中的实际用法
Curve直接传入ECDSAPrivateKey的构造函数以生成对应曲线的私钥,再通过私钥派生公钥:
// 使用 NIST P-224 曲线生成 ECDSA 私钥 var ecPri = ECDSAPrivateKey(P224) var ecPub = ECDSAPublicKey(ecPri)其中ECDSAPrivateKey的构造函数签名为public init(curve: Curve)(见 keys_package_classes.md),初始化失败时会抛出CryptoException。生成后,私钥支持签名操作,公钥支持验证签名操作,两者均支持 PEM 与 DER 格式的编码与解码,并且通过toString()输出密钥种类描述。
三、PadOption 枚举:RSA 填充模式
3.1 枚举定义
PadOption用于设置 RSA 的填充模式:
public enum PadOption { | OAEP(OAEPOption) | PSS(PSSOption) | PKCS1 }RSA 作为确定性很强的数学变换,直接对原始数据运算在安全上是不可接受的,因此必须配合填充模式使用。仓库文档明确给出三种常用填充模式的分工:
- OAEP(Optimal Asymmetric Encryption Padding,最优非对称加密填充):只能用于加密/解密;
- PSS(Probabilistic Signature Scheme,概率签名方案):只能用于签名和验证;
- PKCS1:一种普通的填充模式,用于填充数据长度,可以用于加密、解密、签名和验证。
3.2 枚举值逐个说明
OAEP(OAEPOption):使用最优非对称加密填充初始化PadOption实例,需携带 OAEPOption 参数(详见第四章);PSS(PSSOption):使用概率签名方案初始化PadOption实例,需携带 PSSOption 参数(详见第四章);PKCS1:使用 PKCS #1 公钥密码学标准初始化PadOption实例,不需要额外参数。
3.3 安全提示:为什么建议避免 PKCS1
RSA 的PKCS1填充模式对应早期 PKCS #1 v1.5 规范中定义的填充方式。仓库文档给出了明确的警示:当前对使用 PKCS1 填充模式的攻击较为成熟,容易被攻击者解密或伪造签名(如著名的 Bleichenbacher 攻击,可对使用 v1.5 填充的 RSA 加密实施自适应选择密文攻击)。因此建议采用 PKCS #1 v2 版本中更加安全的PSS(签名场景)或OAEP(加密场景)填充模式,仅在需要与旧系统互操作时才选用PKCS1。
3.4 填充模式与密钥方法的匹配约束
PadOption虽然是一个枚举,但并非所有模式都适用于所有 RSA 方法。结合 keys_package_classes.md 中RSAPrivateKey与RSAPublicKey的方法签名,可以归纳出严格的匹配关系:
| RSA 方法 | 所在类 | 可选 PadOption | 不支持的模式 | 推荐模式 |
|---|---|---|---|---|
encrypt(input, output, padType!) | RSAPublicKey | PKCS1、OAEP | PSS | OAEP |
decrypt(input, output, padType!) | RSAPrivateKey | PKCS1、OAEP | PSS | OAEP |
sign(hash, digest, padType!) | RSAPrivateKey | PKCS1、PSS | OAEP | PSS |
verify(hash, digest, sig, padType!) | RSAPublicKey | PKCS1、PSS | OAEP | PSS |
方法注释中明确:padType参数在加解密场景下"可以选择 PKCS1 或 OAEP 模式,不支持 PSS 模式,在对安全场景要求较高的情况下,推荐使用 OAEP 填充模式";在签名/验证场景下"可以选择 PKCS1 或 PSS 模式,不支持 OAEP 模式,在对安全场景要求较高的情况下,推荐使用 PSS 填充模式"。传入不支持的填充模式会因"设置填充模式失败"而抛出CryptoException。
四、OAEPOption 与 PSSOption:填充参数结构体
OAEP与PSS两个枚举值需要携带对应的参数结构体(见 keys_package_structs.md),理解这些参数是正确使用填充模式的关键。
4.1 OAEPOption
public struct OAEPOption { public init(hash: Digest, mgfHash: Digest, label!: String = "") }OAEP 填充参数包含三个字段:
| 参数 | 类型 | 含义 |
|---|---|---|
hash | Digest | 摘要方法,用于对label进行摘要 |
mgfHash | Digest | 摘要方法,用于设置 MGF1 掩码生成函数中的摘要方法 |
label! | String | 可选参数,默认为空字符串,可通过设置 label 区分不同的加密操作 |
其中Digest是stdx.crypto.digest包中的摘要算法接口,该包提供 MD5、SHA1、SHA224、SHA256、SHA384、SHA512、HMAC、SM3 等常用消息摘要算法(见 crypto_digest_package_overview.md)。hash与mgfHash可以选用不同的摘要算法,示例代码中即使用OAEPOption(SHA1(), SHA256()),即用 SHA1 对 label 做摘要、用 SHA256 作为 MGF1 内部摘要。
4.2 PSSOption
public struct PSSOption { public init(saltLen: Int32) }PSS 填充参数只包含一个字段saltLen(随机盐长度),其约束如下:
- 单位:字节;
- 取值范围:大于等于 0,小于等于(RSA 长度 - 摘要长度 - 2);
- 若
saltLen小于 0,抛出CryptoException; - 盐长度过长会导致签名失败(因为可用的随机盐空间不足)。
因此在实际使用时,需要根据 RSA 密钥长度与所选择摘要算法的输出长度综合计算合理的盐长。
五、实战示例:曲线与填充模式的选择与调用
以下示例均来自 sample_keys.md,展示了上述枚举在真实仓颉程序中的完整调用链。
5.1 ECDSA:P224 曲线生成密钥并签名验证
该示例演示Curve.P224的典型用法——生成 ECDSA 公私钥,用私钥对摘要签名、公钥验证:
import stdx.crypto.keys.* import stdx.crypto.digest.* import std.convert.* import std.crypto.digest.* main() { var ecPri = ECDSAPrivateKey(P224) var ecPub = ECDSAPublicKey(ecPri) var str: String = "helloworld" var sha512Instance = SHA512() sha512Instance.write(str.toArray()) var md: Array<Byte> = sha512Instance.finish() var sig = ecPri.sign(md) if (ecPub.verify(md, sig)) { println("verify successful") } }运行结果:
verify successful注意 ECDSA 的sign(digest)与verify(digest, sig)直接接收摘要字节数组,无需像 RSA 那样显式传入PadOption,因为 ECDSA 的签名方案由其曲线与摘要算法天然决定。
5.2 RSA:OAEP 填充模式加密与解密
该示例演示PadOption.OAEP(OAEPOption)在"公钥加密、私钥解密"流程中的用法,是安全场景下的推荐做法:
import stdx.crypto.keys.* import stdx.crypto.digest.* import std.io.* import std.crypto.digest.* main() { var rsaPri = RSAPrivateKey(2048) var rsaPub = RSAPublicKey(rsaPri) var str: String = "hello world, hello cangjie" var bas1 = ByteBuffer() var bas2 = ByteBuffer() var bas3 = ByteBuffer() bas1.write(str.toArray()) var encOpt = OAEPOption(SHA1(), SHA256()) rsaPub.encrypt(bas1, bas2, padType: OAEP(encOpt)) var encOpt2 = OAEPOption(SHA1(), SHA256()) rsaPri.decrypt(bas2, bas3, padType: OAEP(encOpt2)) var buf = Array<Byte>(str.size, repeat: 0) bas3.read(buf) if (str.toArray() == buf) { println("success") } else { println("fail") } }运行结果:
success该示例同时说明了RSAPrivateKey(2048)的构造方式:默认公钥指数为业界推荐的65537;也可通过init(bits, e)指定公钥指数e(范围为[3, 2^256-1]的奇数)。密钥长度bits需大于等于 512 且小于等于 16384 位,文档建议不小于 3072 位。
5.3 RSA:PKCS1 填充模式签名与验证(从文件导入密钥)
该示例演示PadOption.PKCS1在"私钥签名、公钥验证"流程中的用法,并展示通过decodeFromPem从 PEM 文件导入密钥的互操作场景:
import stdx.crypto.keys.* import stdx.crypto.digest.* import std.crypto.digest.* import std.fs.* import std.io.* main() { var pemPri = String.fromUtf8(readToEnd(File("./files/rsaPri.pem", Read))) var rsaPri = RSAPrivateKey.decodeFromPem(pemPri) var pemPub = String.fromUtf8(readToEnd(File("./files/rsaPub.pem", Read))) var rsaPub = RSAPublicKey.decodeFromPem(pemPub) var str: String = "helloworld" var sha512Instance = SHA512() sha512Instance.write(str.toArray()) var md: Array<Byte> = sha512Instance.finish() var sig = rsaPri.sign(sha512Instance, md, padType: PKCS1) if (rsaPub.verify(sha512Instance, md, sig, padType: PKCS1)) { println("verify successful") } }运行结果:
verify successful说明:该示例需要自行准备
rsaPri.pem、rsaPub.pem公私钥文件。PEM 与 DER 是两种常见的密钥编码格式:PEM 为 base64 编码的可打印文本(以-----BEGIN ...-----与-----END ...-----包裹),DER 为二进制格式。keys 包中的各类均支持encodeToPem()、encodeToDer()编码与decodeFromPem、decodeDer解码,其中私钥的带密码重载(如encodeToDer(password!: ?String))会使用 AES-256-CBC 加密私钥,密码传None时不加密。
5.4 SM2 补充说明
SM2也是 keys 包支持的非对称算法(国密算法),其私钥签名内部采用 SM3 摘要算法。SM2 密钥生成不涉及Curve(由算法固定),也不使用PadOption,其sign(data)与verify(data, sig)直接对原始数据操作,decrypt(input)要求待解密密文遵循 ASN.1 编码规则。使用示例见 sample_keys.md。
六、异常处理与运行环境
6.1 CryptoException
keys 包所有密码学操作(密钥初始化、编解码、加解密、签名验证、填充参数校验)失败时统一抛出CryptoException(定义于 digest_package_exceptions.md)。常见触发场景包括:
Curve/PadOption参数不合法或底层初始化失败;- PEM/DER 字符流格式错误或文件头不符合私钥/公钥头标准;
- 带密码解码时密码错误或密码为空字符串;
- PSS 的
saltLen小于 0,或盐长度过长导致签名失败; - RSA 方法使用了不支持的填充模式(如加密时传入
PSS、签名时传入OAEP)。
6.2 OpenSSL 3 依赖
stdx.crypto.keys底层依赖 OpenSSL 3 的 crypto 动态库,若未安装或版本过低,程序可能无法使用并抛出CryptoException:Can not load openssl library or function xxx。安装参考(详见 keys_package_overview.md):
- Linux:通过包管理工具安装 OpenSSL 3 开发包(如 Ubuntu 22.04 执行
sudo apt install libssl-dev),确保存在libcrypto.so与libcrypto.so.3;或源码编译安装后,将库目录加入LD_LIBRARY_PATH、LIBRARY_PATH; - Windows:安装 OpenSSL 3 x64 软件包,确保存在
libcrypto.dll.a(或libcrypto.lib)与libcrypto-3-x64.dll,前者所在目录加入LIBRARY_PATH,后者所在目录加入PATH; - macOS:
brew install openssl@3,确保存在libcrypto.dylib与libcrypto.3.dylib;自定义目录安装时将库目录加入DYLD_LIBRARY_PATH、LIBRARY_PATH。
七、小结
Curve与PadOption是仓颉stdx.crypto.keys包中决定非对称密码学"选型"的两个核心枚举:
Curve:8 个枚举值覆盖 NIST(P-224/256/384/521)与 Brainpool(BP256/320/384/512)两大曲线家族,直接决定 ECDSA 密钥的安全强度与性能,传入ECDSAPrivateKey(curve)即可完成密钥生成;PadOption:三种填充模式中,OAEP 专用于加密、PSS 专用于签名、PKCS1 通用但存在成熟攻击手段;安全场景下应优先选择 OAEP/PSS,OAEPOption与PSSOption为其提供哈希算法、MGF1 摘要、label 与随机盐长度等精细化配置。
掌握这两个枚举的取值语义、方法匹配约束与安全取舍,即可在实际的仓颉项目中正确完成 RSA/ECDSA 密钥的生成、导入导出、加解密与签名验证。
- 文档
- 知识库
- 教程
- OpenHarmony
【免费下载链接】CangjieCorpus
本仓库为仓颉编程语言语料库,聚焦 仓颉编程语言 核心知识体系,整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源,经结构化处理与专业标注,构建为支持 RAG(检索增强生成)技术 的高质量知识基座,适配智能编码助手、学习辅助工具等应用开发需求。 欢迎开发者基于本语料库构建仓颉语言智能应用,推动鸿蒙开发生态智能化升级!
相关推荐
仓颉 stdx.crypto.keys 密钥枚举深度解析:Curve 椭圆曲线与 PadOption RSA 填充模式实战指南
仓颉 stdx.crypto.keys 密钥枚举深度解析:Curve 椭圆曲线与 PadOption RSA 填充模式实战指南 本文基于仓颉标准库扩展模块 st
标准库网络密码学并发编程cangjie_stdx 密钥枚举深度解析:ECDSA 椭圆曲线 Curve 与 RSA 填充 PadOption 的选型与实践
cangjie_stdx 密钥枚举深度解析:ECDSA 椭圆曲线 Curve 与 RSA 填充 PadOption 的选型与实践 导读:本文围绕 cangjie
标准库网络密码学并发编程XELIS加密算法详解:Ristretto255与椭圆曲线密码学
XELIS加密算法详解:Ristretto255与椭圆曲线密码学 在区块链技术飞速发展的今天,隐私保护和安全通信成为了用户关注的核心议题。XELIS区块链作为一
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考