RSA Encryption Algorithm Problems - c#

As part of my school project, I've tried to create the RSA encryption algorithm. I've followed the pseudocode and added all the operations, however after encrypting and decryption, the program does not return the original plaintext.
using System;
using System.Collections.Generic;
using System.Numerics;
namespace ConsoleApp4
{
class Program
{
private static readonly int INTLIMIT = 2; //represents the max size in bit value
static void Main(string[] args)
{
BigInteger x = generate2048Integer();
BigInteger y = generate2048Integer();
Console.WriteLine(x);
Console.WriteLine(y);
BigInteger n = x * y;
BigInteger a = x - 1;
BigInteger b = y - 1;
BigInteger phi = BigInteger.Abs(a * b) / dgcd(a, b);
BigInteger e = 65537;
BigInteger d = newModInv(e, phi);
BigInteger key = RSAEncryption(77, e, n);
BigInteger text = RSADecryption(key, d, n);
Console.WriteLine(text);
}
public static BigInteger generate2048Integer()
{
Random r = new Random();
string s = "";
for (int i = 0; i < INTLIMIT; i++)
{
s += Convert.ToString(r.Next(0, 9));
}
return BigInteger.Parse(s);
}
public static BigInteger dgcd(BigInteger a, BigInteger b)
{
while (b != 0)
{
BigInteger t = b;
b = mod(a, b);
a = t;
}
return a;
}
public static BigInteger newModInv(BigInteger a, BigInteger b)
{
BigInteger t = 0;
BigInteger r = b;
BigInteger newt = 1;
BigInteger newr = a;
while(newr != 0)
{
BigInteger q = r / newr;
(t, newt) = (newt, t - q * newt);
(r, newr) = (newr, r - q * newr);
}
if (r > 1)
{
return 0;
}
if(t < 0)
{
t = t + b;
}
return t;
}
public static BigInteger mod(BigInteger x, BigInteger m)
{
return (x % m + m) % m;
}
public static BigInteger RSAEncryption(BigInteger plaintext, BigInteger pubD, BigInteger n)
{
BigInteger rtrn = mod(Pow(plaintext, pubD), n);
return rtrn;
}
public static BigInteger RSADecryption(BigInteger ciphertext, BigInteger privD, BigInteger n)
{
BigInteger rtrn = mod(Pow(ciphertext, privD), n);
return rtrn;
}
public static BigInteger Pow(BigInteger value, BigInteger exponent)
{
BigInteger originalValue = value;
while (exponent-- > 1)
value = BigInteger.Multiply(value, originalValue);
return value;
}
}
}
I'm not sure where I've gone wrong here, I believe it may be something to do with the Encryption though.

Related

Dictionary<BigInteger[],BigInteger[]> does not return value when key is clearly correct. Dictionary is of RSA Keys for my custom RSA algorithm

I am currently working on creating a RSA test for a program of mine, this is the debug to make sure everything works before I implement it.
I know the RSA algorithm itself works, the problem lies with the Dictionary of <Biginteger[],Biginteger[]> where it is it form <publickey, privatekey> where public key is an array {e,n} and private key {d,n}.
When generating the keys it adds both to the dictionary successfully however when it puts in the public key to return the private key it says it isnt a valid key.
Unsure why and is bothering me as the debug (attached) would show it should work.
(with regards to why im doing a strange ASCII translation thing and not using the RSA properly it is simply a demo and in my system i just need to encrypt and decrypt values -1<x<999)
The reason for turning from form string "e,n" to an array {e,n} is due to the nature of how i will be transferring the data across a socket so will be in that form.
Any Ideas or help to why it cant find the value would be great :)
static void Main(string[] args)
{
Dictionary<BigInteger[], BigInteger[]> RSA_KEYS = new Dictionary<BigInteger[], BigInteger[]>();
//recipitent receives public key in form e,n
//splits into Biginteger array : {e,n}
string publickeystring = (PublicKeyRequest(RSA_KEYS));
BigInteger[] publickeyresponse = Array.ConvertAll(publickeystring.Split(','), BigInteger.Parse);
Console.WriteLine("Public Key Requested: " + publickeystring);
foreach (var item in RSA_KEYS)
{
Console.WriteLine(item.Key[0] + ", "+ item.Key[1] + ":" + item.Value[0] + ", " + item.Value[1]);
}
//creates message to encrypt
string input = InputToAscii();
//recipitent encrypts message
BigInteger a = encrypt(publickeyresponse, input);
Console.WriteLine("Encrypted Value = " + a);
//using public key sent back from recipitent it will find private key in dictionary to use to decrypt
BigInteger b = decrypt(RSA_KEYS[publickeyresponse], a);
Console.WriteLine("Decrypted Value = " + b);
Console.WriteLine(AsciiToOutput(b));
Console.ReadLine();
}
private static string PublicKeyRequest(Dictionary<BigInteger[], BigInteger[]> RSA_KEYS)
{
KeyValuePair<BigInteger[], BigInteger[]> Keys = GenerateKeys();
Console.WriteLine("added public key to dict: " + Keys.Key[0] + "," + Keys.Key[1]);
BigInteger[] publickey = Keys.Key;
RSA_KEYS.Add(Keys.Key, Keys.Value);
return (publickey[0] + "," + publickey[1]);
}
private static KeyValuePair<BigInteger[], BigInteger[]> GenerateKeys()
{
int p = 4201; //default use 61 4201
int q = 4007; //default use 53 4007
int n = p * q;
Console.WriteLine("p = " + p + ", q = " + q + ", " + "n = " + n);
// n = 3233.
// compute the totient, phi
int ϕn = (p - 1) * (q - 1);
Console.WriteLine("ϕ(n) = " + ϕn);
// phi = 3120.
//e for random number which 1 < e < ϕn and is co prime of ϕn
Random rn = new Random();
bool found = false;
BigInteger e = 0;
while (found == false)
{
e = rn.Next(1, ϕn);
if (Coprime(ϕn, e) == true)
{
break;
}
}
Console.WriteLine("e = " + e);
// Using the extended euclidean algorithm, find 'd' which satisfies
// where (d * e) mod ϕn = 1 find d
BigInteger d = 0;
for (int k = 1; k < ϕn; k++)
{
if ((k * e) % ϕn == 1)
{
d = k;
break;
}
}
Console.WriteLine("d = " + d);
BigInteger[] public_key = new BigInteger[] { e, n }; //(e = 17, n = 3233)
Console.WriteLine("Public key: e = " + e + " n = " + n);
BigInteger[] private_key = new BigInteger[] { d, n }; //(d = 2753, n = 3233)
Console.WriteLine("Private key: d = " + d + " n = " + n);
return new KeyValuePair<BigInteger[], BigInteger[]>(public_key,private_key);
}
private static BigInteger encrypt(BigInteger[] PublicKey, string input)
{
BigInteger m = BigInteger.Parse(input); //m = message
BigInteger c = eMod(m, PublicKey[0], PublicKey[1]); //cipher text = (message ^ e) mod n
return c;
}
private static BigInteger decrypt(BigInteger[] PrivateKey, BigInteger c)
{
BigInteger f = eMod(c, PrivateKey[0], PrivateKey[1]); //result test = cipher ^ d mod n
return f;
}
private static BigInteger eMod(BigInteger a, BigInteger b, BigInteger c) //where a^b % c;
{
//base case
if (b == 0)
{
return 1;
}
else if (b % 2 == 0)
{
BigInteger d = eMod(a, b / 2, c);
//int result = d * d % c;
return ((d * d) % c);
}
else
{
return ((a % c) * eMod(a, b - 1, c)) % c;
}
}
private static BigInteger GetGCDByModulus(BigInteger value1, BigInteger value2)
{
while (value1 != 0 && value2 != 0)
{
if (value1 > value2)
value1 %= value2;
else
value2 %= value1;
}
return BigInteger.Max(value1, value2);
}
private static bool Coprime(BigInteger value1, BigInteger value2)
{
return GetGCDByModulus(value1, value2) == 1;
}
private static string InputToAscii()
{
Console.Write("Enter values to encrypt:");
char[] input = Console.ReadLine().ToCharArray(); //-1 < input < 999;
//char[] input = "-1".ToCharArray();
string AsciiInput = string.Empty;
for (int i = 0; i < input.Length; i++)
{
AsciiInput += ((int)input[i]).ToString();
}
Console.WriteLine(AsciiInput);
return AsciiInput;
}
private static string AsciiToOutput(BigInteger input)
{
string inputstring = input.ToString();
string output = string.Empty;
for (int i = 0; i < inputstring.Length / 2; i++)
{
output += (char)Convert.ToInt32((inputstring.Substring(i * 2, 2)));
}
return output;
}

How to perform modinverse in C#

Is there a way to perform modinverse in C#? My data is in BigInteger format.
P : E61E05F338BC965421720C4128C33FDFC7BC3CE637A3BC92A114E79AC380C90387988639224FE5C578B601E505C85AF85EB86DAEC06413EA419187D1D2396C063CDA7DC805E47906E731F4A0B2C53521CAC812BE68044DBFA8E3DE4BE1E0D94F2E0CC9FC126D21E5AF7038FA0942D12700AFC4DE2D00FB3A1FA6A224D0FA0D7B
dP : 00000000000000000000000000010001
dP^-1 mod P
I've tried BigInteger.ModPow(dP, -1, P). But I cannot use negative exponent.
You have to implement Extended Euclidian Algorithm first:
public static BigInteger Egcd(BigInteger left,
BigInteger right,
out BigInteger leftFactor,
out BigInteger rightFactor) {
leftFactor = 0;
rightFactor = 1;
BigInteger u = 1;
BigInteger v = 0;
BigInteger gcd = 0;
while (left != 0) {
BigInteger q = right / left;
BigInteger r = right % left;
BigInteger m = leftFactor - u * q;
BigInteger n = rightFactor - v * q;
right = left;
left = r;
leftFactor = u;
rightFactor = v;
u = m;
v = n;
gcd = right;
}
return gcd;
}
And then
public static BigInteger ModInverse(BigInteger value, BigInteger modulo) {
BigInteger x, y;
if (1 != Egcd(value, modulo, out x, out y))
throw new ArgumentException("Invalid modulo", nameof(modulo));
if (x < 0)
x += modulo;
return x % modulo;
}

RSAParameters calculating private parameters

I am trying to calculate the private parameters of the RSAParameters struct on .NET Standard. I made a unit test to test my calculations:
[TestMethod]
public void DQDPTest()
{
RSA rsa = RSA.Create();
RSAParameters rsaParams = rsa.ExportParameters(true);
BigInteger p = new BigInteger(rsaParams.P.Reverse().ToArray());
BigInteger q = new BigInteger(rsaParams.Q.Reverse().ToArray());
BigInteger d = new BigInteger(rsaParams.D.Reverse().ToArray());
BigInteger dq = new BigInteger(rsaParams.DQ.Reverse().ToArray());
BigInteger dp = new BigInteger(rsaParams.DP.Reverse().ToArray());
Assert.AreEqual(dq, d % (q - 1));
Assert.AreEqual(dp, d % (p - 1));
}
However, the assertions consistently fail and I cannot figure out why, since DQ and DP are supposed to contain those values. Why is this happening?
I have a similar method for calculating InverseQ, and this does not work either:
[TestMethod]
public void ModInverseTest()
{
RSA rsa = RSA.Create();
RSAParameters rsaParams = rsa.ExportParameters(true);
BigInteger p = new BigInteger(rsaParams.P.Reverse().ToArray());
BigInteger q = new BigInteger(rsaParams.Q.Reverse().ToArray());
BigInteger iq = new BigInteger(rsaParams.InverseQ.Reverse().ToArray());
BigInteger ciq = Extensions.ModInverse(q, p);
Assert.AreEqual(1, (iq * q) % p);
Assert.AreEqual(1, (ciq * q) % p);
Assert.AreEqual(iq, ciq);
}
public static BigInteger ModInverse(BigInteger a, BigInteger n)
{
BigInteger t = 0, nt = 1, r = n, nr = a;
if (n < 0)
{
n = -n;
}
if (a < 0)
{
a = n - (-a % n);
}
while (nr != 0)
{
var quot = r / nr;
var tmp = nt; nt = t - quot * nt; t = tmp;
tmp = nr; nr = r - quot * nr; r = tmp;
}
if (r > 1) throw new ArgumentException(nameof(a) + " is not convertible.");
if (t < 0) t = t + n;
return t;
}
The assertions in ModInverseTest() also consistently fail, which means either I am doing something incorrectly, or these values are simply not what I think they are. Again, why is this happening?
Your values for P and Q are almost certainly negative, which is likely throwing off everything else. This is because the C# BigInteger constructor doesn't allow you to specify positive/negative, and so a most significant byte with the most sigificant bit set means it's a negative number. The solution is to add a padding byte (0x00) which keeps the sign bit clear.
private static System.Numerics.BigInteger GetBigInteger(byte[] parameter)
{
byte[] signPadded = new byte[parameter.Length + 1];
Buffer.BlockCopy(parameter, 0, signPadded, 1, parameter.Length);
Array.Reverse(signPadded);
return new System.Numerics.BigInteger(signPadded);
}

C# ModInverse Function

Is there a built in function that would allow me to calculate the modular inverse of a(mod n)?
e.g. 19^-1 = 11 (mod 30), in this case the 19^-1 == -11==19;
Since .Net 4.0+ implements BigInteger with a special modular arithmetics function ModPow (which produces “X power Y modulo Z”), you don't need a third-party library to emulate ModInverse. If n is a prime, all you need to do is to compute:
a_inverse = BigInteger.ModPow(a, n - 2, n)
For more details, look in Wikipedia: Modular multiplicative inverse, section Using Euler's theorem, the special case “when m is a prime”. By the way, there is a more recent SO topic on this: 1/BigInteger in c#, with the same approach suggested by CodesInChaos.
int modInverse(int a, int n)
{
int i = n, v = 0, d = 1;
while (a>0) {
int t = i/a, x = a;
a = i % x;
i = x;
x = d;
d = v - t*x;
v = x;
}
v %= n;
if (v<0) v = (v+n)%n;
return v;
}
The BouncyCastle Crypto library has a BigInteger implementation that has most of the modular arithmetic functions. It's in the Org.BouncyCastle.Math namespace.
Here is a slightly more polished version of Samuel Allan's algorithm. The TryModInverse method returns a bool value, that indicates whether a modular multiplicative inverse exists for this number and modulo.
public static bool TryModInverse(int number, int modulo, out int result)
{
if (number < 1) throw new ArgumentOutOfRangeException(nameof(number));
if (modulo < 2) throw new ArgumentOutOfRangeException(nameof(modulo));
int n = number;
int m = modulo, v = 0, d = 1;
while (n > 0)
{
int t = m / n, x = n;
n = m % x;
m = x;
x = d;
d = checked(v - t * x); // Just in case
v = x;
}
result = v % modulo;
if (result < 0) result += modulo;
if ((long)number * result % modulo == 1L) return true;
result = default;
return false;
}
There is no library for getting inverse mod, but the following code can be used to get it.
// Given a and b->ax+by=d
long[] u = { a, 1, 0 };
long[] v = { b, 0, 1 };
long[] w = { 0, 0, 0 };
long temp = 0;
while (v[0] > 0)
{
double t = (u[0] / v[0]);
for (int i = 0; i < 3; i++)
{
w[i] = u[i] - ((int)(Math.Floor(t)) * v[i]);
u[i] = v[i];
v[i] = w[i];
}
}
// u[0] is gcd while u[1] gives x and u[2] gives y.
// if u[1] gives the inverse mod value and if it is negative then the following gives the first positive value
if (u[1] < 0)
{
while (u[1] < 0)
{
temp = u[1] + b;
u[1] = temp;
}
}

How to create private RSA key using modulus, D, exponent in C#?

I have 3 byte arrays of length 128, 128, 3 bytes respectively. I don't know what it is, but I expect them to be Modulus, D, Exponent.
Now how can I use these arrays in C# to decrypt a byte array using RSA?
When I create an RSAParameters and assign the 3 byte arrays to Modulus, D, Exponent and try to use that RSAParameters in RSACryptoServiceProvider.ImportParameters, decryption fails stating corrupt keys. I guess the other entries also need to be filled DQ,DP,...etc...
How do I do that in C#? I don't have that values, is there an easy way to decrypt a byte array using only Modulus, D, Exponent in C#, as in other languages?
The Windows implementations seem to only be willing to do RSA via the CRT parameters, leaving D as a potentially ignored value. At the very least, the CRT parameters are required inputs.
First, we need to turn your arrays into BigInteger values. I'm assuming here that you have Big-Endian encoded values. If they're Little-Endian, don't call Array.Reverse() and change the copy-to index from 1 to 0.
private static BigInteger GetBigInteger(byte[] bytes)
{
byte[] signPadded = new byte[bytes.Length + 1];
Buffer.BlockCopy(bytes, 0, signPadded, 1, bytes.Length);
Array.Reverse(signPadded);
return new BigInteger(signPadded);
}
Adding the extra byte prevents numbers from being treated as negative. (One could avoid the allocation and memory copy by testing for the sign bit in the last byte, if one wanted).
So now you have three BigInteger values, n, e, d. Not sure which of n and d is which?
// Unless someone tried really hard to make this break it'll work.
if (n < d)
{
BigInteger tmp = n;
n = d;
d = tmp;
}
Now, using the algorithm from NIST Special Publication 800-56B Recommendation for Pair-Wise August 2009 Key Establishment Schemes Using Integer Factorization Cryptography, Appendix C (as shared in https://stackoverflow.com/a/28299742/6535399) we can calculate the BigInteger values. There's a tricky subtlety, though. RSAParameters values have to have a correct amount of padding, and RSACryptoServiceProvider doesn't do it for you.
private static RSAParameters RecoverRSAParameters(BigInteger n, BigInteger e, BigInteger d)
{
using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
{
BigInteger k = d * e - 1;
if (!k.IsEven)
{
throw new InvalidOperationException("d*e - 1 is odd");
}
BigInteger two = 2;
BigInteger t = BigInteger.One;
BigInteger r = k / two;
while (r.IsEven)
{
t++;
r /= two;
}
byte[] rndBuf = n.ToByteArray();
if (rndBuf[rndBuf.Length - 1] == 0)
{
rndBuf = new byte[rndBuf.Length - 1];
}
BigInteger nMinusOne = n - BigInteger.One;
bool cracked = false;
BigInteger y = BigInteger.Zero;
for (int i = 0; i < 100 && !cracked; i++)
{
BigInteger g;
do
{
rng.GetBytes(rndBuf);
g = GetBigInteger(rndBuf);
}
while (g >= n);
y = BigInteger.ModPow(g, r, n);
if (y.IsOne || y == nMinusOne)
{
i--;
continue;
}
for (BigInteger j = BigInteger.One; j < t; j++)
{
BigInteger x = BigInteger.ModPow(y, two, n);
if (x.IsOne)
{
cracked = true;
break;
}
if (x == nMinusOne)
{
break;
}
y = x;
}
}
if (!cracked)
{
throw new InvalidOperationException("Prime factors not found");
}
BigInteger p = BigInteger.GreatestCommonDivisor(y - BigInteger.One, n);
BigInteger q = n / p;
BigInteger dp = d % (p - BigInteger.One);
BigInteger dq = d % (q - BigInteger.One);
BigInteger inverseQ = ModInverse(q, p);
int modLen = rndBuf.Length;
int halfModLen = (modLen + 1) / 2;
return new RSAParameters
{
Modulus = GetBytes(n, modLen),
Exponent = GetBytes(e, -1),
D = GetBytes(d, modLen),
P = GetBytes(p, halfModLen),
Q = GetBytes(q, halfModLen),
DP = GetBytes(dp, halfModLen),
DQ = GetBytes(dq, halfModLen),
InverseQ = GetBytes(inverseQ, halfModLen),
};
}
}
With the "tricky" BigInteger-to-suitable-for-RSAParameters-byte[] method:
private static byte[] GetBytes(BigInteger value, int size)
{
byte[] bytes = value.ToByteArray();
if (size == -1)
{
size = bytes.Length;
}
if (bytes.Length > size + 1)
{
throw new InvalidOperationException($"Cannot squeeze value {value} to {size} bytes from {bytes.Length}.");
}
if (bytes.Length == size + 1 && bytes[bytes.Length - 1] != 0)
{
throw new InvalidOperationException($"Cannot squeeze value {value} to {size} bytes from {bytes.Length}.");
}
Array.Resize(ref bytes, size);
Array.Reverse(bytes);
return bytes;
}
And for computing InverseQ you need ModInverse:
private static BigInteger ModInverse(BigInteger e, BigInteger n)
{
BigInteger r = n;
BigInteger newR = e;
BigInteger t = 0;
BigInteger newT = 1;
while (newR != 0)
{
BigInteger quotient = r / newR;
BigInteger temp;
temp = t;
t = newT;
newT = temp - quotient * newT;
temp = r;
r = newR;
newR = temp - quotient * newR;
}
if (t < 0)
{
t = t + n;
}
return t;
}
On my computer I'm recovering P and Q from (n, e, d) in ~50ms for a 1024-bit key. ~2-4 seconds for a 4096-bit key.
Note to implementers who like unit tests: There's not really a defined order for P and Q (like a convention that P always be the larger), so your P and Q values may be backwards from an RSAParameters structure that you started with. DP and DQ will thus also be reversed.
You don't have enough when you just have Mod, D, and the exponent. (Well you might have enough) P and Q are VERY hard to calculate from the mod. I wouldn't know how to do that and there are almost certainly more primes than the right ones that multiplied end up with the same mod.
You need atleast P, Q and the public exponent.
P, Q and D are the building blocks
DP = D mod (p - 1)
DQ = D mod (q - 1)
InverseQ = Q^-1 mod p
Modulus = P * Q
so now we have
P Q and D.
and we can calulate DP, DQ, InverseQ and Modulus and Exponent (see below)
long gcd(long a, long b)
{
long temp;
while (b != 0)
{
temp = b;
b = a % b;
a = temp;
}
return a;
}
Exponent = gcd(1, (P - 1)*(Q - 1));

Categories

Resources