C# 如何使用公钥加密对字符串进行加密
我正在尝试实现自己的RSA加密引擎。考虑到这些值: 我试图编写一个方法来加密字符串中的每个字节并返回一个加密字符串:C# 如何使用公钥加密对字符串进行加密,c#,.net,encryption,rsa,public-key-encryption,C#,.net,Encryption,Rsa,Public Key Encryption,我正在尝试实现自己的RSA加密引擎。考虑到这些值: 我试图编写一个方法来加密字符串中的每个字节并返回一个加密字符串: public string Encrypt(string m, Encoding encoding) { byte[] bytes = encoding.GetBytes(m); for (int i = 0; i < bytes.Length; i++) { bytes[i] = (byte)BigInteger.ModPow(by
public string Encrypt(string m, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(m);
for (int i = 0; i < bytes.Length; i++)
{
bytes[i] = (byte)BigInteger.ModPow(bytes[i], e, n);
}
string encryptedString = encoding.GetString(bytes);
Console.WriteLine("Encrypted {0} as {1}.", m, encryptedString);
return encryptedString;
}
更新:我的问题是加密将导致比初始输入字符串更多的字节数:
public byte[] Encrypt(string m, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(m);
byte[] returnBytes = new byte[0];
for (int i = 0; i < bytes.Length; i++)
{
byte[] result = BigInteger.ModPow(bytes[i], (BigInteger)e, n).ToByteArray();
int preSize = returnBytes.Length;
Array.Resize(ref returnBytes, returnBytes.Length + result.Length);
result.CopyTo(returnBytes, preSize);
}
return returnBytes;
}
public string Decrypt(byte[] c, Encoding encoding)
{
byte[] returnBytes = new byte[0];
for (int i = 0; i < c.Length; i++)
{
byte[] result = BigInteger.ModPow(c[i], d, n).ToByteArray();
int preSize = returnBytes.Length;
Array.Resize(ref returnBytes, returnBytes.Length + result.Length);
result.CopyTo(returnBytes, preSize);
}
string decryptedString = encoding.GetString(returnBytes);
return decryptedString;
}
输出结果如下:
?♥D
?♥→☻►♦→☻►♦oD♦8? ?♠oj?♠→☻►♦;♂?♠♂♠?♠
显然,输出不是原始字符串,因为我不能一次解密每个字节,因为有时两个或更多字节的密码文本代表一个整数的值,我需要将其解密回原始字符串的一个字节……所以我想知道处理这个问题的标准机制是什么。如果您希望在C#中使用RSA加密,那么您不应该尝试构建自己的加密。首先,你选择的素数可能太小了。P和Q应该是大素数 您应该查看其他一些问题/答案: 及其他参考资料:
您加密和解密每个字节的基本代码-调用
ModPow
-正在工作,但您正在进行不适当的“拆分消息并加密每个字节”
为了证明ModPow
部分(即数学部分)是正确的,下面是基于您的代码,它将字符串
加密为BigInteger[]
并返回:
using System;
using System.Linq;
using System.Numerics;
using System.Text;
class Test
{
const int p = 61;
const int q = 53;
const int n = 3233;
const int totient = 3120;
const int e = 991;
const int d = 1231;
static void Main()
{
var encrypted = Encrypt("Hello, world.", Encoding.UTF8);
var decrypted = Decrypt(encrypted, Encoding.UTF8);
Console.WriteLine(decrypted);
}
static BigInteger[] Encrypt(string text, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(text);
return bytes.Select(b => BigInteger.ModPow(b, (BigInteger)e, n))
.ToArray();
}
static string Decrypt(BigInteger[] encrypted, Encoding encoding)
{
byte[] bytes = encrypted.Select(bi => (byte) BigInteger.ModPow(bi, d, n))
.ToArray();
return encoding.GetString(bytes);
}
}
接下来,您需要了解更多关于如何使用RSA将一个字节[]
加密为另一个字节[]
,包括所有不同的填充方案等。除了在每个字节上调用ModPow
,还有很多内容
但重申一下,您不应该这样做以生产RSA实现结束。在没有任何安全漏洞的情况下这样做的可能性确实很小。出于学术兴趣,学习更多关于密码学原理的知识,但将真正的实现留给专家,这样做很好。(我远非这一领域的专家-我不可能开始实施我自己的加密…注意:我更新了这个答案。请向下滚动至更新,了解其实际实现方式,因为第一种方式不是正确的RSA加密方式。 我认为这样做的一种方式是(但可能不符合标准),而且,请注意,这并没有:
public byte[] Encrypt(string m, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(m);
byte[] returnBytes = new byte[0];
for (int i = 0; i < bytes.Length; i++)
{
byte[] result = BigInteger.ModPow(bytes[i], (BigInteger)e, n).ToByteArray();
int preSize = returnBytes.Length;
Array.Resize(ref returnBytes, returnBytes.Length + result.Length + 1);
(new byte[] { (byte)(result.Length) }).CopyTo(returnBytes, preSize);
result.CopyTo(returnBytes, preSize + 1);
}
return returnBytes;
}
public string Decrypt(byte[] c, Encoding encoding)
{
byte[] returnBytes = new byte[0];
for (int i = 0; i < c.Length; i++)
{
int dataLength = (int)c[i];
byte[] result = new byte[dataLength];
for (int j = 0; j < dataLength; j++)
{
i++;
result[j] = c[i];
}
BigInteger integer = new BigInteger(result);
byte[] integerResult = BigInteger.ModPow(integer, d, n).ToByteArray();
int preSize = returnBytes.Length;
Array.Resize(ref returnBytes, returnBytes.Length + integerResult.Length);
integerResult.CopyTo(returnBytes, preSize);
}
string decryptedString = encoding.GetString(returnBytes);
return decryptedString;
}
输出:
Encrypting the string: Mary had a little lamb.
Encrypted text: ☻6☻1♦☻j☻☻&♀☻g♦☻t☻☻1♦☻? ☻g♦☻1♦☻g♦☻?♥☻?☻☻7☺☻7☺☻?♥☻?♂☻g♦☻?♥☻1♦☻$☺☻
c ☻?☻
Decrypted text: Mary had a little lamb.
更新:在RSA的实现过程中,我前面所说的一切都是完全错误的。错,错,错!这是执行RSA加密的正确方法:
- 将字符串转换为BigInteger数据类型
- 确保您的整数小于为算法计算的n值,否则将无法对其进行反分
- 加密整数。RSA仅适用于整数加密。这是清楚的
- 从加密的整数中解密它
- 我不禁想知道BigInteger类主要是为密码学而创建的
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace BytePadder
{
class Program
{
const int p = 61;
const int q = 53;
const int n = 3233;
const int totient = 3120;
const int e = 991;
const int d = 1231;
static void Main(string[] args)
{
// ---------------------- RSA Example I ----------------------
// Shows how an integer gets encrypted and decrypted.
BigInteger integer = 1000;
BigInteger encryptedInteger = Encrypt(integer);
Console.WriteLine("Encrypted Integer: {0}", encryptedInteger);
BigInteger decryptedInteger = Decrypt(encryptedInteger);
Console.WriteLine("Decrypted Integer: {0}", decryptedInteger);
// --------------------- RSA Example II ----------------------
// Shows how a string gets encrypted and decrypted.
string unencryptedString = "A";
BigInteger integer2 = new BigInteger(Encoding.UTF8.GetBytes(unencryptedString));
Console.WriteLine("String as Integer: {0}", integer2);
BigInteger encryptedInteger2 = Encrypt(integer2);
Console.WriteLine("String as Encrypted Integer: {0}", encryptedInteger2);
BigInteger decryptedInteger2 = Decrypt(encryptedInteger2);
Console.WriteLine("String as Decrypted Integer: {0}", decryptedInteger2);
string decryptedIntegerAsString = Encoding.UTF8.GetString(decryptedInteger2.ToByteArray());
Console.WriteLine("Decrypted Integer as String: {0}", decryptedIntegerAsString);
Console.ReadLine();
}
static BigInteger Encrypt(BigInteger integer)
{
if (integer < n)
{
return BigInteger.ModPow(integer, e, n);
}
throw new Exception("The integer must be less than the value of n in order to be decypherable!");
}
static BigInteger Decrypt(BigInteger integer)
{
return BigInteger.ModPow(integer, d, n);
}
}
}
首先让您的加密工作在
byte[]
到byte[]
模式。然后担心文本转换。它们是完全独立的-您不应该对实际不是编码文本的数据使用Encoding.GetString
。(我假设您只是为了学术目的而实现此功能?如果您是为了生产目的而实现此功能,请立即停止并使用由专家创建的实现。)@JonSkeet是的,您是对的……Encoding.GetString可能会导致丢失,因为该编码可能不支持特定的字节值。@JonSkeet即使在byte[]到byte[]模式下,您将遇到这样的情况:使用RSA加密算法加密一个字节超出了一个字节的大小限制。我将更新这个问题。biginger.ToByteArray()会有所帮助,但在某些情况下会增加返回字节数组中的元素数。它需要一种机制来确定字节字符串是否有额外的元素。所以你告诉我的是,无论我使用的是由专家创建的什么实现,它们都永远不会相互兼容?换句话说,我可以用一个专家的算法加密,但我不一定能用另一个专家的算法解密密码文本?我从来没有说过这样的话。正确的实现应该是兼容的。我看不出这和你问题中的其他任何东西有什么关系。但是,我要再次提醒您,不要对任何稍微敏感的内容使用业余加密实现。正确处理这类事情是很困难的。对,所以在您的示例中,您加密到一个BigInteger数据类型的数组,然后将其解密回原始字符串。但是,这将不具有本机跨平台支持,因为我无法在其他平台本机使用BigInteger数据类型,因此我无法创建BigInteger数组,以便通过网络层发送,以便从非C设备解密,就像一个iOS应用程序…这仍然会迫使我找到一种方法来加密字节,然后发送加密的字节。现在我想起来了,我可以在每个整数之前有一个字节,表示需要合成成ByTestStream然后解密的字节长度。等我把答案弄清楚后,我再贴一点。不知道该怎么解释……很难用语言表达……等等……当我把代码贴出来时,我会告诉你我的意思……@Alexandru:是的,你可以。然而,这并不是很安全,因为您要分别加密每个字节。任何可以查看加密数据的人都可以发现重复的字节。现在还不清楚你是出于兴趣还是希望在现实世界中使用它。(只是不要;请不要)如果我说这是为了生产,你就不要再帮我了
public byte[] Encrypt(string m, Encoding encoding)
{
byte[] bytes = encoding.GetBytes(m);
byte[] returnBytes = new byte[0];
for (int i = 0; i < bytes.Length; i++)
{
byte[] result = BigInteger.ModPow(bytes[i], (BigInteger)e, n).ToByteArray();
int preSize = returnBytes.Length;
Array.Resize(ref returnBytes, returnBytes.Length + result.Length + 1);
(new byte[] { (byte)(result.Length) }).CopyTo(returnBytes, preSize);
result.CopyTo(returnBytes, preSize + 1);
}
return returnBytes;
}
public string Decrypt(byte[] c, Encoding encoding)
{
byte[] returnBytes = new byte[0];
for (int i = 0; i < c.Length; i++)
{
int dataLength = (int)c[i];
byte[] result = new byte[dataLength];
for (int j = 0; j < dataLength; j++)
{
i++;
result[j] = c[i];
}
BigInteger integer = new BigInteger(result);
byte[] integerResult = BigInteger.ModPow(integer, d, n).ToByteArray();
int preSize = returnBytes.Length;
Array.Resize(ref returnBytes, returnBytes.Length + integerResult.Length);
integerResult.CopyTo(returnBytes, preSize);
}
string decryptedString = encoding.GetString(returnBytes);
return decryptedString;
}
string stringToEncrypt = "Mary had a little lamb.";
Console.WriteLine("Encrypting the string: {0}", stringToEncrypt);
byte[] encryptedBytes = engine.Encrypt(stringToEncrypt, Encoding.UTF8);
Console.WriteLine("Encrypted text: {0}", Encoding.UTF8.GetString(encryptedBytes));
Console.WriteLine("Decrypted text: {0}", engine.Decrypt(encryptedBytes, Encoding.UTF8));
Encrypting the string: Mary had a little lamb.
Encrypted text: ☻6☻1♦☻j☻☻&♀☻g♦☻t☻☻1♦☻? ☻g♦☻1♦☻g♦☻?♥☻?☻☻7☺☻7☺☻?♥☻?♂☻g♦☻?♥☻1♦☻$☺☻
c ☻?☻
Decrypted text: Mary had a little lamb.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace BytePadder
{
class Program
{
const int p = 61;
const int q = 53;
const int n = 3233;
const int totient = 3120;
const int e = 991;
const int d = 1231;
static void Main(string[] args)
{
// ---------------------- RSA Example I ----------------------
// Shows how an integer gets encrypted and decrypted.
BigInteger integer = 1000;
BigInteger encryptedInteger = Encrypt(integer);
Console.WriteLine("Encrypted Integer: {0}", encryptedInteger);
BigInteger decryptedInteger = Decrypt(encryptedInteger);
Console.WriteLine("Decrypted Integer: {0}", decryptedInteger);
// --------------------- RSA Example II ----------------------
// Shows how a string gets encrypted and decrypted.
string unencryptedString = "A";
BigInteger integer2 = new BigInteger(Encoding.UTF8.GetBytes(unencryptedString));
Console.WriteLine("String as Integer: {0}", integer2);
BigInteger encryptedInteger2 = Encrypt(integer2);
Console.WriteLine("String as Encrypted Integer: {0}", encryptedInteger2);
BigInteger decryptedInteger2 = Decrypt(encryptedInteger2);
Console.WriteLine("String as Decrypted Integer: {0}", decryptedInteger2);
string decryptedIntegerAsString = Encoding.UTF8.GetString(decryptedInteger2.ToByteArray());
Console.WriteLine("Decrypted Integer as String: {0}", decryptedIntegerAsString);
Console.ReadLine();
}
static BigInteger Encrypt(BigInteger integer)
{
if (integer < n)
{
return BigInteger.ModPow(integer, e, n);
}
throw new Exception("The integer must be less than the value of n in order to be decypherable!");
}
static BigInteger Decrypt(BigInteger integer)
{
return BigInteger.ModPow(integer, d, n);
}
}
}
Encrypted Integer: 1989
Decrypted Integer: 1000
String as Integer: 65
String as Encrypted Integer: 1834
String as Decrypted Integer: 65
Decrypted Integer as String: A