gpt4 book ai didi

c# - 如何在 RSA 实例的实例化中使用 Json Web key

转载 作者:行者123 更新时间:2023-11-30 16:41:26 34 4
gpt4 key购买 nike

我有一个 json 网络 key ( https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key-41 ),我想用它用私钥签署一些数据,然后用公钥验证它。我在 .net framework 4.5.1 中使用 c#,我似乎无法使用我拥有的键正确实例化类。我使用这个工具生成了 key :https://github.com/mitreid-connect/json-web-key-generator .以下 json 可用,我应该能够从中签名和验证:

{
"kty": "RSA",
"d": "rZ_cdME7usL5EavJW1q0cjz8dhfdO9P-E4dacHYFf4I-TN7o-Q0ksfWCb4fpQPghUoz6v2b6-m3IZk4CocmdEAoFH2JqI0PbH5HIBqgva-bE8-elNJIKwza0Hbrw13bRU6KgpOrc9hrX-NcRCTkeKHYtDWGUa2NDB_lNQvkyg-V0NVXf5oSa_cZ9_H4kHPXrzcBeQapn2M_CFb3qfYgVgQb5xU5n67eAcSlztWHIaSaLyu_YAR0SxnEAvWiik1rtSYrEOWsVrPHfHBFwVHluP0g--bedH6kI3mZRI6H_UbmTMnRtxBkCA5mVdzOmsyX2e98MUqIlOeDQ4zB21xSDQQ",
"e": "AQAB",
"use": "sig",
"alg": "RS512",
"n": "xwHPJaSvKvLqrqb6oeXDL3A4iNgRo5PEQOQCE5zGa6ZWeoC88IuJZxXFJ93wzJk0J22QZJWofC8vV8GAeB3d9mD25koh0dbtb0yoWK-ttWamMIAN4WPiZu30JWzxY1k8LRzOz5lIT9Ze87gV_lgXbpkzQzKFNhxOmV_BhEu1PCLcOTHhic93WQk_E97nYCOwOifmkEFOCBzHEuTG1XHJ1nGEfBCAsdUXrMg_lU3w86TfVDYS6xLVtfVAq4ihDjBsmtPthrdMG4H5Qls8EM-_cbIRe7UEAQK9MgXDLHaQZbx_lQ46_P852SpCprbvqWaoM8zKyEiDf1q6O89D6YIaDw"
}

然后在 C# 中,我有一个包含这些字段的模型,我创建了一个函数来测试我是否可以验证数据:

public class RSAKeyPair
{
public string kty { get; set; }
public string e { get; set; }
public string use { get; set; }
public string alg { get; set; }
public string n { get; set; }
public string d { get; set; }
}

和测试代码:

public static bool TestSigning(RSAKeyPair keySet)
{
if (keySet.alg != "RS512")
{
throw new ArgumentException("Only RS512 is supported.");
}

var oid = CryptoConfig.MapNameToOID("SHA512");

RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();
rsaProvider.ImportParameters(
new RSAParameters()
{
Modulus = FromBase64Url(keySet.n),
Exponent = FromBase64Url(keySet.e),
D = FromBase64Url(keySet.d)
}
);

var hasher = SHA512.Create();

var testmsg = System.Text.Encoding.UTF8.GetBytes("TestMsg");
var hash = hasher.ComputeHash(new MemoryStream(testmsg));

var signedData = rsaProvider.SignHash(hash, oid);
var isSigned = rsaProvider.VerifyHash(hash, oid, signedData);

return isSigned;
}

private static byte[] FromBase64Url(string base64Url)
{
string padded = base64Url.Length % 4 == 0
? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
string base64 = padded.Replace("_", "/")
.Replace("-", "+");
var s = Convert.FromBase64String(base64);
return s;
}

但是当我运行它时。我收到 System.Security.Cryptography.CryptographicException 消息 Object contains only the public half of a key pair。还必须提供私钥。 在尝试获取 signedData

我不知道要设置哪些参数,因为根据我对 RSA 的理解和阅读文档,这似乎是正确的。

我还尝试创建 RSACryptoServiceProvider 的两个实例,一个签名者使用 Exponent = keySet.d,一个验证者使用 Exponent = keySet.e。但是当我为签名者调用 RSACryptoServiceProvider.ImportParameters 时,它会抛出 Bad data 异常。

感谢任何帮助。

最佳答案

主要原因是RSACryptoServiceProvider无法使用模数、公共(public)和私有(private)指数生成私钥,即 n , ed只是,它需要 p , q , dpdq以及。要使用私钥生成 RsaParameters,您需要 following code计算p , q , dpdq最后生成 RsaParameters:

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

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

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

现在继续使用 JWK,如下所示:

public static bool TestSigning(RSAKeyPair keySet)
{
if (keySet.alg != "RS512")
{
throw new ArgumentException("Only SHA512 is supported.");
}


var n = GetBigInteger(FromBase64Url(keySet.n));
var d = GetBigInteger(FromBase64Url(keySet.d));
var e = GetBigInteger(FromBase64Url(keySet.e));

var rsaParams= RecoverRSAParameters(n, e, d);

RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(512);
rsaProvider.ImportParameters(rsaParams);

var hasher = SHA512.Create();

var testmsg = Encoding.UTF8.GetBytes("TestMsg");
var hash = hasher.ComputeHash(new MemoryStream(testmsg));


var oid = CryptoConfig.MapNameToOID("SHA512");

var signedData = rsaProvider.SignHash(hash, oid);
var isSigned = rsaProvider.VerifyHash(hash, oid, signedData);

return isSigned;
}

输出:

enter image description here

关于c# - 如何在 RSA 实例的实例化中使用 Json Web key ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49035158/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com