C# 如何从PEM文件中使用rsa解密

C# 如何从PEM文件中使用rsa解密,c#,encryption,cryptography,rsa,pem,C#,Encryption,Cryptography,Rsa,Pem,我使用以下c#代码使用rsa和PEM文件进行加密和解密: public string encrypt(string elementToEncrypt, string pathPrivateKey) { string pem = System.IO.File.ReadAllText(pathPrivateKey); byte[] Buffer = getBytesFromPEMFile(pem, "PUBLIC KEY"); System.Secur

我使用以下c#代码使用rsa和PEM文件进行加密和解密:

public string encrypt(string elementToEncrypt, string pathPrivateKey) {
        string pem = System.IO.File.ReadAllText(pathPrivateKey);
        byte[] Buffer = getBytesFromPEMFile(pem, "PUBLIC KEY");
        System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
        System.Security.Cryptography.RSAParameters rsaParam = rsa.ExportParameters(false);
        rsaParam.Modulus = Buffer;
        rsa.ImportParameters(rsaParam);
        byte[] encryptedMessageByte = rsa.Encrypt(Convert.FromBase64String(elementToEncrypt),false);
        return Convert.ToBase64String(encryptedMessageByte);
    }

public string decrypt(string elementToDesencrypt, string pathPublicKey)
    {
        string pem = System.IO.File.ReadAllText(pathPublicKey);
        byte[] Buffer = getBytesFromPEMFile(pem, "RSA PRIVATE KEY");
        System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
        System.Security.Cryptography.RSAParameters rsaParam = rsa.ExportParameters(false);
        rsaParam.Modulus = Buffer;
        rsa.ImportParameters(rsaParam);
        byte[] encryptedMessageByte = rsa.Decrypt(Convert.FromBase64String(elementToDesencrypt), false);
        return Convert.ToBase64String(encryptedMessageByte);
    }

public byte[] getBytesFromPEMFile(string pemString, string headerPEM) {
        string header = String.Format("-----BEGIN {0}-----", headerPEM);
        string footer = String.Format("-----END {0}-----", headerPEM);
        int start = pemString.IndexOf(header, StringComparison.Ordinal) + header.Length;
        int end = pemString.IndexOf(footer, start, StringComparison.Ordinal) - start;
        if (start < 0 || end < 0)
        {
            return null;
        }
        return Convert.FromBase64String(pemString.Substring(start, end));
    }
我得到的错误是密钥不存在。

我的pem文件是:

键。pem

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDLPKI8p+ANRabCTdLvJjuT0wx1kt2voJ0+BtdTRBqhJQbRgM2P
dtHilmaVSyiVtD5l1mTl+h8mFRBttiH0VgW3KuyvFk2mrjF78MrsXlYoHVizGgeh
UWVUsNh7EhdgF/hM7miZMXsHoa/MEQwgytPwjpDbOXXECZz8CpHiyNOftwIDAQAB
AoGAUrmXgAEFHeHgAu8SkO2LCpy5UZI6UiaaWokGVIpAHJ+pqtU21tKSlByMHPC+
0FDRpTojT8kDrMieK0obgA0TvcUaARVPGZsLjB4WZLKh7e8LPaUTvAS9dTmKd7xB
4YGFKY+AJb38VdDU9CoQMsiPtIIiPWz09lgGvYRGzXmTBwECQQDsEtLRyOijXISK
iFhtdpBI4yAmnTYyYLrsPXgS7asa80h7vnTmOlUpuqsxZtWNVGcpNiYG4y8OpJU5
Jr8IkNnXAkEA3GRC63+SEbEo5wXcrHF+tzxfFmk3yzS38w5jtGik3yrp6psyjaQ8
Q+D3RaKjGYtjTH3pmljRH2OGEvrNwvFtIQJAFkLgJnAvn9gFl5qr3AamLHleesWw
aqe8eLKDNCW9UNlIKIMZOuydQ0YbBpmP4bfn0ncMtvGNanASskT5FrGyGQJASE7k
3dsnE4LqhpGXy0QZbQjzsain05XiXG52K/TBUy8DPCPbPDmMREEFH+WyWWkwFSKi
iC9nvUKr9IIxDCqlwQJBAIDwEg6yVGdVCQry+OEGtsiaGPveX+lAx/kULba0wfRq
KaQAstQrT7p+ONtC8x8NHDE/ayjz6GlEZ7svR/LZO7w=
-----END RSA PRIVATE KEY-----
和pubkey.pem

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDLPKI8p+ANRabCTdLvJjuT0wx1
kt2voJ0+BtdTRBqhJQbRgM2PdtHilmaVSyiVtD5l1mTl+h8mFRBttiH0VgW3Kuyv
Fk2mrjF78MrsXlYoHVizGgehUWVUsNh7EhdgF/hM7miZMXsHoa/MEQwgytPwjpDb
OXXECZz8CpHiyNOftwIDAQAB
-----END PUBLIC KEY-----
我已经读到,如果我想解密,我应该把两个密钥都放在一个pem文件中,但如果我这么做了,我就不知道该放什么了

rsaParam.Modulus = Buffer;
我的意思是,我必须将两个缓冲区(私有和公共)混合到一个缓冲区中吗?如果是,我该怎么做


感谢您的帮助。

.NET没有内置的对读取“裸密钥”文件的支持

如果将公钥文件的Base64组件粘贴到,您将看到它可以分解为

SEQUENCE
  SEQUENCE
    OBJECT IDENTIFIER rsaEncryption
    NULL
  BIT STRING
    SEQUENCE
      INTEGER (1024-bit) ...
      INTEGER 65537
要将其导入.NET,您需要将第一个整数(本例中为1024位)的字节(而非十进制值)复制到rsaparters.module值中,并将第二个整数的字节复制到rsaparters.index值中。在这两种情况下,如果有一个前导的00字节,则需要将其关闭

对于当前密钥:

RSAParameters rsaParams = new RSAParameters
{
    Modulus = YourFavoriteHexParser(
        "CB3CA23CA7E00D45A6C24DD2EF263B93D30C7592DDAFA09D3E06D753441AA125" +
        "06D180CD8F76D1E29666954B2895B43E65D664E5FA1F2615106DB621F45605B7" +
        "2AECAF164DA6AE317BF0CAEC5E56281D58B31A07A1516554B0D87B12176017F8" +
        "4CEE6899317B07A1AFCC110C20CAD3F08E90DB3975C4099CFC0A91E2C8D39FB7"),
    Exponent = new byte[] { 0x01, 0x00, 0x01 },
};

RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParams);
return rsa;
更一般地说,您需要将公钥文件解析为ASN.1 DER blob,然后使用有效负载中的模数和指数值

如果需要多次使用,最简单的解决方法是使用OpenSSL为密钥文件生成自签名证书,因为.NET可以使用证书中的密钥(
cert.GetRSAPublicKey()

添加对裸键的支持在.NETCoreRoadmap()中,我们可以合理地假设,在将裸键添加到.NETCore之后,它将进入.NETFramework

要解密,您需要私钥。同样,最简单的答案是从密钥生成自签名证书,将证书和密钥捆绑到一个PFX/PKCS#12文件中,然后使用
cert.GetRSAPrivateKey()
。但是,尽管困难重重:

粘贴私钥blob时,我们看到它看起来像

SEQUENCE
  INTEGER 0
  INTEGER (1024-bit)
  INTEGER 65537
  INTEGER (1023-bit)
  INTEGER (512-bit)
  INTEGER (512-bit)
  INTEGER (509-bit)
  INTEGER (511-bit)
  INTEGER (512-bit)
RSAPrivateKey ::= SEQUENCE {
    version           Version,
    modulus           INTEGER,  -- n
    publicExponent    INTEGER,  -- e
    privateExponent   INTEGER,  -- d
    prime1            INTEGER,  -- p
    prime2            INTEGER,  -- q
    exponent1         INTEGER,  -- d mod (p-1)
    exponent2         INTEGER,  -- d mod (q-1)
    coefficient       INTEGER,  -- (inverse of q) mod p
    otherPrimeInfos   OtherPrimeInfos OPTIONAL
在中,我们看到
RSAPrivateKey
结构如下所示

SEQUENCE
  INTEGER 0
  INTEGER (1024-bit)
  INTEGER 65537
  INTEGER (1023-bit)
  INTEGER (512-bit)
  INTEGER (512-bit)
  INTEGER (509-bit)
  INTEGER (511-bit)
  INTEGER (512-bit)
RSAPrivateKey ::= SEQUENCE {
    version           Version,
    modulus           INTEGER,  -- n
    publicExponent    INTEGER,  -- e
    privateExponent   INTEGER,  -- d
    prime1            INTEGER,  -- p
    prime2            INTEGER,  -- q
    exponent1         INTEGER,  -- d mod (p-1)
    exponent2         INTEGER,  -- d mod (q-1)
    coefficient       INTEGER,  -- (inverse of q) mod p
    otherPrimeInfos   OtherPrimeInfos OPTIONAL
这个版本==0意味着只有两个素数。现在我们遇到了一些怪癖。在.NET中,
D
值的大小必须与
模数的大小相同。如果
D
恰好是“1016位”数字(或更小),则需要插入前导的
0x00
值。NET还要求
P
正好是
模数的一半(如果有必要,则取整),并且
Q
DP
DQ
InverseQ
都具有与
P
相同的大小

同样,对于您的密钥:

RSAParameters rsaParams = new RSAParameters
{
    Modulus = YourFavoriteHexParser(
        "CB3CA23CA7E00D45A6C24DD2EF263B93D30C7592DDAFA09D3E06D753441AA125" +
        "06D180CD8F76D1E29666954B2895B43E65D664E5FA1F2615106DB621F45605B7" +
        "2AECAF164DA6AE317BF0CAEC5E56281D58B31A07A1516554B0D87B12176017F8" +
        "4CEE6899317B07A1AFCC110C20CAD3F08E90DB3975C4099CFC0A91E2C8D39FB7"),
    Exponent = new byte[] { 0x01, 0x00, 0x01 },
    D = YourFavoriteHexParser(
        "52B9978001051DE1E002EF1290ED8B0A9CB951923A52269A5A8906548A401C9F" +
        "A9AAD536D6D292941C8C1CF0BED050D1A53A234FC903ACC89E2B4A1B800D13BD" +
        "C51A01154F199B0B8C1E1664B2A1EDEF0B3DA513BC04BD75398A77BC41E18185" +
        "298F8025BDFC55D0D4F42A1032C88FB482223D6CF4F65806BD8446CD79930701"),
    P = YourFavoriteHexParser(
        "EC12D2D1C8E8A35C848A88586D769048E320269D363260BAEC3D7812EDAB1AF3" +
        "487BBE74E63A5529BAAB3166D58D546729362606E32F0EA4953926BF0890D9D7"),
    Q = YourFavoriteHexParser(
        "DC6442EB7F9211B128E705DCAC717EB73C5F166937CB34B7F30E63B468A4DF2A" +
        "E9EA9B328DA43C43E0F745A2A3198B634C7DE99A58D11F638612FACDC2F16D21"),
    DP = YourFavoriteHexParser(
        "1642E026702F9FD805979AABDC06A62C795E7AC5B06AA7BC78B2833425BD50D9" +
        "482883193AEC9D43461B06998FE1B7E7D2770CB6F18D6A7012B244F916B1B219"),
    DQ = YourFavoriteHexParser(
        "484EE4DDDB271382EA869197CB44196D08F3B1A8A7D395E25C6E762BF4C1532F" +
        "033C23DB3C398C4441051FE5B25969301522A2882F67BD42ABF482310C2AA5C1"),
    InverseQ = YourFavoriteHexParser(
        "80F0120EB2546755090AF2F8E106B6C89A18FBDE5FE940C7F9142DB6B4C1F46A" +
        "29A400B2D42B4FBA7E38DB42F31F0D1C313F6B28F3E8694467BB2F47F2D93BBC"),
};

RSA rsa = RSA.Create();
rsa.ImportParameters(rsaParams);
return rsa;

我已经创建了一个用于读取和写入PEM/ASN.1编码文件的库。看

可以从NuGet安装:

PM> Install-Package PemUtils
用法

using (var stream = File.OpenRead(path))
using (var reader = new PemReader(stream))
{
    var rsaParameters = reader.ReadRsaKey();
    rsa.ImportParameters(rsaParameters);
}