简体   繁体   English

如何验证 RSA 公钥?

[英]How to validate an RSA public key?

If I receive a PEM-encoded key, I can import it like so:如果我收到一个 PEM 编码的密钥,我可以像这样导入它:

    using var rsa = new RSACryptoServiceProvider(2048);
    rsa.ImportFromPem(keyString.AsSpan());
    // do stuff with it

However, the documentation for ImportFromPem states that it will indiscriminately accept four key types: PUBLIC KEY, PRIVATE KEY, RSA PRIVATE KEY, RSA PUBLIC KEY, and that "Unsupported or malformed PEM-encoded objects will be ignored."然而, ImportFromPem的文档声明它将不加区别地接受四种密钥类型:PUBLIC KEY、PRIVATE KEY、RSA PRIVATE KEY、RSA PUBLIC KEY,并且“不支持或格式错误的 PEM 编码对象将被忽略”。

If I want to verify that 1) what I received is a public key and not a private key, and 2) it's a valid public key and not an "Unsupported or malformed PEM-encoded object," how would I go about doing that?如果我想验证 1) 我收到的是公钥而不是私钥,并且 2) 它是有效的公钥而不是“不受支持或格式错误的 PEM 编码 object”,我将如何 go 这样做?

The successful import with the posted code also means a formal validation of the RSA key.使用发布的代码成功导入也意味着对 RSA 密钥的正式验证。 The key can be imported:可以导入密钥:

  • if it is an RSA key.如果它是 RSA 密钥。
  • if the key contains one of the labels supported for RSA (ie PUBLIC KEY (SPKI), RSA PUBLIC KEY (public PKCS#1), PRIVATE KEY (PKCS#8), RSA PRIVTE KEY (private PKCS#1)).如果密钥包含 RSA 支持的标签之一(即 PUBLIC KEY (SPKI)、RSA PUBLIC KEY (public PKCS#1)、PRIVATE KEY (PKCS#8)、RSA PRIVTE KEY (private PKCS#1))。
  • if the body consists of a valid (Base64 encoded) ASN.1/DER.如果正文包含有效(Base64 编码)ASN.1/DER。
  • if the label is consistent with the key contained in the body (both by type (public/private) and format (PKCS#1/PKCS#8/SPKI)).如果 label 与正文中包含的密钥一致(按类型(公共/私有)和格式(PKCS#1/PKCS#8/SPKI))。

There is no guarantee that the parameters are validated contentwise for consistency (eg in the case of a private key, the modulus might well not be equal to the product of p and q).不能保证参数在内容方面被验证保持一致性(例如,在私钥的情况下,模数可能不等于 p 和 q 的乘积)。 Among other things, this depends on the platform (eg Windows or Unix).除其他事项外,这取决于平台(例如 Windows 或 Unix)。 Thus, if guaranteed validation of the parameters is required, the parameters must be explicitly validated.因此,如果需要保证参数的验证,则必须显式验证参数。
Explicit validation of the parameters is possible by exporting the RSA parameters with ExportParameters() and then validating them.通过使用ExportParameters()导出RSA 参数然后验证它们,可以显式验证参数。 This is relevant for private keys, where the parameters are dependent on each other, so that these consistencies can be tested (eg whether the modulus is equal to the product of the two primes).这与私钥相关,其中参数相互依赖,因此可以测试这些一致性(例如,模数是否等于两个素数的乘积)。 There are no such consistency checks for public keys.公钥没有这样的一致性检查。
Since this question is about public keys, the checks for private keys are not necessary (and could be omitted).由于这个问题是关于公钥的,因此不需要检查私钥(也可以省略)。

For a key imported this way, PublicOnly can be used to check whether it is a private or public key.对于以这种方式导入的密钥,可以使用PublicOnly来检查它是私钥还是公钥。

This makes it relatively easy to create a logic for RSA key validation, eg:这使得为 RSA 密钥验证创建逻辑变得相对容易,例如:

using System.Numerics;
using System.Security.Cryptography;
...
private static void ImportPublicKey(string key)
{
    using var rsa = new RSACryptoServiceProvider();
    try
    {
        rsa.ImportFromPem(key.AsSpan());
        if (rsa.PublicOnly)
        {
            Console.WriteLine("Public RSA key");
        }
        else
        {
            // Explicit check of the consistency of the parameters for private keys, for example N = p*q
            var rsaParams = rsa.ExportParameters(true);
            BigInteger m = new BigInteger(rsaParams.Modulus, true, true);
            BigInteger p = new BigInteger(rsaParams.P, true, true);
            BigInteger q = new BigInteger(rsaParams.Q, true, true);
            Console.WriteLine("Private RSA key - params " + (p*q==m ? "consistent" : "not consistent"));
        }
    }
    catch
    {
        Console.WriteLine("Invalid or inconsistent RSA key");
    }
}

First of all, it depends on why you want to validate the public key.首先,这取决于您为什么要验证公钥。 You should not expect an adversary to deliberately send a bad key.你不应该期望对手故意发送错误的密钥。 If they can do that they can simply send you the wrong key.如果他们可以做到这一点,他们可以简单地向您发送错误的密钥。 To prevent that you need a better way of managing keys, such as using certificates within a Public Key Infrastructure or PKI.为防止出现这种情况,您需要一种更好的方式来管理密钥,例如在公钥基础设施或 PKI 中使用证书。

Great, that out of the way, I'd like to indicate that all the defined PEM keys contain a public key.太好了,顺便说一下,我想指出所有定义的 PEM 密钥都包含一个公钥。 RSA PUBLIC KEY is a PKCS#1 defined public key and RSA PRIVATE KEY is a PKCS#1 private key. RSA PUBLIC KEY是 PKCS#1 定义的公钥, RSA PRIVATE KEY是 PKCS#1 私钥。 However, the definition of the private key also contains the public exponent .但是,私钥的定义也包含了公共指数 Similarly, PUBLIC KEY is a SubjectPublicKeyInfo structure and PRIVATE KEY is a PKCS#8 defined private key.同样, PUBLIC KEY是一个SubjectPublicKeyInfo结构,而PRIVATE KEY是一个 PKCS#8 定义的私钥。 Both contain PKCS#1 key structures inside and therefore the public key.两者都在内部包含PKCS#1 密钥结构,因此包含公钥。

Maybe you suspect that the public key in the instance is not replaced.也许你怀疑实例中的公钥没有被替换。 That is certainly a possible option if I read the documentation correctly (the quality of the Microsoft documentation is often, uh, questionable though).如果我正确阅读了文档,那当然是一个可能的选择(尽管 Microsoft 文档的质量通常是有问题的)。 In that case you might want to validate that the modulus changes value.在这种情况下,您可能想要验证模数是否更改了值。 The modulus is specific for each key pair and it is contained in both public and private keys.模数特定于每个密钥对,并且包含在公钥和私钥中。 You can access the modulus using ExportParameters(false).Modulus .您可以使用ExportParameters(false).Modulus访问模数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM