如何使用C#中的模数,D,指数创建私有RSA密钥?

我有3个字节的数组,长度分别为128,128,3个字节。 我不知道它是什么,但我希望它们是ModulusDExponent 。 现在我如何在C#中使用这些数组来使用RSA解密字节数组? 当我创建一个RSAParameters并将3字节数组分配给ModulusDExponent并尝试在RSACryptoServiceProvider.ImportParameters使用该RSAParameters时,解密失败说明损坏的密钥。 我猜其他参赛作品也需要填写DQDP等…

我如何在C#中做到这一点? 我没有这个值,有没有一种简单的方法来解密字节数组只使用模数,D,C#中的Exponent,就像在其他语言中一样?

Windows实现似乎只愿意通过CRT参数执行RSA,将D作为可能被忽略的值。 至少,CRT参数是必需的输入。

首先,我们需要将您的数组转换为BigInteger值。 我在这里假设你有Big-Endian编码值。 如果它们是Little-Endian,请不要调用Array.Reverse()并将copy-to index从1更改为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); } 

添加额外字节可防止将数字视为负数。 (如果需要,可以通过测试最后一个字节中的符号位来避免分配和内存复制)。

所以现在你有三个BigInteger值, ned 。 不确定nd中哪一个是哪个?

 // Unless someone tried really hard to make this break it'll work. if (n < d) { BigInteger tmp = n; n = d; d = tmp; } 

现在,使用NIST特别出版物800-56B推荐的算法, 对于使用整数因子分解密码学的2009年8月密钥建立方案,附录C (在https://stackoverflow.com/a/28299742/6535399中共享)我们可以计算BigInteger值。 但是,有一个棘手的微妙之处。 RSAParameters值必须具有正确的填充量,并且RSACryptoServiceProvider不会为您执行此操作。

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

使用“棘手的”BigInteger到适合的RSAParameters-byte []方法:

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

而对于计算InverseQ,您需要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; } 

在我的计算机上,我正在从(n,e,d)恢复P和Q,在~50ms内为1024位密钥。 4096位密钥〜2-4秒。

对于喜欢unit testing的实施者的注意事项:P和Q没有真正定义的顺序(就像P总是更大的约定),所以你的P和Q值可能是从你开始的RSAParameters结构向后。 因此DP和DQ也将被颠倒。

只有Mod,D和指数时,你就没有足够的东西。 (嗯,你可能已经够了)P和Q非常难以从mod中计算出来。 我不知道该怎么做,几乎肯定有更多的素数比正确的素数更多,最终得到相同的mod。

你需要至少P,Q和公共指数。

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