类 OpenSSL::PKey::DSA

DSA,数字签名算法,在 NIST 的 FIPS 186-3 中有规定。它是一种非对称公钥算法,可以像 RSA 一样使用。

公共类方法

generate(size) → dsa 点击切换源代码

通过从头开始生成私钥/公钥对,创建一个新的 DSA 实例。

另请参阅 OpenSSL::PKey.generate_parametersOpenSSL::PKey.generate_key.

size

所需的密钥大小(以位为单位)。

# File openssl/lib/openssl/pkey.rb, line 169
def generate(size, &blk)
  # FIPS 186-4 specifies four (L,N) pairs: (1024,160), (2048,224),
  # (2048,256), and (3072,256).
  #
  # q size is derived here with compatibility with
  # DSA_generator_parameters_ex() which previous versions of ruby/openssl
  # used to call.
  qsize = size >= 2048 ? 256 : 160
  dsaparams = OpenSSL::PKey.generate_parameters("DSA", {
    "dsa_paramgen_bits" => size,
    "dsa_paramgen_q_bits" => qsize,
  }, &blk)
  OpenSSL::PKey.generate_key(dsaparams)
end
new → dsa 点击切换源代码
new(string [, pass]) → dsa
new(size) → dsa

通过从 string 中读取现有密钥,创建一个新的 DSA 实例。

如果在没有参数的情况下调用,则创建一个没有设置密钥组件的新实例。它们可以通过 set_pqgset_key 单独设置。

如果使用字符串调用,则尝试将其解析为 DSA 密钥的 DER 或 PEM 编码。另请参阅 OpenSSL::PKey.read,它可以解析任何类型的密钥。

如果使用数字调用,则生成随机参数和密钥对。此形式是 DSA.generate 的别名。

string

包含 DER 或 PEM 编码密钥的字符串。

pass

包含可选密码的字符串。

size

请参阅 DSA.generate.

示例

p OpenSSL::PKey::DSA.new(1024)
#=> #<OpenSSL::PKey::DSA:0x000055a8d6025bf0 oid=DSA>

p OpenSSL::PKey::DSA.new(File.read('dsa.pem'))
#=> #<OpenSSL::PKey::DSA:0x000055555d6b8110 oid=DSA>

p OpenSSL::PKey::DSA.new(File.read('dsa.pem'), 'mypassword')
#=> #<OpenSSL::PKey::DSA:0x0000556f973c40b8 oid=DSA>
static VALUE
ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
{
    EVP_PKEY *pkey;
    DSA *dsa;
    BIO *in = NULL;
    VALUE arg, pass;
    int type;

    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
    if (pkey)
        rb_raise(rb_eTypeError, "pkey already initialized");

    /* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
    rb_scan_args(argc, argv, "02", &arg, &pass);
    if (argc == 0) {
        dsa = DSA_new();
        if (!dsa)
            ossl_raise(eDSAError, "DSA_new");
        goto legacy;
    }

    pass = ossl_pem_passwd_value(pass);
    arg = ossl_to_der_if_possible(arg);
    in = ossl_obj2bio(&arg);

    /* DER-encoded DSAPublicKey format isn't supported by the generic routine */
    dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey,
                                   PEM_STRING_DSA_PUBLIC,
                                   in, NULL, NULL, NULL);
    if (dsa)
        goto legacy;
    OSSL_BIO_reset(in);

    pkey = ossl_pkey_read_generic(in, pass);
    BIO_free(in);
    if (!pkey)
        ossl_raise(eDSAError, "Neither PUB key nor PRIV key");

    type = EVP_PKEY_base_id(pkey);
    if (type != EVP_PKEY_DSA) {
        EVP_PKEY_free(pkey);
        rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
    }
    RTYPEDDATA_DATA(self) = pkey;
    return self;

  legacy:
    BIO_free(in);
    pkey = EVP_PKEY_new();
    if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) {
        EVP_PKEY_free(pkey);
        DSA_free(dsa);
        ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
    }
    RTYPEDDATA_DATA(self) = pkey;
    return self;
}

公共实例方法

export([cipher, password]) → aString 点击切换源代码

将私钥或公钥序列化为 PEM 编码。

当密钥仅包含公钥部分时

将其序列化为 X.509 SubjectPublicKeyInfo。参数 *cipher* 和 *password* 将被忽略。

PEM 编码的密钥将如下所示

-----BEGIN PUBLIC KEY-----
[...]
-----END PUBLIC KEY-----

考虑使用 public_to_pem 代替。这将密钥序列化为 X.509 SubjectPublicKeyInfo,无论它是公钥还是私钥。

当密钥包含私钥部分,且未提供任何参数时

将其序列化为传统的 OpenSSL DSAPrivateKey。

PEM 编码的密钥将如下所示

-----BEGIN DSA PRIVATE KEY-----
[...]
-----END DSA PRIVATE KEY-----
当密钥包含私钥部分,且提供了 *cipher* 和 *password* 时

将其序列化为传统的 OpenSSL DSAPrivateKey,并使用 OpenSSL 的传统 PEM 加密格式对其进行加密。*cipher* 必须是 OpenSSL::Cipher.new 识别的密码名称,或 OpenSSL::Cipher 的实例。

加密的 PEM 编码密钥将如下所示

-----BEGIN DSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0

[...]
-----END DSA PRIVATE KEY-----

请注意,此格式使用 MD5 来推导出加密密钥,因此在符合 FIPS 的系统上将不可用。

此方法保留用于兼容性。 仅当需要传统的非标准 OpenSSL 格式时才应使用此方法。

考虑使用 public_to_pem (X.509 SubjectPublicKeyInfo) 或 private_to_pem (PKCS #8 PrivateKeyInfo 或 EncryptedPrivateKeyInfo) 代替。

static VALUE
ossl_dsa_export(int argc, VALUE *argv, VALUE self)
{
    OSSL_3_const DSA *dsa;

    GetDSA(self, dsa);
    if (DSA_HAS_PRIVATE(dsa))
        return ossl_pkey_export_traditional(argc, argv, self, 0);
    else
        return ossl_pkey_export_spki(self, 0);
}
也称为:to_pemto_s
initialize_copy(p1) 点击以切换源代码
static VALUE
ossl_dsa_initialize_copy(VALUE self, VALUE other)
{
    EVP_PKEY *pkey;
    DSA *dsa, *dsa_new;

    TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey);
    if (pkey)
        rb_raise(rb_eTypeError, "pkey already initialized");
    GetDSA(other, dsa);

    dsa_new = (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey,
                              (d2i_of_void *)d2i_DSAPrivateKey,
                              (char *)dsa);
    if (!dsa_new)
        ossl_raise(eDSAError, "ASN1_dup");

    pkey = EVP_PKEY_new();
    if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) {
        EVP_PKEY_free(pkey);
        DSA_free(dsa_new);
        ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
    }
    RTYPEDDATA_DATA(self) = pkey;

    return self;
}
params → hash 点击以切换源代码

将密钥的所有参数存储到哈希中,不安全:私有信息可能会泄露!不要使用 :-)) (由您决定)

static VALUE
ossl_dsa_get_params(VALUE self)
{
    OSSL_3_const DSA *dsa;
    VALUE hash;
    const BIGNUM *p, *q, *g, *pub_key, *priv_key;

    GetDSA(self, dsa);
    DSA_get0_pqg(dsa, &p, &q, &g);
    DSA_get0_key(dsa, &pub_key, &priv_key);

    hash = rb_hash_new();
    rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(p));
    rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(q));
    rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(g));
    rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pub_key));
    rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(priv_key));

    return hash;
}
private? → true | false 点击以切换源代码

指示此 DSA 实例是否具有与之关联的私钥。可以使用 DSA#private_key 检索私钥。

static VALUE
ossl_dsa_is_private(VALUE self)
{
    OSSL_3_const DSA *dsa;

    GetDSA(self, dsa);

    return DSA_PRIVATE(self, dsa) ? Qtrue : Qfalse;
}
public? → true | false 点击以切换源代码

指示此 DSA 实例是否具有与之关联的公钥。可以使用 DSA#public_key 检索公钥。

static VALUE
ossl_dsa_is_public(VALUE self)
{
    const DSA *dsa;
    const BIGNUM *bn;

    GetDSA(self, dsa);
    DSA_get0_key(dsa, &bn, NULL);

    return bn ? Qtrue : Qfalse;
}
public_key → dsanew 点击以切换源代码

返回一个新的 DSA 实例,该实例仅包含 DSA 参数和公钥。

此方法是为了向后兼容而提供的。在大多数情况下,无需调用此方法。

为了将公钥序列化为 PEM 或 DER 编码的 X.509 SubjectPublicKeyInfo 格式,请查看 PKey#public_to_pemPKey#public_to_der

# File openssl/lib/openssl/pkey.rb, line 153
def public_key
  OpenSSL::PKey.read(public_to_der)
end
set_key(pub_key, priv_key) → self

DSA 实例设置 pub_keypriv_keypriv_key 可以为 nil

set_pqg(p, q, g) → self

pqg 设置为 DSA 实例。

syssign(string) → string 点击切换源代码

计算并返回 string 的 DSA 签名,其中 string 预计是原始输入数据的已计算消息摘要。签名是使用此 DSA 实例的私钥签发的。

在 3.0 版中已弃用。考虑使用 PKey::PKey#sign_rawPKey::PKey#verify_raw 代替。

string

要签名的原始输入数据的消息摘要。

示例

dsa = OpenSSL::PKey::DSA.new(2048)
doc = "Sign me"
digest = OpenSSL::Digest.digest('SHA1', doc)

# With legacy #syssign and #sysverify:
sig = dsa.syssign(digest)
p dsa.sysverify(digest, sig) #=> true

# With #sign_raw and #verify_raw:
sig = dsa.sign_raw(nil, digest)
p dsa.verify_raw(nil, sig, digest) #=> true
# File openssl/lib/openssl/pkey.rb, line 220
def syssign(string)
  q or raise OpenSSL::PKey::DSAError, "incomplete DSA"
  private? or raise OpenSSL::PKey::DSAError, "Private DSA key needed!"
  begin
    sign_raw(nil, string)
  rescue OpenSSL::PKey::PKeyError
    raise OpenSSL::PKey::DSAError, $!.message
  end
end
sysverify(digest, sig) → true | false 点击切换源代码

验证给定消息摘要输入的签名是否有效。它通过使用此 DSA 实例的公钥验证 sig 来实现。

在 3.0 版中已弃用。考虑使用 PKey::PKey#sign_rawPKey::PKey#verify_raw 代替。

digest

要签名的原始输入数据的消息摘要。

sig

DSA 签名值。

# File openssl/lib/openssl/pkey.rb, line 243
def sysverify(digest, sig)
  verify_raw(nil, sig, digest)
rescue OpenSSL::PKey::PKeyError
  raise OpenSSL::PKey::DSAError, $!.message
end
to_der → aString 点击切换源代码

将私钥或公钥序列化为 DER 编码。

有关详细信息,请参阅 to_pem

此方法保留用于兼容性。 仅当需要传统的非标准 OpenSSL 格式时才应使用此方法。

考虑使用 public_to_derprivate_to_der 代替。

static VALUE
ossl_dsa_to_der(VALUE self)
{
    OSSL_3_const DSA *dsa;

    GetDSA(self, dsa);
    if (DSA_HAS_PRIVATE(dsa))
        return ossl_pkey_export_traditional(0, NULL, self, 1);
    else
        return ossl_pkey_export_spki(self, 1);
}
to_pem([cipher, password]) → aString

将私钥或公钥序列化为 PEM 编码。

当密钥仅包含公钥部分时

将其序列化为 X.509 SubjectPublicKeyInfo。参数 *cipher* 和 *password* 将被忽略。

PEM 编码的密钥将如下所示

-----BEGIN PUBLIC KEY-----
[...]
-----END PUBLIC KEY-----

考虑使用 public_to_pem 代替。这将密钥序列化为 X.509 SubjectPublicKeyInfo,无论它是公钥还是私钥。

当密钥包含私钥部分,且未提供任何参数时

将其序列化为传统的 OpenSSL DSAPrivateKey。

PEM 编码的密钥将如下所示

-----BEGIN DSA PRIVATE KEY-----
[...]
-----END DSA PRIVATE KEY-----
当密钥包含私钥部分,且提供了 *cipher* 和 *password* 时

将其序列化为传统的 OpenSSL DSAPrivateKey,并使用 OpenSSL 的传统 PEM 加密格式对其进行加密。*cipher* 必须是 OpenSSL::Cipher.new 识别的密码名称,或 OpenSSL::Cipher 的实例。

加密的 PEM 编码密钥将如下所示

-----BEGIN DSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0

[...]
-----END DSA PRIVATE KEY-----

请注意,此格式使用 MD5 来推导出加密密钥,因此在符合 FIPS 的系统上将不可用。

此方法保留用于兼容性。 仅当需要传统的非标准 OpenSSL 格式时才应使用此方法。

考虑使用 public_to_pem (X.509 SubjectPublicKeyInfo) 或 private_to_pem (PKCS #8 PrivateKeyInfo 或 EncryptedPrivateKeyInfo) 代替。

别名:export
to_s([cipher, password]) → aString

将私钥或公钥序列化为 PEM 编码。

当密钥仅包含公钥部分时

将其序列化为 X.509 SubjectPublicKeyInfo。参数 *cipher* 和 *password* 将被忽略。

PEM 编码的密钥将如下所示

-----BEGIN PUBLIC KEY-----
[...]
-----END PUBLIC KEY-----

考虑使用 public_to_pem 代替。这将密钥序列化为 X.509 SubjectPublicKeyInfo,无论它是公钥还是私钥。

当密钥包含私钥部分,且未提供任何参数时

将其序列化为传统的 OpenSSL DSAPrivateKey。

PEM 编码的密钥将如下所示

-----BEGIN DSA PRIVATE KEY-----
[...]
-----END DSA PRIVATE KEY-----
当密钥包含私钥部分,且提供了 *cipher* 和 *password* 时

将其序列化为传统的 OpenSSL DSAPrivateKey,并使用 OpenSSL 的传统 PEM 加密格式对其进行加密。*cipher* 必须是 OpenSSL::Cipher.new 识别的密码名称,或 OpenSSL::Cipher 的实例。

加密的 PEM 编码密钥将如下所示

-----BEGIN DSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,733F5302505B34701FC41F5C0746E4C0

[...]
-----END DSA PRIVATE KEY-----

请注意,此格式使用 MD5 来推导出加密密钥,因此在符合 FIPS 的系统上将不可用。

此方法保留用于兼容性。 仅当需要传统的非标准 OpenSSL 格式时才应使用此方法。

考虑使用 public_to_pem (X.509 SubjectPublicKeyInfo) 或 private_to_pem (PKCS #8 PrivateKeyInfo 或 EncryptedPrivateKeyInfo) 代替。

别名:export