RSAParameters calculating private parameters - c#

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

Related

RSA Encryption Algorithm Problems

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.

Processing BigInteger issues

Assume the following Diffie-Hellman info which can also be found on this page
1)P
string givenp = "00e655cc9e04f3bebae76ecca77143ef5c4451876615a9f8b4f712b8f3bdf47ee7f717c09bb5b2b66450831367d9dcf85f9f0528bcd5318fb1dab2f23ce77c48b6b7381eed13e80a14cca6b30b5e37ffe53db15e2d6b727a2efcee51893678d50e9a89166a359e574c4c3ca5e59fae79924fe6f186b36a2ebde9bf09fe4de50453";
BigInteger p = new BigInteger(HexToBytesv2(givenp));
2)G
BigInteger g = new BigInteger(2);
3)Merchant private key
string merchantPrivateKeyHEX = "48887dfd090d175e33beea29e7b38334299289069f9ab492b67807905faa98d96d22d79205bef03f14af093f1797b904734132c34a388fdc79e20497bfa1465fec2aac4fabdf3bb0c9be8685d20f7bfe0346a9abdf7fa89838c3fa9ca6abdb70bea66795ab6699cc154db59490e4159f142f7bddff603c1d3d6c4fff8177e11d";
BigInteger a = new BigInteger(HexToBytesv2(merchantPrivateKeyHEX));
Using the formula publickey = g ^ a mod p I should get the public key provided in the initial link, yet when executing
BigInteger A = BigInteger.ModPow(g, a, p);
ToHex(A.ToByteArray())
the result I get is
00f85c41e84446ecfe43c9911df31d3cf60d83642afd496b741363290139badf75f8b8c5c010dda2446dd483dc553b6c2698c16c9d082391677785f81d54bc9c7c45f8b6d5bdb3e49fec7f5522b880c8c753fb7d3ff2c81e47dcb27d52842def40a812dc95cc679575baf237a955ee9944bd0797326f2a0a58c6c087f9b0b9e82c
instead of
00d9abd78c93dfddeb920d57d6513126d8f1118c9237a45101408dbffe6cfd95b011a016e4e0ab8aef0601e836a452b8bb88be7ca71e4f22f97aa65f8358ee69348d1227d65db6e53641d1a6542aa4be4b4adc75fac816af79a8e3f5097f8313e7b725df37eadc8c774e2033dfa99c95ccef333bf402b066198c30481e2a83875c
Any ideas? I must be missing pretty obvious but I am not sure what that might be.
P.S. Adding the function being used:
public static byte[] HexToBytesv2(this string hex)
{
if (hex.Length % 2 == 1)
hex = '0' + hex;
byte[] ret = new byte[hex.Length / 2];
for (int i = 0; i < ret.Length; i++)
ret[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
return ret;
}
public static string ToHex(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
It's an endian problem.
I've adjusted your encoding and decoding and now get the answer you're looking for:
public static byte[] HexToBytesv2(string hex)
{
if (hex.Length % 2 == 1)
hex = '0' + hex;
byte[] ret = new byte[hex.Length / 2];
for (int i = 0; i < ret.Length; i++)
ret[i] = Convert.ToByte(hex.Substring(hex.Length - (i+1) * 2, 2), 16);
return ret;
}
public static string ToHex( byte[] bytes)
{
var sb = new StringBuilder();
foreach (var b in bytes.Reverse())
{
sb.AppendFormat("{0:x2}", b);
}
return sb.ToString();
}
FYI I used LinqPad and the main method is your code from the question (as adjusted) with checks that the data has not lost anything on the way:
void Main()
{
string givenp = "00e655cc9e04f3bebae76ecca77143ef5c4451876615a9f8b4f712b8f3bdf47ee7f717c09bb5b2b66450831367d9dcf85f9f0528bcd5318fb1dab2f23ce77c48b6b7381eed13e80a14cca6b30b5e37ffe53db15e2d6b727a2efcee51893678d50e9a89166a359e574c4c3ca5e59fae79924fe6f186b36a2ebde9bf09fe4de50453";
BigInteger p = new BigInteger(HexToBytesv2(givenp));
(ToHex(p.ToByteArray()) == "00e655cc9e04f3bebae76ecca77143ef5c4451876615a9f8b4f712b8f3bdf47ee7f717c09bb5b2b66450831367d9dcf85f9f0528bcd5318fb1dab2f23ce77c48b6b7381eed13e80a14cca6b30b5e37ffe53db15e2d6b727a2efcee51893678d50e9a89166a359e574c4c3ca5e59fae79924fe6f186b36a2ebde9bf09fe4de50453").Dump();
BigInteger g = new BigInteger(2);
string merchantPrivateKeyHEX = "48887dfd090d175e33beea29e7b38334299289069f9ab492b67807905faa98d96d22d79205bef03f14af093f1797b904734132c34a388fdc79e20497bfa1465fec2aac4fabdf3bb0c9be8685d20f7bfe0346a9abdf7fa89838c3fa9ca6abdb70bea66795ab6699cc154db59490e4159f142f7bddff603c1d3d6c4fff8177e11d";
BigInteger a = new BigInteger(HexToBytesv2(merchantPrivateKeyHEX));
(ToHex(a.ToByteArray()) == "48887dfd090d175e33beea29e7b38334299289069f9ab492b67807905faa98d96d22d79205bef03f14af093f1797b904734132c34a388fdc79e20497bfa1465fec2aac4fabdf3bb0c9be8685d20f7bfe0346a9abdf7fa89838c3fa9ca6abdb70bea66795ab6699cc154db59490e4159f142f7bddff603c1d3d6c4fff8177e11d").Dump();
BigInteger A = BigInteger.ModPow(g, a, p);
(ToHex(A.ToByteArray()) == "00f85c41e84446ecfe43c9911df31d3cf60d83642afd496b741363290139badf75f8b8c5c010dda2446dd483dc553b6c2698c16c9d082391677785f81d54bc9c7c45f8b6d5bdb3e49fec7f5522b880c8c753fb7d3ff2c81e47dcb27d52842def40a812dc95cc679575baf237a955ee9944bd0797326f2a0a58c6c087f9b0b9e82c").Dump();
(ToHex(A.ToByteArray()) == "00d9abd78c93dfddeb920d57d6513126d8f1118c9237a45101408dbffe6cfd95b011a016e4e0ab8aef0601e836a452b8bb88be7ca71e4f22f97aa65f8358ee69348d1227d65db6e53641d1a6542aa4be4b4adc75fac816af79a8e3f5097f8313e7b725df37eadc8c774e2033dfa99c95ccef333bf402b066198c30481e2a83875c").Dump();
}
Before I swapped the ordering, and included the .Concat(new byte[] { 0 }).ToArray() from your original question, the output was:
True
True
True
False
And now it's:
True
True
False
True
The other issue you're seeing is BigInteger.Parse and the Byte[] constructor always expect the top bit of the first nibble or last byte respectively to be the sign bit. So you need to include the extra 0 character or byte respectively to avoid that.
You're doing a number of unnecessary conversions and they're introducing an error somewhere.
If you remove the broken string-byte[]-BigInteger-byte[]-string steps and let BigInteger itself do the work for you then you'll generate the expected result:
string givenp = "00e655cc9e04f3bebae76ecca77143ef5c4451876615a9f8b4f712b8f3bdf47ee7f717c09bb5b2b66450831367d9dcf85f9f0528bcd5318fb1dab2f23ce77c48b6b7381eed13e80a14cca6b30b5e37ffe53db15e2d6b727a2efcee51893678d50e9a89166a359e574c4c3ca5e59fae79924fe6f186b36a2ebde9bf09fe4de50453";
var p = BigInteger.Parse(givenp, NumberStyles.HexNumber);
var g = new BigInteger(2);
var merchantPrivateKeyHEX = "48887dfd090d175e33beea29e7b38334299289069f9ab492b67807905faa98d96d22d79205bef03f14af093f1797b904734132c34a388fdc79e20497bfa1465fec2aac4fabdf3bb0c9be8685d20f7bfe0346a9abdf7fa89838c3fa9ca6abdb70bea66795ab6699cc154db59490e4159f142f7bddff603c1d3d6c4fff8177e11d";
var a = BigInteger.Parse(merchantPrivateKeyHEX, NumberStyles.HexNumber);
var publicKey = BigInteger.ModPow(g, a, p);
Console.WriteLine(publicKey.ToString("x")); // displays 0d9abd7...

ElGamal C# implementation

I want to implement ElGamal encryption. I need this for my school work but when I want do decryption the last step is always 0 cause of (b/Math.Pow(a,x))%primenumber is always less then 1.
Here is the keys generation:
public void GenerateKey() {
this.x = 3;
this.prvocislo = PrimeGen.findPrimes(29).Max(); //prime number
this.g = this.prvocislo % 12;
this.y = Convert.ToInt32(Math.Pow(this.g, this.x) % this.prvocislo);
this.k = 23;//601}
Here is encrypt function:
public string Encrypt(string word) {
List<string> words = new List<string>();
words = PrimeGen.SplitToArray(word, 2);
string encrypted="";
string sss = PrimeGen.GetStringFromBytes(PrimeGen.GetBytesFromInt(PrimeGen.GetIntFromBytes(PrimeGen.GetBytesFromString("ah")))); //returns ah so conversion works
foreach (string s in words)
{
int a = Convert.ToInt32(Math.Pow(g,k) % prvocislo);
int b = Convert.ToInt32((Math.Pow(y, k) * PrimeGen.GetIntFromBytes(PrimeGen.GetBytesFromString(s))) % prvocislo);
string aS = PrimeGen.GetStringFromBytes(PrimeGen.INT2LE(a + posun));
string bS = PrimeGen.GetStringFromBytes(PrimeGen.INT2LE(b + posun));
encrypted = encrypted + aS + bS;
}
return encrypted;
}
Here is my decrypt function:
public string Decrypt(string ElgamalEncrypted) {
string decrypted = "";
for (int i = 0; i < ElgamalEncrypted.Length; i = i + 2) {
string aS = ElgamalEncrypted.Substring(i, 2);
string bS = ElgamalEncrypted.Substring(i + 2, 2);
int a = PrimeGen.GetIntFromBytes(PrimeGen.GetBytesFromString(aS)) - posun;
int b = PrimeGen.GetIntFromBytes(PrimeGen.GetBytesFromString(bS)) - posun;
if(b==0) b=1;
if (a == 0) a = 1;
decrypted=decrypted+PrimeGen.GetStringFromBytes(PrimeGen.GetBytesFromInt(Convert.ToInt32(((b/Math.Pow(a,x))%prvocislo))));
}
return decrypted;
}
You're using Math.Pow(base, exponent) % modulus for modular exponentiation. That doesn't work because floating points can't represent the large integers crypto needs. Use System.Numerics.BigInteger.ModPow(base, exponent, modulus) instead.
The division probably doesn't work because you use integer division, instead of multiplying with the modular multiplicative inverse of the right side.

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