类 OpenSSL::PKey::PKey
一个抽象类,它将签名创建 (PKey#sign
) 和验证 (PKey#verify
) 捆绑在一起,这些操作对所有实现都是通用的,除了 OpenSSL::PKey::DH
公共类方法
因为 PKey
是一个抽象类,所以显式调用此方法将引发 NotImplementedError
。
static VALUE ossl_pkey_initialize(VALUE self) { if (rb_obj_is_instance_of(self, cPKey)) { ossl_raise(rb_eTypeError, "OpenSSL::PKey::PKey can't be instantiated directly"); } return self; }
公共实例方法
主要用于检查 OpenSSL::X509::Certificate#public_key
是否与其私钥匹配。
示例¶ ↑
x509 = OpenSSL::X509::Certificate.new(pem_encoded_certificate) rsa_key = OpenSSL::PKey::RSA.new(pem_encoded_private_key) rsa_key.compare?(x509.public_key) => true | false
static VALUE ossl_pkey_compare(VALUE self, VALUE other) { int ret; EVP_PKEY *selfPKey; EVP_PKEY *otherPKey; GetPKey(self, selfPKey); GetPKey(other, otherPKey); /* Explicitly check the key type given EVP_PKEY_ASN1_METHOD(3) * docs param_cmp could return any negative number. */ if (EVP_PKEY_id(selfPKey) != EVP_PKEY_id(otherPKey)) ossl_raise(rb_eTypeError, "cannot match different PKey types"); ret = EVP_PKEY_eq(selfPKey, otherPKey); if (ret == 0) return Qfalse; else if (ret == 1) return Qtrue; else ossl_raise(ePKeyError, "EVP_PKEY_eq"); }
使用 pkey
执行公钥解密操作。
有关参数和示例的说明,请参阅 encrypt
。
在版本 3.0 中添加。另请参阅手册页 EVP_PKEY_decrypt(3)。
static VALUE ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; EVP_PKEY_CTX *ctx; VALUE data, options, str; size_t outlen; int state; GetPKey(self, pkey); rb_scan_args(argc, argv, "11", &data, &options); StringValue(data); ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); if (!ctx) ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); if (EVP_PKEY_decrypt_init(ctx) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_decrypt_init"); } if (!NIL_P(options)) { pkey_ctx_apply_options(ctx, options, &state); if (state) { EVP_PKEY_CTX_free(ctx); rb_jump_tag(state); } } if (EVP_PKEY_decrypt(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_decrypt"); } if (outlen > LONG_MAX) { EVP_PKEY_CTX_free(ctx); rb_raise(ePKeyError, "decrypted data would be too large"); } str = ossl_str_new(NULL, (long)outlen, &state); if (state) { EVP_PKEY_CTX_free(ctx); rb_jump_tag(state); } if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_decrypt"); } EVP_PKEY_CTX_free(ctx); rb_str_set_len(str, outlen); return str; }
从 pkey 和 peer_pkey 推导出共享密钥。pkey 必须包含私有组件,peer_pkey 必须包含公有组件。
static VALUE ossl_pkey_derive(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey, *peer_pkey; EVP_PKEY_CTX *ctx; VALUE peer_pkey_obj, str; size_t keylen; int state; GetPKey(self, pkey); rb_scan_args(argc, argv, "1", &peer_pkey_obj); GetPKey(peer_pkey_obj, peer_pkey); ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); if (!ctx) ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); if (EVP_PKEY_derive_init(ctx) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_derive_init"); } if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer"); } if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_derive"); } if (keylen > LONG_MAX) rb_raise(ePKeyError, "derived key would be too large"); str = ossl_str_new(NULL, (long)keylen, &state); if (state) { EVP_PKEY_CTX_free(ctx); rb_jump_tag(state); } if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_derive"); } EVP_PKEY_CTX_free(ctx); rb_str_set_len(str, keylen); return str; }
使用 pkey
执行公钥加密操作。
有关逆向操作,请参阅 decrypt
。
在版本 3.0 中添加。另请参阅手册页 EVP_PKEY_encrypt(3)。
data
-
要加密的
String
。 options
-
包含针对 OpenSSL 的算法特定控制操作的
Hash
。有关详细信息,请参阅 OpenSSL 的手册页 EVP_PKEY_CTX_ctrl_str(3)。
示例
pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) data = "secret data" encrypted = pkey.encrypt(data, rsa_padding_mode: "oaep") decrypted = pkey.decrypt(data, rsa_padding_mode: "oaep") p decrypted #=> "secret data"
static VALUE ossl_pkey_encrypt(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; EVP_PKEY_CTX *ctx; VALUE data, options, str; size_t outlen; int state; GetPKey(self, pkey); rb_scan_args(argc, argv, "11", &data, &options); StringValue(data); ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); if (!ctx) ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); if (EVP_PKEY_encrypt_init(ctx) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_encrypt_init"); } if (!NIL_P(options)) { pkey_ctx_apply_options(ctx, options, &state); if (state) { EVP_PKEY_CTX_free(ctx); rb_jump_tag(state); } } if (EVP_PKEY_encrypt(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_encrypt"); } if (outlen > LONG_MAX) { EVP_PKEY_CTX_free(ctx); rb_raise(ePKeyError, "encrypted data would be too large"); } str = ossl_str_new(NULL, (long)outlen, &state); if (state) { EVP_PKEY_CTX_free(ctx); rb_jump_tag(state); } if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_encrypt"); } EVP_PKEY_CTX_free(ctx); rb_str_set_len(str, outlen); return str; }
HAVE_EVP_PKEY_DUP static VALUE ossl_pkey_initialize_copy(VALUE self, VALUE other) { EVP_PKEY *pkey, *pkey_other; TypedData_Get_Struct(self, EVP_PKEY, &ossl_evp_pkey_type, pkey); TypedData_Get_Struct(other, EVP_PKEY, &ossl_evp_pkey_type, pkey_other); if (pkey) rb_raise(rb_eTypeError, "pkey already initialized"); if (pkey_other) { pkey = EVP_PKEY_dup(pkey_other); if (!pkey) ossl_raise(ePKeyError, "EVP_PKEY_dup"); RTYPEDDATA_DATA(self) = pkey; } return self; }
返回描述 PKey
对象的字符串。
static VALUE ossl_pkey_inspect(VALUE self) { EVP_PKEY *pkey; int nid; GetPKey(self, pkey); nid = EVP_PKEY_id(pkey); return rb_sprintf("#<%"PRIsVALUE":%p oid=%s>", rb_class_name(CLASS_OF(self)), (void *)self, OBJ_nid2sn(nid)); }
返回与 pkey 关联的 OID 的简短名称。
static VALUE ossl_pkey_oid(VALUE self) { EVP_PKEY *pkey; int nid; GetPKey(self, pkey); nid = EVP_PKEY_id(pkey); return rb_str_new_cstr(OBJ_nid2sn(nid)); }
将私钥序列化为 DER 编码的 PKCS #8 格式。如果在没有参数的情况下调用,则使用未加密的 PKCS #8 PrivateKeyInfo 格式。如果使用密码调用,则使用带有 PBES2 加密方案的 PKCS #8 EncryptedPrivateKeyInfo 格式。
static VALUE ossl_pkey_private_to_der(int argc, VALUE *argv, VALUE self) { return do_pkcs8_export(argc, argv, self, 1); }
将私钥序列化为 PEM 编码的 PKCS #8 格式。有关更多详细信息,请参阅 private_to_der
。
未加密的 PEM 编码密钥将如下所示
-----BEGIN PRIVATE KEY----- [...] -----END PRIVATE KEY-----
加密的 PEM 编码密钥将如下所示
-----BEGIN ENCRYPTED PRIVATE KEY----- [...] -----END ENCRYPTED PRIVATE KEY-----
static VALUE ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self) { return do_pkcs8_export(argc, argv, self, 0); }
将公钥序列化为 DER 编码的 X.509 SubjectPublicKeyInfo 格式。
static VALUE ossl_pkey_public_to_der(VALUE self) { return ossl_pkey_export_spki(self, 1); }
将公钥序列化为 PEM 编码的 X.509 SubjectPublicKeyInfo 格式。
PEM 编码密钥将如下所示
-----BEGIN PUBLIC KEY----- [...] -----END PUBLIC KEY-----
static VALUE ossl_pkey_public_to_pem(VALUE self) { return ossl_pkey_export_spki(self, 0); }
有关 EVP_PKEY_get_raw_private_key() 的信息,请参阅 OpenSSL
文档。
static VALUE ossl_pkey_raw_private_key(VALUE self) { EVP_PKEY *pkey; VALUE str; size_t len; GetPKey(self, pkey); if (EVP_PKEY_get_raw_private_key(pkey, NULL, &len) != 1) ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key"); str = rb_str_new(NULL, len); if (EVP_PKEY_get_raw_private_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1) ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key"); rb_str_set_len(str, len); return str; }
有关 EVP_PKEY_get_raw_public_key() 的信息,请参阅 OpenSSL
文档。
static VALUE ossl_pkey_raw_public_key(VALUE self) { EVP_PKEY *pkey; VALUE str; size_t len; GetPKey(self, pkey); if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1) ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key"); str = rb_str_new(NULL, len); if (EVP_PKEY_get_raw_public_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1) ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key"); rb_str_set_len(str, len); return str; }
使用消息摘要算法 digest
和私钥 pkey
对 data
进行哈希和签名。
有关验证操作,请参阅 verify
。
另请参阅手册页 EVP_DigestSign(3)。
digest
-
表示消息摘要算法名称的
String
,如果PKey
类型不需要消息摘要算法,则为nil
。为了向后兼容,这可以是OpenSSL::Digest
的实例。它的状态不会影响签名。 data
-
一个
String
。要进行哈希和签名的數據。 options
-
包含针对 OpenSSL 的算法特定控制操作的
Hash
。有关详细信息,请参阅 OpenSSL 的手册页 EVP_PKEY_CTX_ctrl_str(3)。options
参数是在版本 3.0 中添加的。
示例
data = "Sign me!" pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) signopts = { rsa_padding_mode: "pss" } signature = pkey.sign("SHA256", data, signopts) # Creates a copy of the RSA key pkey, but without the private components pub_key = pkey.public_key puts pub_key.verify("SHA256", signature, data, signopts) # => true
static VALUE ossl_pkey_sign(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; VALUE digest, data, options, sig; const EVP_MD *md = NULL; EVP_MD_CTX *ctx; EVP_PKEY_CTX *pctx; size_t siglen; int state; pkey = GetPrivPKeyPtr(self); rb_scan_args(argc, argv, "21", &digest, &data, &options); if (!NIL_P(digest)) md = ossl_evp_get_digestbyname(digest); StringValue(data); ctx = EVP_MD_CTX_new(); if (!ctx) ossl_raise(ePKeyError, "EVP_MD_CTX_new"); if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) { EVP_MD_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_DigestSignInit"); } if (!NIL_P(options)) { pkey_ctx_apply_options(pctx, options, &state); if (state) { EVP_MD_CTX_free(ctx); rb_jump_tag(state); } } #if OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_LIBRESSL_PREREQ(3, 4, 0) if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { EVP_MD_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_DigestSign"); } if (siglen > LONG_MAX) { EVP_MD_CTX_free(ctx); rb_raise(ePKeyError, "signature would be too large"); } sig = ossl_str_new(NULL, (long)siglen, &state); if (state) { EVP_MD_CTX_free(ctx); rb_jump_tag(state); } if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { EVP_MD_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_DigestSign"); } #else if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { EVP_MD_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_DigestSignUpdate"); } if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) { EVP_MD_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_DigestSignFinal"); } if (siglen > LONG_MAX) { EVP_MD_CTX_free(ctx); rb_raise(ePKeyError, "signature would be too large"); } sig = ossl_str_new(NULL, (long)siglen, &state); if (state) { EVP_MD_CTX_free(ctx); rb_jump_tag(state); } if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen) < 1) { EVP_MD_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_DigestSignFinal"); } #endif EVP_MD_CTX_free(ctx); rb_str_set_len(sig, siglen); return sig; }
使用私钥 pkey
对 data
进行签名。与 sign
不同,data
不会被 digest
自动进行哈希。
有关验证操作,请参阅 verify_raw
。
在版本 3.0 中添加。另请参阅手册页 EVP_PKEY_sign(3)。
digest
-
表示消息摘要算法名称的
String
,如果PKey
类型不需要消息摘要算法,则为nil
。虽然此方法不会使用它对data
进行哈希,但根据签名算法,此参数可能仍然是必需的。 data
-
一个
String
。要签名的數據。 options
-
包含针对 OpenSSL 的算法特定控制操作的
Hash
。有关详细信息,请参阅 OpenSSL 的手册页 EVP_PKEY_CTX_ctrl_str(3)。
示例
data = "Sign me!" hash = OpenSSL::Digest.digest("SHA256", data) pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048) signopts = { rsa_padding_mode: "pss" } signature = pkey.sign_raw("SHA256", hash, signopts) # Creates a copy of the RSA key pkey, but without the private components pub_key = pkey.public_key puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true
static VALUE ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; VALUE digest, data, options, sig; const EVP_MD *md = NULL; EVP_PKEY_CTX *ctx; size_t outlen; int state; GetPKey(self, pkey); rb_scan_args(argc, argv, "21", &digest, &data, &options); if (!NIL_P(digest)) md = ossl_evp_get_digestbyname(digest); StringValue(data); ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); if (!ctx) ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); if (EVP_PKEY_sign_init(ctx) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_sign_init"); } if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); } if (!NIL_P(options)) { pkey_ctx_apply_options(ctx, options, &state); if (state) { EVP_PKEY_CTX_free(ctx); rb_jump_tag(state); } } if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_sign"); } if (outlen > LONG_MAX) { EVP_PKEY_CTX_free(ctx); rb_raise(ePKeyError, "signature would be too large"); } sig = ossl_str_new(NULL, (long)outlen, &state); if (state) { EVP_PKEY_CTX_free(ctx); rb_jump_tag(state); } if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_sign"); } EVP_PKEY_CTX_free(ctx); rb_str_set_len(sig, outlen); return sig; }
将密钥参数、公钥和私钥组件(包含在密钥中)转储到人类可读的文本中。
这是为了调试目的。
另请参阅手册页 EVP_PKEY_print_private(3)。
static VALUE ossl_pkey_to_text(VALUE self) { EVP_PKEY *pkey; BIO *bio; GetPKey(self, pkey); if (!(bio = BIO_new(BIO_s_mem()))) ossl_raise(ePKeyError, "BIO_new"); if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1) goto out; OSSL_BIO_reset(bio); if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1) goto out; OSSL_BIO_reset(bio); if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1) goto out; BIO_free(bio); ossl_raise(ePKeyError, "EVP_PKEY_print_params"); out: return ossl_membio2str(bio); }
使用消息摘要算法 digest
和公钥 pkey
验证 data
的 signature
。
如果签名成功验证,则返回 true
,否则返回 false
。调用者必须检查返回值。
有关签名操作和示例,请参阅 sign
。
另请参阅手册页 EVP_DigestVerify(3)。
static VALUE ossl_pkey_verify(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; VALUE digest, sig, data, options; const EVP_MD *md = NULL; EVP_MD_CTX *ctx; EVP_PKEY_CTX *pctx; int state, ret; GetPKey(self, pkey); rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options); ossl_pkey_check_public_key(pkey); if (!NIL_P(digest)) md = ossl_evp_get_digestbyname(digest); StringValue(sig); StringValue(data); ctx = EVP_MD_CTX_new(); if (!ctx) ossl_raise(ePKeyError, "EVP_MD_CTX_new"); if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) { EVP_MD_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_DigestVerifyInit"); } if (!NIL_P(options)) { pkey_ctx_apply_options(pctx, options, &state); if (state) { EVP_MD_CTX_free(ctx); rb_jump_tag(state); } } #if OSSL_OPENSSL_PREREQ(1, 1, 1) || OSSL_LIBRESSL_PREREQ(3, 4, 0) ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)); EVP_MD_CTX_free(ctx); if (ret < 0) ossl_raise(ePKeyError, "EVP_DigestVerify"); #else if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) { EVP_MD_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate"); } ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LEN(sig)); EVP_MD_CTX_free(ctx); if (ret < 0) ossl_raise(ePKeyError, "EVP_DigestVerifyFinal"); #endif if (ret) return Qtrue; else { ossl_clear_error(); return Qfalse; } }
使用公钥 pkey
验证 data
的 signature
。与 verify
不同,此方法不会使用 digest
自动对 data
进行哈希。
如果签名成功验证,则返回 true
,否则返回 false
。调用者必须检查返回值。
有关签名操作和示例代码,请参阅 sign_raw
。
在版本 3.0 中添加。另请参阅手册页 EVP_PKEY_verify(3)。
signature
-
包含要验证的签名的
String
。
static VALUE ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; VALUE digest, sig, data, options; const EVP_MD *md = NULL; EVP_PKEY_CTX *ctx; int state, ret; GetPKey(self, pkey); rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options); ossl_pkey_check_public_key(pkey); if (!NIL_P(digest)) md = ossl_evp_get_digestbyname(digest); StringValue(sig); StringValue(data); ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); if (!ctx) ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); if (EVP_PKEY_verify_init(ctx) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_verify_init"); } if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); } if (!NIL_P(options)) { pkey_ctx_apply_options(ctx, options, &state); if (state) { EVP_PKEY_CTX_free(ctx); rb_jump_tag(state); } } ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data)); EVP_PKEY_CTX_free(ctx); if (ret < 0) ossl_raise(ePKeyError, "EVP_PKEY_verify"); if (ret) return Qtrue; else { ossl_clear_error(); return Qfalse; } }
使用公钥 pkey
从 signature
中恢复已签名的數據。并非所有签名算法都支持此操作。
在版本 3.0 中添加。另请参阅手册页 EVP_PKEY_verify_recover(3)。
signature
-
包含要验证的签名的
String
。
static VALUE ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self) { EVP_PKEY *pkey; VALUE digest, sig, options, out; const EVP_MD *md = NULL; EVP_PKEY_CTX *ctx; int state; size_t outlen; GetPKey(self, pkey); rb_scan_args(argc, argv, "21", &digest, &sig, &options); ossl_pkey_check_public_key(pkey); if (!NIL_P(digest)) md = ossl_evp_get_digestbyname(digest); StringValue(sig); ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL); if (!ctx) ossl_raise(ePKeyError, "EVP_PKEY_CTX_new"); if (EVP_PKEY_verify_recover_init(ctx) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_verify_recover_init"); } if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md"); } if (!NIL_P(options)) { pkey_ctx_apply_options(ctx, options, &state); if (state) { EVP_PKEY_CTX_free(ctx); rb_jump_tag(state); } } if (EVP_PKEY_verify_recover(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(sig), RSTRING_LEN(sig)) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_verify_recover"); } out = ossl_str_new(NULL, (long)outlen, &state); if (state) { EVP_PKEY_CTX_free(ctx); rb_jump_tag(state); } if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen, (unsigned char *)RSTRING_PTR(sig), RSTRING_LEN(sig)) <= 0) { EVP_PKEY_CTX_free(ctx); ossl_raise(ePKeyError, "EVP_PKEY_verify_recover"); } EVP_PKEY_CTX_free(ctx); rb_str_set_len(out, outlen); return out; }