模块 OpenSSL::PKey

非对称公钥算法

非对称公钥算法解决了建立和共享用于加密/解密消息的密钥的问题。这种算法中的密钥由两部分组成:可以分发给其他人的公钥和需要保密的私钥。

用公钥加密的消息只能由拥有相关私钥的接收者解密。由于公钥算法比对称密钥算法(参见 OpenSSL::Cipher)慢得多,它们通常用于在彼此拥有公钥的双方之间建立共享的对称密钥。

非对称算法提供了很多很好的特性,这些特性在许多不同领域中使用。一个非常常见的应用是数字签名的创建和验证。要签署文档,签名者通常使用消息摘要算法(参见 OpenSSL::Digest)计算文档的摘要,然后使用私钥对其进行加密(即签名)。任何拥有公钥的人都可以通过自己计算原始文档的消息摘要,使用签名者的公钥解密签名,并将结果与之前计算的消息摘要进行比较来验证签名。当且仅当解密的签名等于此消息摘要时,签名才有效。

PKey 模块为三种流行的公钥/私钥算法提供支持

这些实现的每一个实际上都是抽象 PKey 类的子类,该类以 PKey#signPKey#verify 的形式提供支持数字签名的接口。

Diffie-Hellman 密钥交换

最后,PKey 还具有 OpenSSL::PKey::DH,它是基于有限域中离散对数的 Diffie-Hellman 密钥交换协议的实现,这与 DSA 的构建基础相同。Diffie-Hellman 协议可用于在不安全的通道上交换(对称)密钥,而无需参与方之间任何预先的共同知识。由于 DH 的安全性需要相对较长的“公钥”(即在参与者之间公开传输的部分),DH 往往非常慢。如果安全或速度是您主要关心的问题,OpenSSL::PKey::EC 提供了 Diffie-Hellman 协议的另一种实现。

公共类方法

OpenSSL::PKey.generate_key(algo_name [, options]) → pkey 点击以切换源代码
OpenSSL::PKey.generate_key(pkey [, options]) → pkey

生成新的密钥(对)。

如果将字符串作为第一个参数给出,它会为指定名称的算法生成一个新的随机密钥,就像 ::generate_parameters 一样。如果给出 OpenSSL::PKey::PKey,它会使用密钥包含的参数,为与密钥相同的算法生成一个新的随机密钥。

有关 options 和给定块的详细信息,请参阅 ::generate_parameters

示例

pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
pkey_params.priv_key #=> nil
pkey = OpenSSL::PKey.generate_key(pkey_params)
pkey.priv_key #=> #<OpenSSL::BN 6277...
static VALUE
ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
{
    return pkey_generate(argc, argv, self, 0);
}
OpenSSL::PKey.generate_parameters(algo_name [, options]) → pkey 点击以切换源代码

为算法生成新参数。algo_name 是表示算法的字符串。可选参数 options 是指定算法特定选项的哈希。选项的顺序可能很重要。

可以可选地传递一个块。传递给该块的参数的含义取决于算法的实现。该块可能被调用一次或多次,或者甚至可能不被调用。

有关受支持的选项,请参阅“openssl genpkey”实用工具命令的文档。

示例

pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
p pkey.p.num_bits #=> 2048
static VALUE
ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self)
{
    return pkey_generate(argc, argv, self, 1);
}
OpenSSL::PKey.new_raw_private_key(algo, string) → PKey 点击以切换源代码

有关详细信息,请参阅 OpenSSL 文档中的 EVP_PKEY_new_raw_private_key()

static VALUE
ossl_pkey_new_raw_private_key(VALUE self, VALUE type, VALUE key)
{
    EVP_PKEY *pkey;
    const EVP_PKEY_ASN1_METHOD *ameth;
    int pkey_id;
    size_t keylen;

    StringValue(type);
    StringValue(key);
    ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
    if (!ameth)
        ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
    EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);

    keylen = RSTRING_LEN(key);

    pkey = EVP_PKEY_new_raw_private_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
    if (!pkey)
        ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key");

    return ossl_pkey_new(pkey);
}
OpenSSL::PKey.new_raw_public_key(algo, string) → PKey 点击以切换源代码

有关详细信息,请参阅 OpenSSL 文档中的 EVP_PKEY_new_raw_public_key()

static VALUE
ossl_pkey_new_raw_public_key(VALUE self, VALUE type, VALUE key)
{
    EVP_PKEY *pkey;
    const EVP_PKEY_ASN1_METHOD *ameth;
    int pkey_id;
    size_t keylen;

    StringValue(type);
    StringValue(key);
    ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
    if (!ameth)
        ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
    EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);

    keylen = RSTRING_LEN(key);

    pkey = EVP_PKEY_new_raw_public_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
    if (!pkey)
        ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key");

    return ossl_pkey_new(pkey);
}
OpenSSL::PKey.read(string [, pwd ]) → PKey 点击以切换源代码
OpenSSL::PKey.read(io [, pwd ]) → PKey

stringio 读取 DER 或 PEM 编码的字符串,并返回适当的 PKey 类的实例。

参数

  • string 是一个包含任意私钥或公钥的 DER 或 PEM 编码的字符串。

  • io 是包含 DER 或 PEM 编码的任意私钥或公钥的 IO 实例。

  • pwd 是一个可选密码,以防 stringio 是加密的 PEM 资源。

static VALUE
ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    BIO *bio;
    VALUE data, pass;

    rb_scan_args(argc, argv, "11", &data, &pass);
    bio = ossl_obj2bio(&data);
    pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
    BIO_free(bio);
    if (!pkey)
        ossl_raise(ePKeyError, "Could not parse PKey");
    return ossl_pkey_new(pkey);
}