public bool SubmitResponse(SignatureMessage message) { bool retval = false; try { // Use the public key hint to identify which public key to use. byte[] challenge; byte[] publicKey = DAL.Instance.GetPublicKeyForUser(message.UserId, message.PublicKeyHint, out challenge); CngKey pubCngKey = new SubjectPublicKeyInfo(publicKey).GetPublicKey(); // Validate that the original challenge was signed using the corresponding private key. using (RSACng pubKey = new RSACng(pubCngKey)) { byte[] signature = Convert.FromBase64String(message.Signature); retval = pubKey.VerifyData(challenge, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } } catch (Exception) { } // Return a boolean response to the client // TODO: What should actually be returned is an authentication token (OAuth or equivalent) // that the client uses for subsequent authentication requests return retval; }
private static void TestSignVerifyDataRoundTrip(byte[] message, HashAlgorithmName hashAlgorithm, RSASignaturePadding paddingMode, int expectedSignatureLength) { using (RSA rsa = new RSACng()) { byte[] signature = rsa.SignData(message, hashAlgorithm, paddingMode); // RSACng.SignHash() is intentionally non-deterministic so we can verify that we got back a signature of the right length // but nothing about the contents. Assert.Equal(expectedSignatureLength, signature.Length); bool verified = rsa.VerifyData(message, signature, hashAlgorithm, paddingMode); Assert.True(verified); } }
/// <summary> /// Verifies the given RSA PKCSv1.5 signature. /// </summary> /// <param name="dataToVerify"></param> /// <param name="signature"></param> /// <param name="rsaCngProvider">RSA CNG Provider.</param> /// <returns>true if signature is valid, false if it is not valid</returns> private bool RSAVerifySignature(byte[] dataToVerify, byte[] signature, RSACng rsaCngProvider) { Debug.Assert((dataToVerify != null) && (dataToVerify.Length != 0)); Debug.Assert((signature != null) && (signature.Length != 0)); Debug.Assert(rsaCngProvider != null); return rsaCngProvider.VerifyData(dataToVerify, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); }
private static void TestSignAndVerifyDataFromStream(int messageSize) { RSASignaturePadding padding = RSASignaturePadding.Pkcs1; byte[] message = new byte[messageSize]; byte b = 5; for (int i = 0; i < message.Length; i++) { message[i] = b; b = (byte)((b << 4) | (i & 0xf)); } byte[] hash = SHA1.Create().ComputeHash(message); Stream stream = new MemoryStream(message); using (RSA rsa = new RSACng()) { byte[] signature = rsa.SignData(stream, HashAlgorithmName.SHA1, padding); // Since the unique codepath being tested here is HashData(Stream...), the interesting test is to see if HashData(Stream...) // computed the right hash. The easiest way to test that is to compute the hash ourselves and call VerifyHash. bool verified = rsa.VerifyHash(hash, signature, HashAlgorithmName.SHA1, padding); Assert.True(verified); stream = new MemoryStream(message); verified = rsa.VerifyData(stream, signature, HashAlgorithmName.SHA1, padding); Assert.True(verified); } }
public async Task<bool> SubmitResponse(SignatureMessage message) { bool retval = false; try { string challenge; JsonWebKey publicKey = _credentialService.GetPublicKeyForUser(message.UserId, message.PublicKeyHint, out challenge); var decodedClientData = message.ClientData.Rfc4648Base64UrlDecode(); var decodedAuthnrData = message.AuthnrData.Rfc4648Base64UrlDecode(); var clientDataJson = Encoding.UTF8.GetString(decodedClientData); var clientData = JsonConvert.DeserializeObject<ClientData>(clientDataJson); if (clientData.Challenge != challenge) return false; var sha256 = SHA256.Create(); var hashedClientData = sha256.ComputeHash(decodedClientData); var buffer = new byte[decodedAuthnrData.Length + hashedClientData.Length]; decodedAuthnrData.CopyTo(buffer, 0); hashedClientData.CopyTo(buffer, decodedAuthnrData.Length); var publicKeyInfo = new RSAParameters(); publicKeyInfo.Modulus = publicKey.N.Rfc4648Base64UrlDecode(); publicKeyInfo.Exponent = publicKey.E.Rfc4648Base64UrlDecode(); var rsa = new RSACng(); rsa.ImportParameters(publicKeyInfo); byte[] signature = message.Signature.Rfc4648Base64UrlDecode(); retval = rsa.VerifyData(buffer, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); if (retval) { var user = _signInService.FindBySubject(message.UserId); await IssueCookie(user, "idsvr", "fido"); } } catch (Exception) { } return retval; }