var byteData = Encoding.Unicode.GetBytes( encodedSerializedHeader + "." + encodedPayload);
var hasher = new SHA256CryptoServiceProvider();
var digest = hasher.ComputeHash(byteData);
var signature = await keyVaultClient.SignAsync("https://offline-token-api.vault.azure.net/keys/offlinetokenprime256v1cert/3e99b8ce5dkkk3d4fb8bc6a645e7c6aa5de",
SecurityAlgorithms.EcdsaSha256, digest);
var encodedSignature = Base64UrlEncoder.Encode(signature.Result);
Now to fetch the public key for verification i am using following:-
var secret = keyVaultClient.GetSecretAsync(vaultAddress, "offlinetokenprime256v1cert").GetAwaiter().GetResult();
X509Certificate2Collection exportedCertCollection = new X509Certificate2Collection();
exportedCertCollection.Import(Convert.FromBase64String(secret.Value));
X509Certificate2 certFromSecret = exportedCertCollection.Cast<X509Certificate2>().Single(s => s.HasPrivateKey);
var publickeybyte = certFromSecret.GetPublicKey();
var publicekeybyte = certFromSecret.GetPublicKeyString();
var privatek = certFromSecret.GetECDsaPrivateKey();
var publicECDsa = LoadPublicKey(FromHexString(publicekeybyte));
var pubpri = certFromSecret.GetECDsaPublicKey();
var privateECDsa = LoadPrivateKey(FromHexString(privateKey));
var publiccECDsa = LoadPublicKey(FromHexString(publicKey));
for offline verification -
var securityToken = new JwtSecurityToken(token);
var securityTokenHandler = new JwtSecurityTokenHandler();
IdentityModelEventSource.ShowPII = true;
var validationParameters = new TokenValidationParameters()
{
ValidIssuer = securityToken.Issuer,
ValidAudience = securityToken.Audiences.First(),
IssuerSigningKey = new ECDsaSecurityKey(eCDsa)
};
SecurityToken stoken;
var claims = securityTokenHandler.ValidateToken(token, validationParameters, out stoken);
return true;
但是出现错误,这对其他拥有相同解决方案的人来说是行不通的吗?我想在不从保管库中取出私钥的情况下签名我的令牌,并且想对jwt令牌中包含的信息进行签名。是否可以使用签名同步对令牌进行签名并脱机验证?
根据我的知识,用户无法从Azure密钥保管库密钥获取私钥。只能检索公共密钥。
这里是我用来签名和验证的示例:
KeyVaultClient kvc = new KeyVaultClient(AuthenticationCallback);
var key = kvc.GetKeyAsync(baseUrl, "ECDSA").GetAwaiter().GetResult();
var parameters = key.Key.ToECDsa().ExportParameters(false);
var pubKeyX = parameters.Q.X;
var pubKeyY = parameters.Q.Y;
// You can store X and Y, so that you may not need to get them from Azure Key Vault again
// Use X and Y to create ECDsa instance
var ecdsa = ECDsa.Create(new System.Security.Cryptography.ECParameters
{
Curve = ECCurve.NamedCurves.nistP256,
Q = new ECPoint
{
X = pubKeyX,
Y = pubKeyY
}
});
// Generate JWT
var now = DateTime.UtcNow;
var claims = new List<Claim>()
{
new Claim(JwtRegisteredClaimNames.Sub, "jack"),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Email, "[email protected]", ClaimValueTypes.String)
};
var jwt = new JwtSecurityToken(
issuer: "aaa",
audience: "bbb",
claims: claims,
notBefore: now,
expires: now.AddHours(1)
);
var header = Base64UrlEncoder.Encode(JsonConvert.SerializeObject(new Dictionary<string, string>()
{
{ JwtHeaderParameterNames.Alg, "ES256" },
{ JwtHeaderParameterNames.Kid, key.KeyIdentifier.ToString() },
{ JwtHeaderParameterNames.Typ, "JWT" }
}));
// Sign
var byteData = Encoding.UTF8.GetBytes($"{header}.{jwt.EncodedPayload}");
var hasher = new SHA256CryptoServiceProvider();
var digest = hasher.ComputeHash(byteData);
var result = kvc.SignAsync(key.KeyIdentifier.ToString(), "ES256", digest).GetAwaiter().GetResult().Result;
var signature = Base64UrlEncoder.Encode(result);
// Verify
var tokenHandler = new JwtSecurityTokenHandler();
var claimsPrincipal = tokenHandler.ValidateToken($"{header}.{jwt.EncodedPayload}.{signature}", new TokenValidationParameters
{
ValidIssuer = "aaa",
ValidAudience = "bbb",
IssuerSigningKey = new ECDsaSecurityKey(ecdsa)
}, out var parsedToken);