0

I want to run my C# code to login a web site, so I need to implement the RSA Encryption method in the web site. Below is my C# and JavaScript test code to encrypt "test", but they display the different results.How to modify the C# code to get the same result as the JavaScript code?

JavaScript:Save the code to a html file and opened by web browser will see the result.

Or run the code online:https://onlinegdb.com/fzKiCrbGf

It is the JavaScript RSA library with documentation comments:http://www.ohdave.com/rsa/RSA.js

<script src="http://www.ohdave.com/rsa/RSA.js"></script>
<script src="http://www.ohdave.com/rsa/Barrett.js"></script>
<script src="http://www.ohdave.com/rsa/BigInt.js"></script>
<script>
setMaxDigits(130);
var key = new RSAKeyPair("010001","","906C793510FB049452764740B21B97A51DAEA794AB6E43836269D5E6317D49226C12362BA22DAB5EC3BC79553A8A098B01F3C4D81A87B3EE5BD2F4F1431CC495EE2FE54688B212145BB32D56EEEEE1430CE26234331B291CFC53C9B84FAFFDF0B44371A032880C3D567F588D2CD5FCE28D9CDD2923CB547DAD219A6A1B8B5D3D");
var result=encryptedString(key,"test")
document.write(result);
</script>

C#:It is the code of the C# Consloe Program.Run the code will see the result output to the consloe.

Or run the code online:https://onlinegdb.com/B1wG_5rXu

class Program
{
    static void Main(string[] args)
    {
        System.Security.Cryptography.RSAParameters rsaParams = new System.Security.Cryptography.RSAParameters
        {
            Modulus = HexToByteArray("906C793510FB049452764740B21B97A51DAEA794AB6E43836269D5E6317D49226C12362BA22DAB5EC3BC79553A8A098B01F3C4D81A87B3EE5BD2F4F1431CC495EE2FE54688B212145BB32D56EEEEE1430CE26234331B291CFC53C9B84FAFFDF0B44371A032880C3D567F588D2CD5FCE28D9CDD2923CB547DAD219A6A1B8B5D3D"),
            Exponent = HexToByteArray("010001"),
        };
        System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
        rsa.ImportParameters(rsaParams);
        byte[] result = rsa.Encrypt(System.Text.Encoding.UTF8.GetBytes("test"), false);
        System.Console.Write(ByteArrayToHex(result));
        System.Console.ReadKey();
    }

    public static byte[] HexToByteArray(string hex)
    {
        return Enumerable.Range(0, hex.Length)
                         .Where(x => x % 2 == 0)
                         .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
                         .ToArray();
    }

    public static string ByteArrayToHex(byte[] ba)
    {
        System.Text.StringBuilder hex = new System.Text.StringBuilder(ba.Length * 2);
        foreach (byte b in ba)
            hex.AppendFormat("{0:x2}", b);
        return hex.ToString();
    }
}
9
  • 2
    The .NET version won't even be consistent with itself from run to run. You're using PKCS#1 v1.5 padding, which adds random data to the plaintext before encrypting. Commented Mar 10, 2021 at 1:10
  • if add random data to the plaintext , the results should be different for each running. But they are the same. Commented Mar 10, 2021 at 1:16
  • If I click on the link you provided to run the C# code, and press run, I get one value, then if I press run, I get another value. It's different on each run. Commented Mar 10, 2021 at 1:18
  • Sorry , I was wrong, It's different on each run. Is it possible to remove the padding before encrypting? Commented Mar 10, 2021 at 1:35
  • 1
    No. C#'s implementation only supports two padding options, both of which use random bytes. Commented Mar 10, 2021 at 1:45

1 Answer 1

2

The JavaScript library uses textbook rsa by default, i.e. none of the usual (non-deterministic) paddings (PKCS#1 v1.5 or OAEP) are applied (note that the JavaScript library also supports PKCS#1 v1.5 padding).
textbook RSA is insecure and should therefore not be used in practice! As noted in the comment, .NET does not support this insecure variant out-of-the-box, so a third-party library must be applied, e.g. BouncyCastle.

Furthermore, the JavaScript library internally reverses the order of the plaintext, which must therefore be done explicitly in the C# code.

The JavaScript code below:

setMaxDigits(130);
var key = new RSAKeyPair("010001","","906C793510FB049452764740B21B97A51DAEA794AB6E43836269D5E6317D49226C12362BA22DAB5EC3BC79553A8A098B01F3C4D81A87B3EE5BD2F4F1431CC495EE2FE54688B212145BB32D56EEEEE1430CE26234331B291CFC53C9B84FAFFDF0B44371A032880C3D567F588D2CD5FCE28D9CDD2923CB547DAD219A6A1B8B5D3D");
var result=encryptedString(key,"test")
document.write(result);
<script src="http://www.ohdave.com/rsa/BigInt.js"></script>
<script src="http://www.ohdave.com/rsa/Barrett.js"></script>
<script src="http://www.ohdave.com/rsa/RSA.js"></script>

produces the following ciphertext:

4331ef280f5fd4f4c53fc2367c90fceb5cc65eca7b343cb5e67c120e4a47202e5343f9b9952f885542053d7c408495a2a3f53da9d13839fcd5b0fc044543ffccd44e8057015534c4ff0f1b849619cf0e5b2c86751c6f6effbc4555158c5000876cc0bb5915abdfbcf211be8a195a97b3fb1662c71a20d8183c589da5a5549b55 

A possible implementation in C# that provides the result of the JavaScript code is:

using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using System;
using System.Text;

...

// Encode plaintext and reverse order
string plaintext = "test";
var dataToEncrypt = Encoding.UTF8.GetBytes(plaintext);
Array.Reverse(dataToEncrypt);

// Import key via modulus and public exponent
string modulus = "906C793510FB049452764740B21B97A51DAEA794AB6E43836269D5E6317D49226C12362BA22DAB5EC3BC79553A8A098B01F3C4D81A87B3EE5BD2F4F1431CC495EE2FE54688B212145BB32D56EEEEE1430CE26234331B291CFC53C9B84FAFFDF0B44371A032880C3D567F588D2CD5FCE28D9CDD2923CB547DAD219A6A1B8B5D3D";
string exponent = "010001";
BigInteger rsaPubMod = new BigInteger(modulus, 16);
BigInteger rsaPubExp = new BigInteger(exponent, 16);
RsaKeyParameters rsaPublic = new RsaKeyParameters(false, rsaPubMod, rsaPubExp);

// Encrypt with NoPadding (= textbook RSA) - Be aware that this is insecure!!!
var cipher = CipherUtilities.GetCipher("RSA/NONE/NoPadding");
cipher.Init(true, rsaPublic);
var encryptedData = cipher.DoFinal(dataToEncrypt);

// Hex encode the data
var encryptedDataHex = BitConverter.ToString(encryptedData).Replace("-", "").ToLower();

Console.WriteLine(encryptedDataHex); // 4331ef280f5fd4f4c53fc2367c90fceb5cc65eca7b343cb5e67c120e4a47202e5343f9b9952f885542053d7c408495a2a3f53da9d13839fcd5b0fc044543ffccd44e8057015534c4ff0f1b849619cf0e5b2c86751c6f6effbc4555158c5000876cc0bb5915abdfbcf211be8a195a97b3fb1662c71a20d8183c589da5a5549b55
Sign up to request clarification or add additional context in comments.

2 Comments

Deterministic means a rainbow table can be used to find the password if a hacker is too lazy to use one of the cracking tools targeting textbook implementations. One has to wonder whether that's the whole point - the OP asked an identical question yesterday and didn't like the answer that the script is at fault, or that a popular library should be used instead
@PanagiotisKanavos - Yes, I agree. Deleting an old question and posting more or less the same question is a bad habit, since all the information about the previous question is lost and has to be worked out again with a corresponding time investment. It's also kind of disrespectful to those who took the time to help with the deleted question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.