keys 包

介绍

keys 包提供非对称加密算法

使用本包需要外部依赖 OpenSSL 3crypto 动态库文件,故使用前需安装相关工具:

  • 对于 Linux 操作系统,可参考以下方式:
    • 如果系统的包管理工具支持安装 OpenSSL 3 开发工具包,可通过这个方式安装,并确保系统安装目录下含有 libcrypto.solibcrypto.so.3 这两个动态库文件,例如 Ubuntu 22.04 系统上可使用 sudo apt install libssl-dev 命令安装 libssl-dev 工具包;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.solibcrypto.so.3 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 LD_LIBRARY_PATH 以及 LIBRARY_PATH 中。
  • 对于 Windows 操作系统,可按照以下步骤:
    • 自行下载 OpenSSL 3.x.x 源码编译安装 x64 架构软件包或者自行下载安装第三方预编译的供开发人员使用的 OpenSSL 3.x.x 软件包;
    • 确保安装目录下含有 libcrypto.dll.a(或 libcrypto.lib)、libcrypto-3-x64.dll 这两个库文件;
    • libcrypto.dll.a(或 libcrypto.lib) 所在的目录路径设置到环境变量 LIBRARY_PATH 中,将 libcrypto-3-x64.dll 所在的目录路径设置到环境变量 PATH 中。
  • 对于 macOS 操作系统,可参考以下方式:
    • 使用 brew install openssl@3 安装,并确保系统安装目录下含有 libcrypto.dyliblibcrypto.3.dylib 这两个动态库文件;
    • 如果无法通过上面的方式安装,可自行下载 OpenSSL 3.x.x 源码编译安装软件包,并确保安装目录下含有 libcrypto.dyliblibcrypto.3.dylib 这两个动态库文件,然后可选择下面任意一种方式来保证系统链接器可以找到这些文件:
      • 在系统未安装 OpenSSL 的场景,安装时选择直接安装到系统路径下;
      • 安装在自定义目录的场景,将这些文件所在目录设置到环境变量 DYLD_LIBRARY_PATH 以及 LIBRARY_PATH 中。

如果未安装OpenSSL 3软件包或者安装低版本的软件包,程序可能无法使用并抛出相关异常 CryptoException: Can not load openssl library or function xxx.

主要接口

class RSAPrivateKey

public class RSAPrivateKey <: PrivateKey{
    public init(bits: Int32)
    public init(bits: Int32, e: BigInt)
}

RSA 私钥类,提供生成 RSA 私钥能力,RSA 私钥支持签名和解密操作,支持 PEM 和 DER 格式的编码解码,符合 PKCS1 标准,详见 rfc8017

init

public init(bits: Int32)

功能:init 初始化生成私钥, 公共指数默认值为 65537,业界推荐。

参数:

  • bits:密钥长度,需要大于等于 512 位,并且小于等于 16384 位

异常:

  • CryptoException - 密钥长度不符合要求或初始化失败,抛出异常

init

public init(bits: Int32, e: BigInt)

功能:init 初始化生成私钥,允许用户指定公共指数。

参数:

  • bits:密钥长度,需要大于等于 512 位,并且小于等于 16384 位,推荐使用的密钥长度不小于 3072 位
  • e:公钥公共指数,范围是 [3, 2^256-1] 的奇数

异常:

  • CryptoException - 密钥长度不符合要求、公钥公共指数值不符合要求或初始化失败,抛出异常

func sign

public func sign(hash: Digest, digest: Array<Byte>, padType!: PadOption): Array<Byte>

功能:sign 对数据的摘要结果进行签名。

参数:

  • hash:摘要方法,获取 digest 结果使用的摘要方法
  • digest:数据的摘要结果
  • padType:填充模式,可以选择 PKCS1 或 PSS 模式,不支持 OAEP 模式,在对安全场景要求较高的情况下,推荐使用 PSS 填充模式

返回值:签名后的数据

异常:

  • CryptoException:设置摘要方法失败、设置填充模式失败或签名失败,抛出异常

func decrypt

public func decrypt(input: InputStream, output: OutputStream, padType!: PadOption): Unit

功能:decrypt 解密出原始数据。

参数:

  • input:加密的数据
  • digest:解密后的数据
  • padType:填充模式,可以选择 PKCS1 或 OAEP 模式,不支持 PSS 模式,在对安全场景要求较高的情况下,推荐使用 OAEP 填充模式

异常:

  • CryptoException - 设置填充模式失败或解密失败,抛出异常

func encodeToDer

public override func encodeToDer(): DerBlob

功能:将私钥编码为 DER 格式。

返回值:Derblob 对象

异常:

  • CryptoException:编码失败,抛出异常

func encodeToDer

public func encodeToDer(password!: ?String): DerBlob

功能:使用 AES-256-CBC 加密私钥,将私钥编码为 DER 格式。

参数:

  • password:加密私钥需要提供的密码,密码为 None 时则不加密

返回值:Derblob 对象

异常:

  • CryptoException:编码失败、加密失败或者参数密码为空字符串,抛出异常

func encodeToPem

public override func encodeToPem(): PemEntry

功能:将私钥编码为 PEM 格式。

返回值:PemEntry 对象

异常:

  • CryptoException:编码失败,抛出异常

func decodeDer

public static func decodeDer(blob: DerBlob): RSAPrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • password:二进制格式的私钥对象

返回值:解码出的 RSA 私钥

异常:

  • CryptoException:解码失败,抛出异常

func decodeDer

public static func decodeDer(blob: DerBlob, password!: ?String): RSAPrivateKey

功能:将加密的私钥从 DER 格式解码。

参数:

  • blob:二进制格式的私钥对象
  • password:解密私钥需要提供的密码,密码为 None 时则不解密

返回值:解码出的 RSA 私钥

异常:

  • CryptoException:解码失败、解密失败或者参数密码为空字符串,抛出异常

func decodeFromPem

public static func decodeFromPem(text: String): RSAPrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text:PEM 格式的私钥字符流

返回值:解码出的 RSA 私钥

异常:

  • CryptoException:解码失败、解密失败、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常

func decodeFromPem

public static func decodeFromPem(text: String, password!: ?String): RSAPrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text:PEM 格式的私钥字符流
  • password:解密私钥需要提供的密码,密码为 None 时则不解密

返回值:解码出的 RSA 私钥

异常:

  • CryptoException:解码失败、解密失败、参数密码为空字符串、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常

func toString

public override func toString(): String

功能:输出私钥种类。

class RSAPublicKey

public class RSAPublicKey <: PublicKey {
    public init(pri: RSAPrivateKey)
}

RSA 公钥类,提供生成 RSA 公钥能力,RSA 公钥支持验证签名和加密操作,支持 PEM 和 DER 格式的编码解码。

init

public init(pri: RSAPrivateKey)

功能:init 初始化公钥,从私钥中获取对应的公钥。

参数:

  • pri:RSA私钥

异常:

  • CryptoException:初始化失败,抛出异常

func verify

public func verify(hash: Digest, digest: Array<Byte>, sig: Array<Byte>, padType!: PadOption): Bool

功能:verify 验证签名结果。

参数:

  • hash:摘要方法,获取 digest 结果使用的摘要方法
  • digest:数据的摘要结果
  • sig:数据的签名结果
  • padType:填充模式,可以选择 PKCS1 或 PSS 模式,不支持 OAEP 模式,在对安全场景要求较高的情况下,推荐使用 PSS 填充模式

返回值:返回 true 表示验证成功,false 失败

异常:

  • CryptoException:设置填充模式失败或验证失败,抛出异常

func encrypt

public func encrypt(input: InputStream, output: OutputStream, padType!: PadOption): Unit

功能:encrypt 给一段数据进行加密。

参数:

  • input:需要加密的数据
  • output:加密后的数据
  • padType:填充模式,可以选择 PKCS1 或 OAEP 模式,不支持 PSS 模式,在对安全场景要求较高的情况下,推荐使用 OAEP 填充模式

异常:

  • CryptoException:设置填充模式失败或加密失败,抛出异常

func encodeToDer

public override func encodeToDer(): DerBlob

功能:将公钥编码为 DER 格式。

返回值:返回 Derblob 对象

异常:

  • CryptoException:编码失败,抛出异常

func encodeToPem

public override func encodeToPem(): PemEntry

功能:将公钥编码为 PEM 格式。

返回值:返回 PemEntry 对象

异常:

  • CryptoException:编码失败,抛出异常

func decodeDer

public static func decodeDer(blob: DerBlob): RSAPublicKey

功能:将公钥从 DER 格式解码。

参数:

  • blob:二进制格式的公钥对象

返回值:解码出的 RSA 公钥

异常:

  • CryptoException:解码失败,抛出异常

func decodeFromPem

public static func decodeFromPem(text: String): RSAPublicKey

功能:将公钥从PEM 格式解码。

参数:

  • text:PEM 格式的公钥字符流

返回值:解码出的 RSA 公钥

异常:

  • CryptoException:解码失败、字符流不符合 PEM 格式或文件头不符合公钥头标准时,抛出异常

func toString

public override func toString(): String

功能:输出公钥种类

enum PadOption

public enum PadOption {
    | OAEP(OAEPOption) | PSS(PSSOption) | PKCS1
}

枚举类型 PadOption 用于设置 RSA 的填充模式,RSA 有三种常用的填充模式,OAEP 为最优非对称加密填充,只能用于加密解密;PSS 为概率签名方案, 只能用于签名和验证,PKCS1 是一种普通的填充模式,用于填充数据长度,可以用于加密、解密、签名和验证。RSA 的 PKCS1 填充模式是在早期的 PKCS #1 v1.5 规范中定义的填充模式,当前对使用 PKCS1 填充模式的攻击较为成熟,容易被攻击者解密或伪造签名,建议采用 PKCS #1 v2 版本中更加安全的 PSS 或 OAEP 填充模式。

OAEP

OAEP(OAEPOption)

功能:使用最优非对称加密初始化 PadOption 实例。

PSS

PSS(PSSOption)

功能:使用概率签名方案初始化 PadOption 实例。

PKCS1

PKCS1

功能:使用 PKCS #1 公钥密码学标准初始化 PadOption 实例。

struct OAEPOption

public struct OAEPOption {
    public init(hash: Digest, mgfHash: Digest, label!: String = "")
}

此结构体为 OAEP 填充模式需要设置的参数。

init

public init(hash: Digest, mgfHash: Digest, label!: String = "")

功能:初始化 OAEP 填充参数。

参数:

  • hash:摘要方法,用于对 label 进行摘要
  • mgfHash:摘要方法,用于设置 MGF1 函数中的摘要方法
  • label: 摘要方法,label 是可选参数,默认为空字符串,可以通过设置 lable 来区分不同的加密操作

init

public init(hash: Digest, mgfHash: Digest, label!: String = "")

功能:初始化 OAEP 填充参数。

参数:

  • hash:摘要方法,用于对 label 进行摘要
  • mgfHash:摘要方法,用于设置 MGF1 函数中的摘要方法
  • label:label 是可选参数,默认为空字符串,可以通过设置 lable 来区分不同的加密操作

struct PSSOption

public struct PSSOption {
    public init(saltLen: Int32)
}

此结构体为 PSS 填充模式需要设置的参数。

init

public init(saltLen: Int32)

功能:初始化 PSS 填充参数。

参数:

  • saltLen:随机盐长度,长度应大于等于 0,小于等于(RSA 长度 - 摘要长度 - 2),长度单位为字节,长度过长会导致签名失败

异常:

  • CryptoException:随机盐长度小于 0,抛出异常

enum Curve

public enum Curve {
    | P224 | P256 | P384 | P521 | BP256 | BP320 | BP384 | BP512
}

枚举类型 Curve 用于选择生成 ECDSA 密钥时使用的椭圆曲线类型,支持 NIST P-224,NIST P-256,NIST P-384,NIST P-521,Brainpool P-256,Brainpool P-320,Brainpool P-384,Brainpool P-512 八种椭圆曲线。

P224

P224

功能:使用 NIST P-224 椭圆曲线初始化 Curve 实例。

P256

P256

功能:使用 NIST P-256 椭圆曲线初始化 Curve 实例。

P384

P384

功能:使用 NIST P-384 椭圆曲线初始化 Curve 实例。

P521

P521

功能:使用 NIST P-521 椭圆曲线初始化 Curve 实例。

BP256

BP256

功能:使用 Brainpool P-256 椭圆曲线初始化 Curve 实例。

BP320

BP320

功能:使用 Brainpool P-320 椭圆曲线初始化 Curve 实例。

BP384

BP384

功能:使用 Brainpool P-384 椭圆曲线初始化 Curve 实例。

BP512

BP512

功能:使用 Brainpool P-512 椭圆曲线初始化 Curve 实例。

class ECDSAPrivateKey

public class ECDSAPrivateKey <: PrivateKey {
    public init(curve: Curve)
}

ECDSA 私钥类,提供生成 ECDSA 私钥能力,ECDSA 的私钥支持签名操作,同时支持 PEM 和 DER 格式的编码解码,详见 FIPS 186-4

init

public init(curve: Curve)

功能:init 初始化生成私钥。

参数:

  • curve:椭圆曲线类型

异常:

  • CryptoException:初始化失败,抛出异常

func sign

public func sign(digest: Array<Byte>): Array<Byte>

功能:sign 对数据的摘要结果进行签名。

参数:

  • digest:数据的摘要结果

返回值:签名后的数据

异常:

  • CryptoException:签名失败,抛出异常

func encodeToDer

public override func encodeToDer(): DerBlob

功能:将私钥编码为 DER 格式。

返回值:返回 Derblob 对象

异常:

  • CryptoException:编码失败,抛出异常

func encodeToDer

public func encodeToDer(password!: ?String): DerBlob

功能:使用 AES-256-CBC 加密私钥,将私钥编码为 DER 格式。

参数:

  • password:加密私钥需要提供的密码,密码为 None 时则不加密

返回值:Derblob 对象

异常:

  • CryptoException:编码失败、加密失败或者参数密码为空字符串,抛出异常

func encodeToPem

public override func encodeToPem(): PemEntry

功能:将私钥编码为 PEM 格式。

返回值:PemEntry 对象

异常:

  • CryptoException:编码失败,抛出异常

func decodeDer

public static func decodeDer(blob: DerBlob): ECDSAPrivateKey

功能:将私钥从 DER 格式解码。

参数:

  • blob:二进制格式的私钥对象

返回值:解码出的 ECDSA 私钥

异常:

  • CryptoException:解码失败,抛出异常

func decodeDer

public static func decodeDer(blob: DerBlob, password!: ?String): ECDSAPrivateKey

功能:将加密的私钥从 DER 格式解码。

参数:

  • blob:二进制格式的私钥对象
  • password:解密私钥需要提供的密码,密码为 None 时则不解密

返回值:解码出的 ECDSA 私钥

异常:

  • CryptoException:解码失败、解密失败或者参数密码为空字符串,抛出异常

func decodeFromPem

public static func decodeFromPem(text: String): ECDSAPrivateKey

功能:将私钥从 PEM 格式解码。

参数:

  • text:PEM 格式的私钥字符流

返回值:解码出的 ECDSA 私钥

异常:

  • CryptoException:解码失败、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常

func decodeFromPem

public static func decodeFromPem(text: String, password!: ?String): ECDSAPrivateKey

功能:将私钥从PEM 格式解码。

参数:

  • text:PEM 格式的私钥字符流
  • password:解密私钥需要提供的密码,密码为 None 时则不解密

返回值:解码出的 ECDSA 私钥

异常:

  • CryptoException:解码失败、解密失败、参数密码为空字符串、字符流不符合 PEM 格式或文件头不符合私钥头标准时,抛出异常

func toString

public override func toString(): String

功能:输出私钥种类。

class ECDSAPublicKey

public class ECDSAPublicKey <: PublicKey {
    public init(pri: ECDSAPrivateKey)
}

ECDSA 公钥类,提供生成 ECDSA 公钥能力,ECDSA 公钥支持验证签名操作,支持 PEM 和 DER 格式的编码解码。

init

public init(pri: ECDSAPrivateKey)

功能:init 初始化公钥,从私钥中获取对应的公钥。

参数:

  • pri:ECDSA 私钥

异常:

  • CryptoException:初始化失败,抛出异常

func verify

public func verify(digest: Array<Byte>, sig: Array<Byte>): Bool

功能:verify 验证签名结果。

参数:

  • digest:数据的摘要结果
  • sig:数据的签名结果

返回值:返回 true 表示验证成功,false 失败

func encodeToDer

public override func encodeToDer(): DerBlob

功能:将公钥编码为 DER 格式。

返回值:返回 Derblob 对象

异常:

  • CryptoException:编码失败,抛出异常

func encodeToPem

public override func encodeToPem(): PemEntry

功能:将公钥编码为 PEM 格式。

返回值:PemEntry 对象

异常:

  • CryptoException:编码失败,抛出异常

func decodeDer

public static func decodeDer(blob: DerBlob): ECDSAPublicKey

功能:将公钥从 DER 格式解码。

参数:

  • blob:二进制格式的公钥对象

返回值:解码出的 ECDSA 公钥

异常:

  • CryptoException:编码失败,抛出异常

func decodeFromPem

public static func decodeFromPem(text: String): ECDSAPublicKey

功能:将公钥从 PEM 格式解码。

参数:

  • text:PEM 格式的公钥字符流

返回值:解码出的 ECDSA 公钥

异常:

  • CryptoException:解码失败、字符流不符合 PEM 格式或文件头不符合公钥头标准时,抛出异常

func toString

public override func toString(): String

功能:输出公钥种类。

示例

RSA 密钥示例

使用 RSA 密钥使用示例。

生成 rsa 公钥及私钥,并使用公钥的 OAEP 填充模式加密,用私钥的 OAEP 填充模式解密。

from crypto import keys.*
from crypto import digest.*
from std import io.*
from std import crypto.digest.*

main() {
    var rsaPri = RSAPrivateKey(2048)
    var rsaPub = RSAPublicKey(rsaPri)

    var str: String = "hello world, hello cangjie"
    var bas1 = ByteArrayStream()
    var bas2 = ByteArrayStream()
    var bas3 = ByteArrayStream()
    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, item:0)
    bas3.read(buf)
    if (str.toArray() == buf){
        println("success")
    } else {
        println("fail")
    }
}

从文件中读取 rsa 公钥和私钥,并使用私钥的 PKCS1 填充模式签名,用公钥的 PKCS1 填充模式验证签名结果。

from crypto import keys.*
from crypto import digest.*
from std import crypto.digest.*
from std import fs.*

main() {
    var pemPri = String.fromUtf8(File("./files/rsaPri.pem", OpenOption.Open(true, false)).readToEnd())
    var rsaPri = RSAPrivateKey.decodeFromPem(pemPri)

    var pemPub = String.fromUtf8(File("./files/rsaPub.pem", OpenOption.Open(true, false)).readToEnd())
    var rsaPub = RSAPublicKey.decodeFromPem(pemPub)

    var str: String = "helloworld"
    var sha512Instance = SHA512()
    var md: Array<Byte> = digest(sha512Instance, str)

    var sig = rsaPri.sign(sha512Instance, md, padType: PKCS1)
    if (rsaPub.verify(sha512Instance, md, sig, padType: PKCS1)){
        println("verify successful")
    }
}

ECDSA 密钥示例

使用 ECDSA 密钥使用示例。

生成 ECDSA 公钥及私钥,并使用私钥签名,公钥验证签名结果。

from crypto import keys.*
from crypto import digest.*
from std import convert.*
from std import crypto.digest.*

main() {
    var ecPri = ECDSAPrivateKey(P224)
    var ecPub = ECDSAPublicKey(ecPri)

    var str: String = "helloworld"
    var sha512Instance = SHA512()
    var md: Array<Byte> = digest(sha512Instance, str)

    var sig = ecPri.sign(md)
    println(sig)
    if (ecPub.verify(md, sig)){
        println("verify successful")
    }
}