如何使用公钥加密技术加密字符串

我正在尝试实现自己的RSA加密引擎。 鉴于这些RSA算法值:

p = 61. // A prime number. q = 53. // Also a prime number. n = 3233. // p * q. totient = 3120. // (p - 1) * (q - 1) e = 991. // Co-prime to the totient (co-prime to 3120). d = 1231. // d * e = 1219921, which is equal to the relation where 1 + k * totient = 1219921 when k = 391. 

我正在尝试编写一个方法来加密字符串中的每个字节并返回一个加密的字符串:

 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; } 

这里显而易见的问题是BigInteger.ModPow(bytes[i], e, n)可能太大而无法放入字节空间; 它可能导致大小超过8位的值。 如何解决这个问题,同时仍然能够将加密的字节串解密回常规字符串?

更新 :即使从byte []加密到byte [],您也会遇到使用RSA算法加密该字节超出字节大小限制的情况:

 public byte[] 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); } return bytes; } 

更新 :我的问题是加密会导致比初始输入字符串更多的字节:

 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; } 

如果你运行这样的代码:

 byte[] encryptedBytes = engine.Encrypt("Hello, world.", Encoding.UTF8); Console.WriteLine(engine.Decrypt(encryptedBytes, Encoding.UTF8)); 

输出将是这样的:

 ?♥D ?♥→☻►♦→☻►♦oD♦8? ?♠oj?♠→☻►♦;♂?♠♂♠?♠ 

显然,输出不是原始字符串,因为我不能一次尝试解密每个字节,因为有时两个或更多字节的密码表示我需要解密回一个字节的一个整数的值。原始字符串…所以我想知道处理这个的标准机制是什么。

你加密和解密每个字节的基本代码 – 对ModPow的调用 – 正在运行,但是你正在进行“不正确地分割消息和加密每个字节”。

为了表明ModPow部分 – 即数学 – 很好,这里的代码基于你的,它将string加密为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将byte[]加密到另一个byte[]中,包括所有不同的填充方案等。除了在每个字节上调用ModPow ,还有很多内容。

但重申一下,您应该这样做以最终生成生产RSA。 你没有任何安全漏洞的可能性非常小。 为了学术兴趣,了解密码学原理的更多信息,这样做很好,但是将实际的实现留给专家。 (我远非这个领域的专家 – 我无法开始实施自己的加密……)

如果您希望在C#中使用RSA加密,那么您不应该尝试构建自己的RSA加密。 对于初学者来说,你选择的素数可能很小。 P和Q应该是大素数。

你应该看看其他一些问题/答案:

如何使用RSA加密C#中的文件(海量数据)

C#中的大数据RSA加密

和其他参考: http : //msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.encrypt(v=vs.110).aspx

http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx

注意:我更新了这个答案。 请向下滚动到更新,了解它应该如何实现,因为这样做的第一种方法不是正确的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; } 

这有可能是跨平台的,因为您可以选择使用不同的数据类型来表示e或n,并将其传递给C#后端服务。 这是一个测试:

 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. 

更新 :我之前说过的所有内容在实施RSA时都是完全错误的。 错,错,错! 这是进行RSA加密的正确方法:

  • 将字符串转换为BigInteger数据类型。
  • 确保您的整数小于您为算法计算的n的值,否则您将无法对其进行decypher。
  • 加密整数。 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); } } } 

输出示例:

 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