使用给定的模数和指数加密字符串。

huangapple go评论87阅读模式
英文:

Encrypt string using given modulus and exponent

问题

以下是您提供的代码部分的翻译结果:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace RSACypherTest
{
    public class Program
    {
        public static RSACryptoServiceProvider rsa;
        static void Main(string[] args)
        {
            string str = "1234";
            string publicRSA = "010001|0097152d7034a8b48383d3dba20c43d049";
            string encrypted = "";
            Console.WriteLine("Original text: " + str);
            encrypted = Encrypt(str, publicRSA);
            Console.WriteLine("Encrypted text: " + encrypted);
            Console.ReadLine();
        }
        public static string Encrypt(string str, string PublicRSA)
        {
            string[] Separated = PublicRSA.Split('|');
            RsaKeyParameters pubParameters = MakeKey(Separated[1], Separated[0], false);
            IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine());
            eng.Init(true, pubParameters);
            byte[] plaintext = Encoding.UTF8.GetBytes(Reverse(str));
            byte[] encdata = eng.ProcessBlock(plaintext, 0, plaintext.Length);
            return ByteArrayToString(encdata);
        }
        public static string Reverse(string s)
        {
            char[] charArray = s.ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }
        public static string ByteArrayToString(byte[] ba)
        {
            return BitConverter.ToString(ba).Replace("-", "");
        }
        public static byte[] StringToByteArray(string hex)
        {
            int NumberChars = hex.Length;
            byte[] bytes = new byte[NumberChars / 2];
            for (int i = 0; i < NumberChars; i += 2)
                bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
            return bytes;
        }
        private static RsaKeyParameters MakeKey(string modulusHexString, string exponentHexString, bool isPrivateKey)
        {
            var modulus = new BigInteger(modulusHexString, 16);
            var exponent = new BigInteger(exponentHexString, 16);
            return new RsaKeyParameters(isPrivateKey, modulus, exponent);
        }
    }
}

请注意,由于代码涉及了一些专有术语和编程概念,翻译可能不会与原始代码的结构和语法完全一致。如果您在使用翻译后的代码时遇到任何问题,请随时向我提问。

英文:

I need to replicate the functionality of the following JAVA code that receives a string with the exponent and modulus of a public key to generate a public key with said parameters and encrypt a string:

package snippet;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.Security;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import javax.crypto.Cipher;
public class Snippet {
public static void main(String ... strings) {
try {
// Needed if you don&#39;t have this provider
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//String and received public key example
String ReceivedString = &quot;1234&quot;;
String publicRSA = &quot;010001|0097152d7034a8b48383d3dba20c43d049&quot;;
EncryptFunc(ReceivedString, publicRSA);
//The result obtained from the ReceivedString and the publicRSA is as follows:
//Result in hex [1234] -&gt; [777786fe162598689a8dc172ed9418cb]
} catch (Exception ex) {
System.out.println(&quot;Error: &quot; );
ex.printStackTrace();
}
}
public static String EncryptFunc(String ReceivedString, String clavePublica) throws Exception {
String result = &quot;&quot;;
//We separate the received public string into exponent and modulus
//We receive it as &quot;exponent|modulus&quot;
String[] SplitKey = clavePublica.split(&quot;\\|&quot;);
KeyFactory keyFactory = KeyFactory.getInstance(&quot;RSA&quot;,&quot;BC&quot;);
RSAPublicKeySpec ks = new RSAPublicKeySpec(new BigInteger(hex2byte(SplitKey[1])), new BigInteger(hex2byte(SplitKey[0])));
//With these specs, we generate the public key
RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(ks);
//We instantiate the cypher, with the EncryptFunc and the obtained public key
Cipher cipher= Cipher.getInstance(&quot;RSA/None/NoPadding&quot;,&quot;BC&quot;);
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
//We reverse the ReceivedString and encrypt it
String ReceivedStringReverse = reverse(ReceivedString);
byte[] cipherText2 = cipher.doFinal(ReceivedStringReverse.getBytes(&quot;UTF8&quot;));
result = byte2hex(cipherText2);
System.out.println(&quot;result in hex [&quot;+ReceivedString+&quot;] -&gt; [&quot;+result+&quot;]&quot;);
return result;
}
public static byte[] hex2byte(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i &lt; len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) &lt;&lt; 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static String byte2hex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte aByte : bytes) {
result.append(String.format(&quot;%02x&quot;, aByte));
// upper case
// result.append(String.format(&quot;%02X&quot;, aByte));
}
return result.toString();
}
public static String reverse(String source) {
int i, len = source.length();
StringBuilder dest = new StringBuilder(len);
for (i = (len - 1); i &gt;= 0; i--){
dest.append(source.charAt(i));
}
return dest.toString();
}
}

I've tried several approaches with this one, And I have done some searching here, here, here, here and here.

I Managed to create the public key with the given parameters, but the results are always different when I encrypt the string:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace RSACypherTest
{
public class Program
{
public static RSACryptoServiceProvider rsa;
static void Main(string[] args)
{
string str = &quot;1234&quot;;
string publicRSA = &quot;010001|0097152d7034a8b48383d3dba20c43d049&quot;;
string encrypted = &quot;&quot;;
Console.WriteLine(&quot;Original text: &quot; + str);
encrypted = Encrypt(str, publicRSA);
Console.WriteLine(&quot;Encrypted text: &quot; + encrypted);
Console.ReadLine();
}
public static string Encrypt(string str, string PublicRSA)
{
string[] Separated = PublicRSA.Split(&#39;|&#39;);
RsaKeyParameters pubParameters = MakeKey(Separated[1], Separated[0], false);
IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(true, pubParameters);
byte[] plaintext = Encoding.UTF8.GetBytes(Reverse(str));
byte[] encdata = eng.ProcessBlock(plaintext, 0, plaintext.Length);
return ByteArrayToString(encdata);
}
public static string Reverse(string s)
{
char[] charArray = s.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}
public static string ByteArrayToString(byte[] ba)
{
return BitConverter.ToString(ba).Replace(&quot;-&quot;, &quot;&quot;);
}
public static byte[] StringToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i &lt; NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
private static RsaKeyParameters MakeKey(string modulusHexString, string exponentHexString, bool isPrivateKey)
{
var modulus = new BigInteger(modulusHexString, 16);
var exponent = new BigInteger(exponentHexString, 16);
return new RsaKeyParameters(isPrivateKey, modulus, exponent);
}
}
}

I'm trying to use BouncyCastle because it seems to be the most effcient way of dealing with the key generation and everything. Any help concerning this would be very much appreciated.

Thanks in advance.

答案1

得分: 1

这不是你问题的答案,但可能有助于你理解 RSA 加密。

我在 C# 中设置了一个示例加密程序,并使用了你提供的公钥(将 BigInteger 模数和指数转换为 Base64 值,然后只是将公钥的 XML 字符串表示写入以便用于加密)。密钥长度适用于最多 5 字节的数据长度。

当运行加密程序 5 次时,每次运行都会得到不同的 encodedData(这里使用 Base64 编码)。所以这是 RSA 加密的预期行为。

由于 C# 允许我“构建”一个短密钥,因此不可能生成这样长度的新密钥对,我怀疑 Bouncy Castle 也不会这样做(但在 Stack Overflow 上有很多对 BC 有更好理解的同行 :-))。

如果你想要这个程序,你可以使用以下外部链接获取程序:https://jdoodle.com/ia/40。

结果:

加载一个预先创建的公钥
publicKeyXML2: <RSAKeyValue><Modulus>lxUtcDSotIOD09uiDEPQSQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>

以 Base64 编码的加密数据: JIFfO7HXCvdi0nSxKb0eLA==
以 Base64 编码的加密数据: dvtRw0U0KtT/pDJZW2X0FA==
以 Base64 编码的加密数据: CqJJKZevO6jWH6DQ1dnkhQ==
以 Base64 编码的加密数据: G7cL6BBwxysItvD/Rg0PuA==
以 Base64 编码的加密数据: HcfZJITu/PzN84WgI8yc6g==

代码:

using System;
using System.Security.Cryptography;
using System.Text;

class RSACSPSample
{

    static void Main()
    {
        try
        {
            // 创建字节数组以保存原始数据、加密数据和解密数据。
            byte[] dataToEncrypt = System.Text.Encoding.UTF8.GetBytes("1234");
            byte[] encryptedData;

            // 创建 RSACryptoServiceProvider 的新实例以生成公钥和私钥数据。
            using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
            {
                Console.WriteLine("加载一个预先创建的公钥");
	            string publicKeyXML = "<RSAKeyValue><Modulus>AJcVLXA0qLSDg9PbogxD0Ek=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
	            RSA.FromXmlString(publicKeyXML);
	            string publicKeyXML2 = RSA.ToXmlString(false);
                Console.WriteLine("publicKeyXML2: " + publicKeyXML2);
                Console.WriteLine();

                // 将数据传递给 ENCRYPT,传递公钥信息(使用 RSACryptoServiceProvider.ExportParameters(false)),
                // 以及一个布尔标志指定不使用 OAEP 填充。
                for (int i = 0; i < 5; i++)
                {
                    encryptedData = RSAEncrypt(dataToEncrypt, RSA.ExportParameters(false), false);
                    string encryptedDataBase64 = Convert.ToBase64String(encryptedData);
                    Console.WriteLine("以 Base64 编码的加密数据: " + encryptedDataBase64);
                }

            }
        }
        catch (ArgumentNullException)
        {
            // 在加密未成功时捕获此异常。
            Console.WriteLine("加密失败。");
        }
    }

    public static byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
    {
        try
        {
            byte[] encryptedData;
            // 创建 RSACryptoServiceProvider 的新实例。
            using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
            {

                // 导入 RSA 密钥信息。这只需要包括公钥信息。
                RSA.ImportParameters(RSAKeyInfo);

                // 加密传递的字节数组并指定 OAEP 填充。
                // OAEP 填充仅在 Microsoft Windows XP 或更高版本上可用。
                encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
            }
            return encryptedData;
        }
        // 捕获并在控制台上显示 CryptographicException。
        catch (CryptographicException e)
        {
            Console.WriteLine(e.Message);

            return null;
        }
    }
}

注意:这只是你提供的代码的中文翻译,其中可能包含一些代码注释和字符串的翻译。如果需要进一步的解释或讨论,请随时提问。

英文:

This is not the answer to your question but may help you in understanding RSA encryption.

I setup a sample encryption program in C# and used your given public key (converted the BigInteger modulus & exponent to Base64 values and further just wrote the XML-String representation of the public to use this key for encryption. The keylength is good for a length of maximum 5 byte data.

When running the encryption 5 times you will receive different encodedData (here in Base64 encoding) each run. So it's the expected behavior of the RSA encryption.

As C# allows me to "build" a short key it is not possible to generate a fresh keypair of such length and I doubt that Bouncy Castle would do (but here on SO there are many colleagues with a much better understanding of BC :-).

If you would like the program you can use the following external link to the program: https://jdoodle.com/ia/40.

Result:

load a pre created public key
publicKeyXML2: <RSAKeyValue><Modulus>lxUtcDSotIOD09uiDEPQSQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>

encryptedData in Base64: JIFfO7HXCvdi0nSxKb0eLA==
encryptedData in Base64: dvtRw0U0KtT/pDJZW2X0FA==
encryptedData in Base64: CqJJKZevO6jWH6DQ1dnkhQ==
encryptedData in Base64: G7cL6BBwxysItvD/Rg0PuA==
encryptedData in Base64: HcfZJITu/PzN84WgI8yc6g==

code:

using System;
using System.Security.Cryptography;
using System.Text;
class RSACSPSample
{
static void Main()
{
try
{
//Create byte arrays to hold original, encrypted, and decrypted data.
byte[] dataToEncrypt = System.Text.Encoding.UTF8.GetBytes(&quot;1234&quot;);
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider to generate
//public and private key data.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
Console.WriteLine(&quot;load a pre created public key&quot;);
string publicKeyXML = &quot;&lt;RSAKeyValue&gt;&lt;Modulus&gt;AJcVLXA0qLSDg9PbogxD0Ek=&lt;/Modulus&gt;&lt;Exponent&gt;AQAB&lt;/Exponent&gt;&lt;/RSAKeyValue&gt;&quot;;
RSA.FromXmlString(publicKeyXML);
string publicKeyXML2 = RSA.ToXmlString(false);
Console.WriteLine(&quot;publicKeyXML2: &quot; + publicKeyXML2);
Console.WriteLine();
//Pass the data to ENCRYPT, the public key information 
//(using RSACryptoServiceProvider.ExportParameters(false),
//and a boolean flag specifying no OAEP padding.
for (int i = 0; i &lt; 5; i++)
{
encryptedData = RSAEncrypt(dataToEncrypt, RSA.ExportParameters(false), false);
string encryptedDataBase64 = Convert.ToBase64String(encryptedData);
Console.WriteLine(&quot;encryptedData in Base64: &quot; + encryptedDataBase64);
}
}
}
catch (ArgumentNullException)
{
//Catch this exception in case the encryption did
//not succeed.
Console.WriteLine(&quot;Encryption failed.&quot;);
}
}
public static byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This only needs
//toinclude the public key information.
RSA.ImportParameters(RSAKeyInfo);
//Encrypt the passed byte array and specify OAEP padding.  
//OAEP padding is only available on Microsoft Windows XP or
//later.  
encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
return encryptedData;
}
//Catch and display a CryptographicException  
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
}

答案2

得分: 0

虽然我不会将自己的答案标记为正确答案,但我发现有可能重新创建我问题中提到的 Java 代码的整个功能。

正如 Michael Fehr 在他的回答中提到的,任何加密方法都会尽量避免创建重复或可预测的模式,就像这个回答所描述的那样。

在这种特定情况下,既然目标是复制 Java 代码的功能,而该功能围绕着使用给定的公钥加密字符串时获得相同的结果,我们可以使用这篇帖子中的答案生成如下代码片段:

private static string EncryptMessage(string str, string publicRSA)
{
    string[] Separated = publicRSA.Split('|');
    RsaKeyParameters pubParameters = MakeKey(Separated[1], Separated[0], false);

    var eng = new RsaEngine();
    eng.Init(true, pubParameters);

    string x = Reverse(str);
    byte[] plaintext = Encoding.UTF8.GetBytes(x);

    var encdata = ByteArrayToString(eng.ProcessBlock(plaintext, 0, plaintext.Length));

    return encdata;
}

private static RsaKeyParameters MakeKey(string modulusHexString, string exponentHexString, bool isPrivateKey)
{
    byte[] mod = StringToByteArray(modulusHexString);
    byte[] exp = StringToByteArray(exponentHexString);
    var modulus = new BigInteger(mod);
    var exponent = new BigInteger(exp);
    return new RsaKeyParameters(isPrivateKey, modulus, exponent);
}

总结一下:

  1. 正如 Michael Fehr 所说,一个加密引擎不会生成可重复/可预测模式,这不仅是正常的,而且是预期的
  2. 为了实现上述观点,它们在消息中添加随机的“填充”
  3. **有可能(但不推荐)**使用 BouncyCastle 来生成无填充引擎,以模仿诸如这样的 Java 代码的功能:Cipher rsa = Cipher.getInstance("RSA/ECB/nopadding");
英文:

While I won't mark my own answer as the correct one, I've found that there's the possibility to recreate the entire functionality of the java code mentioned in my question.

As Michael Fehr mentions in his answer, Its absolutely logical that any encryption method will try to avoid creating repeating or predictable patterns, as this answer perfectly describes.

Since in this particular situation the aim is to replicate the java code functionality, and said functionality revolves around getting the same results when encrypting a string with a given public key, we can use the answer in this post to generate a pice of code like the following:

    private static string EncryptMessage(string str, string publicRSA)
{
string[] Separated = publicRSA.Split(&#39;|&#39;);
RsaKeyParameters pubParameters = MakeKey(Separated[1], Separated[0], false);
var eng = new RsaEngine();
eng.Init(true, pubParameters);
string x = Reverse(str);
byte[] plaintext = Encoding.UTF8.GetBytes(x);
var encdata = ByteArrayToString(eng.ProcessBlock(plaintext, 0, plaintext.Length));
return encdata;
}
private static RsaKeyParameters MakeKey(string modulusHexString, string exponentHexString, bool isPrivateKey)
{
byte[] mod = StringToByteArray(modulusHexString);
byte[] exp = StringToByteArray(exponentHexString);
var modulus = new BigInteger(mod);
var exponent = new BigInteger(exp);
return new RsaKeyParameters(isPrivateKey, modulus, exponent);
}

To recap:

  1. As Michael Fehr says, it is not only normal but expected of a crypyography engine to NOT generate repeatable/predictable patterns
  2. To deliver on the previous point, they add random "padding" to the messages
  3. It's possible (but not recommended) to use BouncyCastle to generate a No-padding engine, emulating the functionality of Java code such as this Cipher rsa = Cipher.getInstance(&quot;RSA/ECB/nopadding&quot;);

huangapple
  • 本文由 发表于 2020年7月27日 19:48:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/63114698.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定