无法在 C# 中解密由 openssl 完成的加密字符串。总是得到 Org.BouncyCastle.Security.InvalidKeyException
Cannot decrypt in C# an encrypted string done by openssl. Always get Org.BouncyCastle.Security.InvalidKeyException
我试图在 C# 中解密一个由 openssl 通过命令行加密的字符串,但它一直抛出以下异常:
Exception thrown: 'Org.BouncyCastle.Security.InvalidKeyException' in BouncyCastle.Crypto.dll
An unhandled exception of type 'Org.BouncyCastle.Security.InvalidKeyException' occurred in
BouncyCastle.Crypto.dll
Not an RSA key
我正在使用 RSA 加密,这些是我用来生成 .pem 文件和 encrypt/decrypt 测试字符串的命令(来自 git bash):
// Create private key
// openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out privkey.pem
// Create public key
// openssl pkey -pubout -in privkey.pem -out pubkey.pem
// "helloworld" as test text
// echo helloworld > clear_text.txt
// Encrypt using public key
// openssl rsautl -encrypt -inkey pubkey.pem -pubin -in clear_text.txt -out crypt.bin
// Decrypt using private key
// openssl rsautl -decrypt -inkey privkey.pem -in crypt.bin -out decrypt.txt
在 C# 中需要做的只是上面序列的最后一行,但在 C# 中。这是我用来加载 .pem 文件(由 openssl 生成)和解密字符串的 C# 代码。
static private PemReader publicKeyPemFile;
static private PemReader privateKeyPemFile;
static private string filesRootPath = System.IO.Directory.GetCurrentDirectory() + "/../../../";
static public void LoadKeys()
{
publicKeyPemFile = new PemReader(
(StreamReader)File.OpenText(filesRootPath + "pubkey.pem")
);
privateKeyPemFile = new PemReader(
(StreamReader)File.OpenText(filesRootPath + "privkey.pem")
);
}
static public string RSADecrypt(byte[] cipherTextBytes)
{
RsaKeyParameters keys = (RsaKeyParameters)privateKeyPemFile.ReadObject();
OaepEncoding eng = new OaepEncoding(new RsaEngine());
eng.Init(false, keys);
int length = cipherTextBytes.Length;
int blockSize = eng.GetInputBlockSize();
List<byte> plainTextBytes = new List<byte>();
for (int chunkPosition = 0;
chunkPosition < length;
chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, length - chunkPosition);
plainTextBytes.AddRange(eng.ProcessBlock(
cipherTextBytes, chunkPosition, chunkSize
));
}
string outString = Encoding.UTF8.GetString(plainTextBytes.ToArray());
return outString;
}
但是在尝试解密时失败,如下所示。
真正让我烦恼的是,如果我仅使用下面的加密方式使用 C# 进行加密和解密,它就可以工作。这是一个C#加密代码,使用openssl生成的.pem文件。
static public string RSAEncrypt(string clearText)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(clearText);
RsaKeyParameters keys = (RsaKeyParameters)publicKeyPemFile.ReadObject();
OaepEncoding eng = new OaepEncoding(new RsaEngine());
eng.Init(true, keys);
int length = plainTextBytes.Length;
int blockSize = eng.GetInputBlockSize();
List<byte> cipherTextBytes = new List<byte>();
for (int chunkPosition = 0;
chunkPosition < length;
chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, length - chunkPosition);
cipherTextBytes.AddRange(eng.ProcessBlock(
plainTextBytes, chunkPosition, chunkSize
));
}
return result;Convert.ToBase64String(cipherTextBytes.ToArray());
}
但是如果使用 openssl 加密并尝试使用 C# 解密总是崩溃。
最终测试程序
static void Main(string[] args)
{
RSAEncryption.LoadKeys();
RSAEncryption.TestRSAFromOpenSSL();
}
static public void TestRSAFromOpenSSL()
{
byte[] bytes = File.ReadAllBytes(filesRootPath + "crypt.bin");
string outString = RSADecrypt(bytes);
Debug.WriteLine("clear text = " + bytes.Length);
}
有什么线索吗?
谢谢。
我尝试用一段更简单的代码来复制您的问题,但我做不到。但是在尝试解密文本时出现错误。事实证明,我的 openssl
使用 pkcs1 作为默认编码而不是 oaep。当我改变它时,我让它工作了。
这是我的代码
byte[] cipherText = Convert.FromBase64String(File.ReadAllText("./crypt.bin"));
PemReader pr = new PemReader((StreamReader)File.OpenText("./privkey.pem"));
var keys = (RsaKeyParameters)pr.ReadObject();
var eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(false, keys);
var length = cipherText.Length;
var blockSize = eng.GetInputBlockSize();
var plainTextBytes = new List<byte>();
for (int chunkPosition = 0; chunkPosition < length; chunkPosition += blockSize)
{
var chunkSize = Math.Min(blockSize, length - chunkPosition);
plainTextBytes.AddRange(eng.ProcessBlock(cipherText, chunkPosition, chunkSize));
}
Console.WriteLine(Encoding.UTF8.GetString(plainTextBytes.ToArray()));
我 运行 在我的 Linux 盒子上通过 base64 编码加密文本,以减少 t运行 发送时出现任何错误的风险。我的代码使用 .NET core 3.1 和 Bouncy Castle Core 1.86。
您的代码中让我印象深刻的一件事是 LoadKeys 方法。它并没有真正加载密钥。它设置了一个可以加载密钥的 reader 。我的预感是,如果您两次请求同一个密钥,它将无法正常工作。你这样做吗?
我试图在 C# 中解密一个由 openssl 通过命令行加密的字符串,但它一直抛出以下异常:
Exception thrown: 'Org.BouncyCastle.Security.InvalidKeyException' in BouncyCastle.Crypto.dll
An unhandled exception of type 'Org.BouncyCastle.Security.InvalidKeyException' occurred in
BouncyCastle.Crypto.dll
Not an RSA key
我正在使用 RSA 加密,这些是我用来生成 .pem 文件和 encrypt/decrypt 测试字符串的命令(来自 git bash):
// Create private key
// openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:65537 -out privkey.pem
// Create public key
// openssl pkey -pubout -in privkey.pem -out pubkey.pem
// "helloworld" as test text
// echo helloworld > clear_text.txt
// Encrypt using public key
// openssl rsautl -encrypt -inkey pubkey.pem -pubin -in clear_text.txt -out crypt.bin
// Decrypt using private key
// openssl rsautl -decrypt -inkey privkey.pem -in crypt.bin -out decrypt.txt
在 C# 中需要做的只是上面序列的最后一行,但在 C# 中。这是我用来加载 .pem 文件(由 openssl 生成)和解密字符串的 C# 代码。
static private PemReader publicKeyPemFile;
static private PemReader privateKeyPemFile;
static private string filesRootPath = System.IO.Directory.GetCurrentDirectory() + "/../../../";
static public void LoadKeys()
{
publicKeyPemFile = new PemReader(
(StreamReader)File.OpenText(filesRootPath + "pubkey.pem")
);
privateKeyPemFile = new PemReader(
(StreamReader)File.OpenText(filesRootPath + "privkey.pem")
);
}
static public string RSADecrypt(byte[] cipherTextBytes)
{
RsaKeyParameters keys = (RsaKeyParameters)privateKeyPemFile.ReadObject();
OaepEncoding eng = new OaepEncoding(new RsaEngine());
eng.Init(false, keys);
int length = cipherTextBytes.Length;
int blockSize = eng.GetInputBlockSize();
List<byte> plainTextBytes = new List<byte>();
for (int chunkPosition = 0;
chunkPosition < length;
chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, length - chunkPosition);
plainTextBytes.AddRange(eng.ProcessBlock(
cipherTextBytes, chunkPosition, chunkSize
));
}
string outString = Encoding.UTF8.GetString(plainTextBytes.ToArray());
return outString;
}
但是在尝试解密时失败,如下所示。
真正让我烦恼的是,如果我仅使用下面的加密方式使用 C# 进行加密和解密,它就可以工作。这是一个C#加密代码,使用openssl生成的.pem文件。
static public string RSAEncrypt(string clearText)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(clearText);
RsaKeyParameters keys = (RsaKeyParameters)publicKeyPemFile.ReadObject();
OaepEncoding eng = new OaepEncoding(new RsaEngine());
eng.Init(true, keys);
int length = plainTextBytes.Length;
int blockSize = eng.GetInputBlockSize();
List<byte> cipherTextBytes = new List<byte>();
for (int chunkPosition = 0;
chunkPosition < length;
chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, length - chunkPosition);
cipherTextBytes.AddRange(eng.ProcessBlock(
plainTextBytes, chunkPosition, chunkSize
));
}
return result;Convert.ToBase64String(cipherTextBytes.ToArray());
}
但是如果使用 openssl 加密并尝试使用 C# 解密总是崩溃。
最终测试程序
static void Main(string[] args)
{
RSAEncryption.LoadKeys();
RSAEncryption.TestRSAFromOpenSSL();
}
static public void TestRSAFromOpenSSL()
{
byte[] bytes = File.ReadAllBytes(filesRootPath + "crypt.bin");
string outString = RSADecrypt(bytes);
Debug.WriteLine("clear text = " + bytes.Length);
}
有什么线索吗?
谢谢。
我尝试用一段更简单的代码来复制您的问题,但我做不到。但是在尝试解密文本时出现错误。事实证明,我的 openssl
使用 pkcs1 作为默认编码而不是 oaep。当我改变它时,我让它工作了。
这是我的代码
byte[] cipherText = Convert.FromBase64String(File.ReadAllText("./crypt.bin"));
PemReader pr = new PemReader((StreamReader)File.OpenText("./privkey.pem"));
var keys = (RsaKeyParameters)pr.ReadObject();
var eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(false, keys);
var length = cipherText.Length;
var blockSize = eng.GetInputBlockSize();
var plainTextBytes = new List<byte>();
for (int chunkPosition = 0; chunkPosition < length; chunkPosition += blockSize)
{
var chunkSize = Math.Min(blockSize, length - chunkPosition);
plainTextBytes.AddRange(eng.ProcessBlock(cipherText, chunkPosition, chunkSize));
}
Console.WriteLine(Encoding.UTF8.GetString(plainTextBytes.ToArray()));
我 运行 在我的 Linux 盒子上通过 base64 编码加密文本,以减少 t运行 发送时出现任何错误的风险。我的代码使用 .NET core 3.1 和 Bouncy Castle Core 1.86。
您的代码中让我印象深刻的一件事是 LoadKeys 方法。它并没有真正加载密钥。它设置了一个可以加载密钥的 reader 。我的预感是,如果您两次请求同一个密钥,它将无法正常工作。你这样做吗?