使用 RSA 公钥解密使用 RSA 私钥加密的字符串

时间:2023-03-28
本文介绍了使用 RSA 公钥解密使用 RSA 私钥加密的字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我知道我可能得到的主要答案是你为什么要这么做?!

I know the main answer I am likely to get is why the hell would you want to do that?!

不幸的是,尽管我提出了抗议,但我还是不得不这样做,尽管我知道这毫无意义.

Unfortunately despite my protests I have to do it, even though I know it makes little sense.

我有用 .Net 编写的函数,可以使用私钥解密,使用公钥加密.我还进行了 RSA 签名和验证,并且对我认为这一切是如何工作的有一个合理的理解.

I have functions written in .Net to decrypt using a private key, encrypt using a public key. I also RSA sign and verify and have a reasonable understanding of how this all work I think.

我现在收到一个使用私钥进行 RSA 加密的值,我应该通过使用公钥解密来导出可用值.

I am now being sent a value that is RSA encrypted using a private key which I am supposed to derive a usable value by decrypting using the public key.

我似乎无法弄清楚如何做到这一点.我是个白痴吗?这是正常的做法吗?

I can't seem to figure out how to do this. Am I being an idiot? Is this a normal thing to do?

向我发送值的人告诉我,这在 PHP 中没有问题.我不知道也没有使用过PHP.我找不到使用我知道的任何主要语言(即 C++、Java、C#)的库.我正在使用的服务器使用 .Net.

I am told by the person sending me the value that this is no problem in PHP. I don't know and haven't used PHP yet. I can't find a library to do it in any of the main languages I know i.e. C++, Java, C#. The server I am working on uses .Net.

我希望有人可以帮助我.

I am hoping someone might be able help me.

如果除了乞求他们改变他们正在做的事情之外,还有某种合理的解决方案,那就太好了.

It would be great if there is some kind of reasonable solution besides begging them to change what they are doing.

这是我的方法(从 Iridium 指出的我以前的坏方法更新)但是当我尝试解密该值时,我得到一个异常

This is my method (updated from my previous bad one as pointed out by Iridium) but when I try to decrypt the value I get an exception

解码 OAEP 填充时出错."

"Error occurred while decoding OAEP padding."

如果我使用 rsa.Decrypt(bytes, false) 我会得到一个错误的密钥异常.

If I use rsa.Decrypt(bytes, false) I get a bad key exception.

public static string DecryptUsingPublic(string dataEncrypted, string publicKey)
    {
        if (dataEncrypted == null) throw new ArgumentNullException("dataEncrypted");
        if (publicKey == null) throw new ArgumentNullException("publicKey");
        try
        {
            RSAParameters _publicKey = LoadRsaPublicKey(publicKey, false);
            RSACryptoServiceProvider rsa = InitRSAProvider(_publicKey);

            byte[] bytes = Convert.FromBase64String(dataEncrypted);
            byte[] decryptedBytes = rsa.Decrypt(bytes, true);

            ArrayList arrayList = new ArrayList();
            arrayList.AddRange(decryptedBytes);

           return Encoding.UTF8.GetString(decryptedBytes);
        }
        catch
        {
            return null;
        }
    }

    private static RSAParameters LoadRsaPublicKey(String publicKeyFilePath, Boolean isFile)
    {
        RSAParameters RSAKeyInfo = new RSAParameters();
        byte[] pubkey = ReadFileKey(publicKeyFilePath, "PUBLIC KEY", isFile);
        byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
        byte[] seq = new byte[15];
        // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
        MemoryStream mem = new MemoryStream(pubkey);
        BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading
        byte bt = 0;
        ushort twobytes = 0;

        try
        {

            twobytes = binr.ReadUInt16();
            if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                binr.ReadByte();    //advance 1 byte
            else if (twobytes == 0x8230)
                binr.ReadInt16();   //advance 2 bytes
            else
                return RSAKeyInfo;

            seq = binr.ReadBytes(15);       //read the Sequence OID
            if (!CompareBytearrays(seq, SeqOID))    //make sure Sequence for OID is correct
                return RSAKeyInfo;

            twobytes = binr.ReadUInt16();
            if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
                binr.ReadByte();    //advance 1 byte
            else if (twobytes == 0x8203)
                binr.ReadInt16();   //advance 2 bytes
            else
                return RSAKeyInfo;

            bt = binr.ReadByte();
            if (bt != 0x00)     //expect null byte next
                return RSAKeyInfo;

            twobytes = binr.ReadUInt16();
            if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                binr.ReadByte();    //advance 1 byte
            else if (twobytes == 0x8230)
                binr.ReadInt16();   //advance 2 bytes
            else
                return RSAKeyInfo;

            twobytes = binr.ReadUInt16();
            byte lowbyte = 0x00;
            byte highbyte = 0x00;

            if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
                lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
            else if (twobytes == 0x8202)
            {
                highbyte = binr.ReadByte(); //advance 2 bytes
                lowbyte = binr.ReadByte();
            }
            else
                return RSAKeyInfo;
            byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
            int modsize = BitConverter.ToInt32(modint, 0);

            byte firstbyte = binr.ReadByte();
            binr.BaseStream.Seek(-1, SeekOrigin.Current);

            if (firstbyte == 0x00)
            {   //if first byte (highest order) of modulus is zero, don't include it
                binr.ReadByte();    //skip this null byte
                modsize -= 1;   //reduce modulus buffer size by 1
            }

            byte[] modulus = binr.ReadBytes(modsize);   //read the modulus bytes

            if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
                return RSAKeyInfo;
            int expbytes = (int)binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
            byte[] exponent = binr.ReadBytes(expbytes);


            RSAKeyInfo.Modulus = modulus;
            RSAKeyInfo.Exponent = exponent;

            return RSAKeyInfo;
        }
        catch (Exception)
        {
            return RSAKeyInfo;
        }

        finally { binr.Close(); }
        //return RSAparams;

    }

 private static RSACryptoServiceProvider InitRSAProvider(RSAParameters rsaParam)
    {
        //
        // Initailize the CSP
        //   Supresses creation of a new key
        //
        CspParameters csp = new CspParameters();
        //csp.KeyContainerName = "RSA Test (OK to Delete)";

        const int PROV_RSA_FULL = 1;
        csp.ProviderType = PROV_RSA_FULL;

        const int AT_KEYEXCHANGE = 1;
        // const int AT_SIGNATURE = 2;
        csp.KeyNumber = AT_KEYEXCHANGE;
        //
        // Initialize the Provider
        //
        RSACryptoServiceProvider rsa =
          new RSACryptoServiceProvider(csp);
        rsa.PersistKeyInCsp = false;

        //
        // The moment of truth...
        //
        rsa.ImportParameters(rsaParam);
        return rsa;
    }

    private static int GetIntegerSize(BinaryReader binr)
    {
        byte bt = 0;
        byte lowbyte = 0x00;
        byte highbyte = 0x00;
        int count = 0;
        bt = binr.ReadByte();
        if (bt != 0x02)     //expect integer
            return 0;
        bt = binr.ReadByte();

        if (bt == 0x81)
            count = binr.ReadByte();    // data size in next byte
        else
            if (bt == 0x82)
            {
                highbyte = binr.ReadByte(); // data size in next 2 bytes
                lowbyte = binr.ReadByte();
                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
                count = BitConverter.ToInt32(modint, 0);
            }
            else
            {
                count = bt;     // we already have the data size
            }

        while (binr.ReadByte() == 0x00)
        {   //remove high order zeros in data
            count -= 1;
        }
        binr.BaseStream.Seek(-1, SeekOrigin.Current);       //last ReadByte wasn't a removed zero, so back up a byte
        return count;
    }

    private static bool CompareBytearrays(byte[] a, byte[] b)
    {
        if (a.Length != b.Length)
            return false;
        int i = 0;
        foreach (byte c in a)
        {
            if (c != b[i])
                return false;
            i++;
        }
        return true;
    }

InitRSAProvider 和 LoadRsaPublicKey 上面的两种方法已从教程中删除,以允许 PEM 密钥作为字符串用于 .Net.

The two methods above InitRSAProvider and LoadRsaPublicKey were gotten out of tutorials to allow PEM keys as Strings to be used with .Net.

推荐答案

查看了一些关于 RSA 加密模式的信息,看起来 PKCS#1 v1.5(你正在使用,因为你是调用 Decrypt(..., false))

Having looked at some of the information on RSA encryption modes, it would appear that PKCS#1 v1.5 (which you're using, because you're calling Decrypt(..., false))

"...可以对长度为 最多 k - 11 个八位字节的消息进行操作(k 是 RSA 模数的八位字节长度)"

"...can operate on messages of length up to k - 11 octets (k is the octet length of the RSA modulus)"

(RFC 3447,强调我的).

(RFC 3447, emphasis mine).

根据指示您的密钥为 128 字节的错误消息,这意味着您无法使用 PKCS#1 v1.5 对超过 128 - 11 = 的消息执行 RSA (en|de)cryption117 字节.

Based on the error message, which indicates that your key is 128 bytes, that means that you can't perform RSA (en|de)cryption using PKCS#1 v1.5 on a message with more than 128 - 11 = 117 bytes.

您不应直接使用 RSA 加密您的消息,而应使用对称算法加密消息正文,并仅使用 RSA 加密对称加密密钥.只有当您的消息相当短(即您的密钥大小低于 117 字节)时,您才应考虑直接使用 RSA 加密消息.

Instead of encrypting your message directly using RSA, you should be using a symmetric algorithm to encrypt the body of the message, and encrypt only the symmetric encryption key using RSA. Only if your message is reasonably short (i.e. below 117 bytes for your key size) should you consider encrypting the message directly with RSA.

我添加了以下内容,假设您的输入是 Base64 编码的,正如您在下面的评论中指出的那样:

I have added the following, assuming that your input is Base64 encoded as you indicate in your comment below:

public string DecryptUsingPublic(string dataEncryptedBase64, string publicKey)
    {
        if (dataEncryptedBase64 == null) throw new ArgumentNullException("dataEncryptedBase64");
        if (publicKey == null) throw new ArgumentNullException("publicKey");
        try
        {
            RSAParameters _publicKey = LoadRsaPublicKey(publicKey, false);
            RSACryptoServiceProvider rsa = InitRSAProvider(_publicKey);

            byte[] bytes = Convert.FromBase64String(dataEncryptedBase64);
            byte[] decryptedBytes = rsa.Decrypt(bytes, false);

            // I assume here that the decrypted data is intended to be a
            // human-readable string, and that it was UTF8 encoded.
            return Encoding.UTF8.GetString(decryptedBytes);
        }
        catch
        {
            return null;
        }
    }

这篇关于使用 RSA 公钥解密使用 RSA 私钥加密的字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:C# BouncyCastle - 使用公钥/私钥的 RSA 加密 下一篇:如何在 .NET 中加密字符串?

相关文章