Cryptography 如果我只有p、q、d和u,如何使用rsacryptserviceprovider进行解密?
我正在创建一个简单的客户端应用程序来进行实验,但我很难理解RSA的使用方式。让我们以会话ID的解密为例,这是登录时必须首先做的事情之一 API为我提供了以下RSA数据:Cryptography 如果我只有p、q、d和u,如何使用rsacryptserviceprovider进行解密?,cryptography,rsa,public-key-encryption,encryption-asymmetric,rsacryptoserviceprovider,Cryptography,Rsa,Public Key Encryption,Encryption Asymmetric,Rsacryptoserviceprovider,我正在创建一个简单的客户端应用程序来进行实验,但我很难理解RSA的使用方式。让我们以会话ID的解密为例,这是登录时必须首先做的事情之一 API为我提供了以下RSA数据: p(1024位) q(1024位) d(2044位) u(1024位) 首先,我不知道“u”代表什么。我从代码中看到,它是通过modinverse(p,q)计算出来的——这就是通常所说的qInverse吗 这是相当少的RSA数据的私钥比我以前使用过,所以我不太清楚如何使它。然而,据我所知,RSACryptoServicePr
- p(1024位)
- q(1024位)
- d(2044位)
- u(1024位)
modinverse(p,q)
计算出来的——这就是通常所说的qInverse吗
这是相当少的RSA数据的私钥比我以前使用过,所以我不太清楚如何使它。然而,据我所知,RSACryptoServiceProvider使用的一些RSA数据只是出于优化目的而预先计算的数据,所以可能不需要其他数据
使用此数据,站点的JavaScript使用以下函数解密会话ID:
// Compute m**d mod p*q for RSA private key operations.
function RSAdecrypt(m, d, p, q, u)
{
var xp = bmodexp(bmod(m,p), bmod(d,bsub(p,[1])), p);
var xq = bmodexp(bmod(m,q), bmod(d,bsub(q,[1])), q);
var t=bsub(xq,xp);
if(t.length==0)
{
t=bsub(xp,xq);
t=bmod(bmul(t, u), q);
t=bsub(q,t);
}
else
{
t=bmod(bmul(t, u), q);
}
return badd(bmul(t,p), xp);
}
我希望在.NET中使用RSACryptServiceProvider执行此操作,但如果我将我拥有的4条数据(假设u==qInverse)提供给它,则在导入期间会拒绝该密钥,并出现“坏数据”异常
我应该对数据做些什么吗?RSACryptoServiceProvider在这种情况下可用吗
下面是我正在测试的参数和加密数据的示例
var p = Convert.FromBase64String("1AkMwy3SPbJtL/k2RUPNztBQKow0NX9LVr5/73+zR3cuwgUToYkVefKdzlTgeri9CAVUq/+jU6o+P7sUpPUN+V97quZa00m3GSIdonRMdaMrDDH5aHnkQgOsCjLJDWXU6+TQBqLumR3XMSat3VO09Dps+6NcMc+uMi5atC3tb+0=");
var q = Convert.FromBase64String("qtnlmPbATJajNdihw1K6cwSormySATp7g75vYfilYx6RXN3xpNCZR/i8zFbx/lDh+n1a2rdHy1nWyuaD3UmE26d1xUkmsPDfBc72WXt88UqWE/gF7NJjtgTxS2Ui+2GGKUCloi5UA/pOI7R5TBvGI8zna00SH78bctyE0dcAcwM=");
var d = Convert.FromBase64String("CFL4QPQ8zLzrf2bUzCVX8S2/eALzo/P2cvQsW9lft7uelHYfC1CvHP+z4RvQgXABpgT8YTdU+sgdMHrhHT1vxeUaDRkcQv9lV0IP6YtAcD+gk5jDQkXk4ruYztTUF3v4u8rlMuZ8kAKKWKw+JH6grLWD/vXjMv2RybxPqq3fKI6VJaj/Y/ZnDjD5HrQmJopnCbOrZrPysNb/rGrN3ad9ysaZwBvQtIE0/tQvmL+lsI+PfF9oGKeHkciIo0D4N2abOKT2fiazNm1U9LnrQih687ge0aeAlP2OO8c0h/nbEkMbNg83n1GGEt3DNojIWbT5uHaj12M6G81leS77mfLvSQ==");
var u = Convert.FromBase64String("CNlUzgCf6Ymd/qeWiv3ScCIXYCwjP3SNLHxRgozIbNg2JEKpJn2M3vO72qLI+FT34xckaAGIcKWMkmpoaKy6PYF4jsAz2atLEClLimbMEPvpWxK7b/I5yvXMT7i2r5hr0OjjplL0wFQYL1IS2M8DTrL99rd9zXCoCWg5Tax6zQM=");
var encryptedData = Convert.FromBase64String("CABt/Qp7ZODvweEk5RY9JNMXoyFfUwMnc53zbP5jB4jnwWXibLLvjc+Dv5CwQAtUYRme+vRd80++178BiWl0YSOKKhQaDQKoeOUONn3KbZVWyCtyWyQZNtASPoQfizay/Dw3yP5BKsJmDpEv47awdEZzh8IqTcTKeQbpHFL+3uL5EjIENpxMh15rJUsY9w+jq6Yax+379tq67EPMUON0aYkRQ3k1Rsp9fOL6qrgoqOPmOc0cIQgx76t6SFB9LmDySkyBhtK+vcEkdn9GwzZqc6n/Jqt9K8a+mbBv3K7eO3Pa37SDncsaxEzlyLwQ2om1+bK2QwauSQl+7QwQS1a9Ejb9");
var rsa = new RSACryptoServiceProvider();
// Throws exception saying "Bad data"
rsa.ImportParameters(new RSAParameters
{
D = d,
P = p,
Q = q,
InverseQ = u
});
附录2月2日
我已经在链接的StackOverflow答案中找到了答案,我认为我已经确定了如何生成缺少的组件。然而,现在我遇到了一个“坏键”异常,这让我很困惑
我将编写用于生成缺失组件的代码——也许您可以在某处发现错误
我还手动计算了InverseQ和D,其值与输入数据中的值相匹配。以下是我仅基于q、p和e生成所需数据的函数
private static RSAParameters CalculateRsaParameters(BigInteger p, BigInteger q, BigInteger e)
{
var modulus = BigInteger.Multiply(p, q);
var phi = BigInteger.Multiply(BigInteger.Subtract(p, BigInteger.One), BigInteger.Subtract(q, BigInteger.One));
BigInteger x, y;
// From http://www.codeproject.com/Articles/60108/BigInteger-Library
// Returns 1 with my test data.
ExtendedEuclidGcd(e, phi, out x, out y);
var d = BigInteger.Remainder(x, phi);
var dp = BigInteger.Remainder(d, BigInteger.Subtract(p, BigInteger.One));
var dq = BigInteger.Remainder(d, BigInteger.Subtract(q, BigInteger.One));
BigInteger x2, y2;
// Returns 1 with my test data.
ExtendedEuclidGcd(q, p, out x2, out y2);
// y2 since it matched the pre-generated inverseQ data I had and x2 was some negative value, so it did not seem to fit. I have no idea what the logic behind which to pick really is.
var qInverse = BigInteger.Remainder(y2, p);
return new RSAParameters
{
D = ToBigEndianByteArray(d, 256),
DP = ToBigEndianByteArray(dp, 128),
DQ = ToBigEndianByteArray(dq, 128),
InverseQ = ToBigEndianByteArray(qInverse, 128),
Exponent = ToBigEndianByteArray(e, 1),
Modulus = ToBigEndianByteArray(modulus, 256),
P = ToBigEndianByteArray(p, 128),
Q = ToBigEndianByteArray(q, 128)
};
}
我的输入数据是:
e = 17
p = 148896287039501678969147386479458178246000691707699594019852371996225136011987881033904404601666619814302065310828663028471342954821076961960815187788626496609581811628527023262215778397482476920164511192915070597893567835708908996890192512834283979142025668876250608381744928577381330716218105191496818716653
q = 119975764355551220778509708561576785383941026741388506773912560292606151764383332427604710071170171329268379604135341015979284377183953677973647259809025842247294479469402755370769383988530082830904396657573472653613365794770434467132057189606171325505138499276437937752474437953713231209677228298628994462467
下面是我如何利用生成的结构:
var rsa = new RSACryptoServiceProvider(2048);
rsa.ImportParameters(CalculateRsaParameters(p, q, e));
ImportParameters
调用抛出一个异常,表示“坏键”。我做错了什么
如果我切换Q和p会发生什么?
显然,它使RSACryptServiceProvider接受数据!但这到底意味着什么
我是通过在生成代码中使用extendededeeuclidgcd
的方式得到这个想法的。对这两个实例使用不同的输出让我很烦恼,所以我做了这个实验
有一件事是u!=qInverse
-这是正确的吗?我不理解原始JavaScript函数中的数学运算,因此我不确定其含义是什么。我猜原稿中的u值实际上是某种内部捷径,而不是QInverse,对吗
后续的进一步测试(即数据的实际解密)。一旦有了新的进展,我将对问题进行编辑
设置此参数后解密失败
我拥有的加密测试数据是(base64编码):
由于我不确定字节顺序,因此给出了两个备选方案。两个字符串中的数据相同
在第一种情况下,解密这两个命令都失败,出现一个异常,即“坏数据”和“没有足够的存储空间来处理此命令”。在第二种情况下(MSDN声称这可能意味着密钥与加密数据不匹配)。我告诉RSACryptServiceProvider使用了PKCS填充,尽管我也尝试了OAEP(它只是给出了一个关于无法解码填充的错误)
最初的JavaScript解密数据没有问题,尽管它的“p”和“q”与我的不同
现在,我的问题是:
- P和Q开关是否是有效的操作
- 我的推理是正确的还是我在什么地方犯了错误
- 要成功解密测试数据,我接下来应该做什么
看看在使用.NET大整数和RSA参数时,可能会遇到许多陷阱。两个可能影响你的是endianness和leading zero suppression 类从.NET4.0开始提供,它的方法和构造函数使用litte-endian格式 不幸的是,该结构期望其字节数组字段采用大端顺序。还有另一个不相容性必须考虑。
System.Numerics.BigInteger
可以是正的,也可以是负的,ToByteArray()
方法通过使用twos补码表示法的变体来解释这一点。实际上,这意味着字节数组表示形式具有高阶字节>=
128将有一个额外的零字节置于最高顺序位置。但是,假定rsapameter
字段均为正,因此前导零会被无偿拒绝,并出现“坏数据”加密异常。必须删除出现这些前导零的位置
以下是显示这些操作的简单示例代码片段:
static BigInteger ExtGCD(BigInteger a, BigInteger b, out BigInteger lastx, out BigInteger lasty)
{
var x = BigInteger.Zero;
lastx = BigInteger.One;
var y = BigInteger.One;
lasty = BigInteger.Zero;
while (!b.IsZero)
{
BigInteger remainder;
BigInteger q = BigInteger.DivRem(a, b, out remainder);
a = b;
b = remainder;
var t = x;
x = lastx - q * x;
lastx = t;
t = y;
y = lasty - q * y;
lasty = t;
}
return a;
}
static BigInteger inverse(BigInteger a, BigInteger n)
{
BigInteger d, x, y;
d = ExtGCD(a, n, out x, out y);
if (d.IsOne)
{
// Always return the least positive value
return (x + n) % n;
}
else
{
throw new ArgumentException("the arguments must be relatively prime, i.e. their gcd must be 1");
}
}
static byte[] ToByteArrayBE(BigInteger b)
{
var x = b.ToByteArray(); // x is little-endian
Array.Reverse(x); // now it is big-endian
if (x[0] == 0)
{
var newarray = new byte[x.Length - 1];
Array.Copy(x, 1, newarray, 0, newarray.Length);
return newarray;
} else
{
return x;
}
}
static RSAParameters CalculateRsaParameters(BigInteger p, BigInteger q, BigInteger e)
{
// Given p, q, and e (the RSA encryption exponent) compute the remaining parameters
var phi = (p - 1) * (q - 1);
var d = inverse(e, phi);
var dp = d % (p - 1);
var dq = d % (q - 1);
var qInv = inverse(q, p);
var RsaParams = new RSAParameters
{
Modulus = ToByteArrayBE(p * q),
Exponent = ToByteArrayBE(e),
P = ToByteArrayBE(p),
Q = ToByteArrayBE(q),
D = ToByteArrayBE(d),
DP = ToByteArrayBE(dp),
DQ = ToByteArrayBE(dq),
InverseQ = ToByteArrayBE(qInv)
};
return RsaParams;
}
static void Main(string[] args)
{
BigInteger p = BigInteger.Parse("148896287039501678969147386479458178246000691707699594019852371996225136011987881033904404601666619814302065310828663028471342954821076961960815187788626496609581811628527023262215778397482476920164511192915070597893567835708908996890192512834283979142025668876250608381744928577381330716218105191496818716653");
BigInteger q = BigInteger.Parse("119975764355551220778509708561576785383941026741388506773912560292606151764383332427604710071170171329268379604135341015979284377183953677973647259809025842247294479469402755370769383988530082830904396657573472653613365794770434467132057189606171325505138499276437937752474437953713231209677228298628994462467");
BigInteger e = new BigInteger(17);
RSAParameters RsaParams = CalculateRsaParameters(p, q, e);
var Rsa = new RSACryptoServiceProvider();
Rsa.ImportParameters(RsaParams);
}
}
听起来很合理,但我希望情况并非如此,因为我没有所有可用的数据。现有的JavaScript实现只能用我列出的4条数据执行RSA解密操作——这是我想要复制的行为。请参阅我指向GregS answer的注释。您可能需要提供所有数据,但计算数据应该相对容易,特别是因为您已经拥有私有指数
D
。您需要计算其余参数。请参阅:缺少“e”参数。显然是17号。@GregS我想你把它放在这里很好:谢谢,owlstead和@GregS-you
static BigInteger ExtGCD(BigInteger a, BigInteger b, out BigInteger lastx, out BigInteger lasty)
{
var x = BigInteger.Zero;
lastx = BigInteger.One;
var y = BigInteger.One;
lasty = BigInteger.Zero;
while (!b.IsZero)
{
BigInteger remainder;
BigInteger q = BigInteger.DivRem(a, b, out remainder);
a = b;
b = remainder;
var t = x;
x = lastx - q * x;
lastx = t;
t = y;
y = lasty - q * y;
lasty = t;
}
return a;
}
static BigInteger inverse(BigInteger a, BigInteger n)
{
BigInteger d, x, y;
d = ExtGCD(a, n, out x, out y);
if (d.IsOne)
{
// Always return the least positive value
return (x + n) % n;
}
else
{
throw new ArgumentException("the arguments must be relatively prime, i.e. their gcd must be 1");
}
}
static byte[] ToByteArrayBE(BigInteger b)
{
var x = b.ToByteArray(); // x is little-endian
Array.Reverse(x); // now it is big-endian
if (x[0] == 0)
{
var newarray = new byte[x.Length - 1];
Array.Copy(x, 1, newarray, 0, newarray.Length);
return newarray;
} else
{
return x;
}
}
static RSAParameters CalculateRsaParameters(BigInteger p, BigInteger q, BigInteger e)
{
// Given p, q, and e (the RSA encryption exponent) compute the remaining parameters
var phi = (p - 1) * (q - 1);
var d = inverse(e, phi);
var dp = d % (p - 1);
var dq = d % (q - 1);
var qInv = inverse(q, p);
var RsaParams = new RSAParameters
{
Modulus = ToByteArrayBE(p * q),
Exponent = ToByteArrayBE(e),
P = ToByteArrayBE(p),
Q = ToByteArrayBE(q),
D = ToByteArrayBE(d),
DP = ToByteArrayBE(dp),
DQ = ToByteArrayBE(dq),
InverseQ = ToByteArrayBE(qInv)
};
return RsaParams;
}
static void Main(string[] args)
{
BigInteger p = BigInteger.Parse("148896287039501678969147386479458178246000691707699594019852371996225136011987881033904404601666619814302065310828663028471342954821076961960815187788626496609581811628527023262215778397482476920164511192915070597893567835708908996890192512834283979142025668876250608381744928577381330716218105191496818716653");
BigInteger q = BigInteger.Parse("119975764355551220778509708561576785383941026741388506773912560292606151764383332427604710071170171329268379604135341015979284377183953677973647259809025842247294479469402755370769383988530082830904396657573472653613365794770434467132057189606171325505138499276437937752474437953713231209677228298628994462467");
BigInteger e = new BigInteger(17);
RSAParameters RsaParams = CalculateRsaParameters(p, q, e);
var Rsa = new RSACryptoServiceProvider();
Rsa.ImportParameters(RsaParams);
}
}