jose-jwtライブラリ を使用しており、暗号化にRS256アルゴリズムを使用してC#で署名付きJWTを作成したいと考えています。私は暗号化の経験がないので、私の無知を許してください。ドキュメントに次の例が表示されます。
var payload = new Dictionary<string, object>()
{
{ "sub", "[email protected]" },
{ "exp", 1300819380 }
};
var privateKey=new X509Certificate2("my-key.p12", "password", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet).PrivateKey as RSACryptoServiceProvider;
string token=Jose.JWT.Encode(payload, privateKey, JwsAlgorithm.RS256);
これはp12
ファイルの使用を示していますが、以下の形式のRSAキーファイルをどのように使用しますか? X509Certificate2 のドキュメントを見ていますが、RSA秘密鍵のオプションがありません。 PKCS7
のみを受け入れるようです。これは私が公開鍵であると理解しています。
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----
最後に、 docs にリストされている2つのオプションの違いは何ですか?2つのオプションをどのように選択すればよいですか?
- - - - - - - - - - - - - オプション1 - - - - - - - - - - - ----
RS- *およびPS- *ファミリー
CLR:
RS256、RS384、RS512およびPS256、PS384、PS512署名には、対応する長さのRSACryptoServiceProvider(通常はプライベート)キーが必要です。 CSPは、Microsoft Enhanced RSAおよびAES Cryptographic Providerの使用を強制する必要があります。これは通常、RSAParametersを再インポートすることで実行できます。詳細は http://clrsecurity.codeplex.com/discussions/243156 を参照してください。
--------------------------オプション2 ---------------------- ----
CORECLR:RS256、RS384、RS512署名には、対応する長さのRSA(通常はプライベート)キーが必要です。
この投稿が古いことは知っていますが、これを理解するのに永遠にかかったので、共有したいと思いました。
OpenSSLを使用してRSAキーを作成したことをテストするには:
openssl genrsa -out privateKey.pem 512
openssl rsa -in privateKey.pem -pubout -out publicKey.pem
次の2つのnugetパッケージが必要です。
テストコード
public static void Test()
{
string publicKey = File.ReadAllText(@"W:\Dev\Temp\rsa_keys\publicKey.pem");
string privateKey = File.ReadAllText(@"W:\Dev\Temp\rsa_keys\privateKey.pem");
var claims = new List<Claim>();
claims.Add(new Claim("claim1", "value1"));
claims.Add(new Claim("claim2", "value2"));
claims.Add(new Claim("claim3", "value3"));
var token = CreateToken(claims, privateKey);
var payload = DecodeToken(token, publicKey);
}
トークンを作成
public static string CreateToken(List<Claim> claims, string privateRsaKey)
{
RSAParameters rsaParams;
using (var tr = new StringReader(privateRsaKey))
{
var pemReader = new PemReader(tr);
var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
if (keyPair == null)
{
throw new Exception("Could not read RSA private key");
}
var privateRsaParams = keyPair.Private as RsaPrivateCrtKeyParameters;
rsaParams = DotNetUtilities.ToRSAParameters(privateRsaParams);
}
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(rsaParams);
Dictionary<string, object> payload = claims.ToDictionary(k => k.Type, v => (object)v.Value);
return Jose.JWT.Encode(payload, rsa, Jose.JwsAlgorithm.RS256);
}
}
トークンをデコード
public static string DecodeToken(string token, string publicRsaKey)
{
RSAParameters rsaParams;
using (var tr = new StringReader(publicRsaKey))
{
var pemReader = new PemReader(tr);
var publicKeyParams = pemReader.ReadObject() as RsaKeyParameters;
if (publicKeyParams == null)
{
throw new Exception("Could not read RSA public key");
}
rsaParams = DotNetUtilities.ToRSAParameters(publicKeyParams);
}
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(rsaParams);
// This will throw if the signature is invalid
return Jose.JWT.Decode(token, rsa, Jose.JwsAlgorithm.RS256);
}
}
https://jwt.io/ トークンをテストするのに最適なリソースです
証明書を使用する場合は、このメソッドを使用して拇印で取得できます
private X509Certificate2 GetByThumbprint(string Thumbprint)
{
var localStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
localStore.Open(OpenFlags.ReadOnly);
return localStore.Certificates//.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false)
.Find(X509FindType.FindByThumbprint, Thumbprint, false)
.OfType<X509Certificate2>().First();
}
その後:
private JwtSecurityToken GenerateJWT()
{
var securityKey = new Microsoft.IdentityModel.Tokens.X509SecurityKey(GetByThumbprint("YOUR-CERT-THUMBPRINT-HERE"));
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, "RS256");
var JWTHeader = new JwtHeader(credentials);
var payload = new JwtPayload
{
{ "iss", "Issuer-here"},
{ "exp", (Int32)(DateTime.UtcNow.AddHours(1).Subtract(new DateTime(1970, 1, 1))).TotalSeconds},
{ "iat", (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds}
};
var token = new JwtSecurityToken(JWTHeader, payload);
return token;
}
この質問の鍵は、トークンのエンコードと署名にそれぞれJWTとBouncy Castleライブラリを使用することです。
最初に、秘密鍵をRSAパラメータの形式に変換する必要があります。次に、RSAパラメータを秘密鍵としてRSAアルゴリズムに渡す必要があります。最後に、JWTライブラリを使用して、トークンをエンコードおよび署名します。
public string GenerateJWTToken(string rsaPrivateKey)
{
var rsaParams = GetRsaParameters(rsaPrivateKey);
var encoder = GetRS256JWTEncoder(rsaParams);
// create the payload according to your need
var payload = new Dictionary<string, object>
{
{ "iss", ""},
{ "sub", "" },
// and other key-values
};
// add headers. 'alg' and 'typ' key-values are added automatically.
var header = new Dictionary<string, object>
{
{ "{header_key}", "{your_private_key_id}" },
};
var token = encoder.Encode(header,payload, new byte[0]);
return token;
}
private static IJwtEncoder GetRS256JWTEncoder(RSAParameters rsaParams)
{
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(rsaParams);
var algorithm = new RS256Algorithm(csp, csp);
var serializer = new JsonNetSerializer();
var urlEncoder = new JwtBase64UrlEncoder();
var encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder;
}
private static RSAParameters GetRsaParameters(string rsaPrivateKey)
{
var byteArray = Encoding.ASCII.GetBytes(rsaPrivateKey);
using (var ms = new MemoryStream(byteArray))
{
using (var sr = new StreamReader(ms))
{
// use Bouncy Castle to convert the private key to RSA parameters
var pemReader = new PemReader(sr);
var keyPair = pemReader.ReadObject() as AsymmetricCipherKeyPair;
return DotNetUtilities.ToRSAParameters(keyPair.Private as RsaPrivateCrtKeyParameters);
}
}
}
ps:RSA秘密鍵の形式は次のとおりです。
----- RSAプライベートキーの開始-----
{base64形式の値}
----- RSAプライベートキーの終了-----
暗号化されたJWTを作成するコードは次のとおりです。
var cert = new X509Certificate2(".\\key.cer");
var rsa = (RSACryptoServiceProvider) cert.PublicKey.Key;
var payload = new Dictionary<string, object>()
{
{"sub", "[email protected]"},
{"exp", 1300819380}
};
var encryptedToken =
JWT.Encode(
payload,
rsa,
JweAlgorithm.RSA_OAEP,
JweEncryption.A256CBC_HS512,
null);
GetRSAPrivateKeyは、.NET 4.6でのみ使用できます。以下のURLをご覧ください。
公開証明書と.NET 4.6を使用している場合、デコードには以下を使用できます。
string token = "eyJhbGciOiJSUzI1NiIsInR....";
string certificate = "MIICnzCCAYcCBgFd2yEPx....";
var publicKey = new X509Certificate2(Convert.FromBase64String(certificate )).GetRSAPublicKey();
string decoded = JWT.Decode(token, publicKey, JwsAlgorithm.RS256);