public static Dictionary <string, string> ExtractPublicKey(this ECDsaCng eCDsaCng) { var parameters = eCDsaCng.ExportParameters(false); string crv = string.Empty; if (parameters.Curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP256.Oid.FriendlyName) { crv = "P-256"; } else if (parameters.Curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP384.Oid.FriendlyName) { crv = "P-384"; } else if (parameters.Curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP521.Oid.FriendlyName) { crv = "P-521"; } var result = new Dictionary <string, string> { { ECFields.CURVE, crv }, { ECFields.X, parameters.Q.X.Base64EncodeBytes() }, { ECFields.Y, parameters.Q.Y.Base64EncodeBytes() } }; return(result); }
public static JObject ExtractToJson(this ECDsaCng eCDsaCng) { var parameters = eCDsaCng.ExportParameters(true); string crv = string.Empty; if (parameters.Curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP256.Oid.FriendlyName) { crv = "P-256"; } else if (parameters.Curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP384.Oid.FriendlyName) { crv = "P-384"; } else if (parameters.Curve.Oid.FriendlyName == ECCurve.NamedCurves.nistP521.Oid.FriendlyName) { crv = "P-521"; } return(new JObject { { ECFields.CURVE, crv }, { ECFields.X, parameters.Q.X.Base64EncodeBytes() }, { ECFields.Y, parameters.Q.Y.Base64EncodeBytes() }, { ECFields.D, parameters.D.Base64EncodeBytes() }, }); }
public static Dictionary <string, string> ExtractPrivateKey(this ECDsaCng eCDsaCng) { var parameters = eCDsaCng.ExportParameters(true); var result = new Dictionary <string, string> { { ECFields.D, parameters.D.Base64EncodeBytes() } }; return(result); }
public static void TestSpecialNistKeys(int keySize, string curveName, CngAlgorithm algorithm) { using (ECDsaCng cng = (ECDsaCng)ECDsaFactory.Create(keySize)) { Assert.Equal(keySize, cng.KeySize); ECParameters param = cng.ExportParameters(false); Assert.Equal(curveName, param.Curve.Oid.FriendlyName); Assert.Equal(algorithm, cng.Key.Algorithm); } }
public static CBORObject CreatePublicKeyFromU2fRegistrationData(byte[] keyHandleData, byte[] publicKeyData) { var publicKey = new ECDsaCng(ConvertPublicKey(publicKeyData)); var coseKey = CBORObject.NewMap(); coseKey.Add(COSE.KeyCommonParameter.KeyType, COSE.KeyType.EC2); coseKey.Add(COSE.KeyCommonParameter.Alg, -7); var keyParams = publicKey.ExportParameters(false); if (keyParams.Curve.Oid.FriendlyName.Equals(ECCurve.NamedCurves.nistP256.Oid.FriendlyName)) { coseKey.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P256); } coseKey.Add(COSE.KeyTypeParameter.X, keyParams.Q.X); coseKey.Add(COSE.KeyTypeParameter.Y, keyParams.Q.Y); return(coseKey); }
internal async void MakeAssertionResponse(COSE.KeyType kty, COSE.Algorithm alg, COSE.EllipticCurve crv = COSE.EllipticCurve.P256) { const string rp = "fido2.azurewebsites.net"; byte[] rpId = System.Text.Encoding.UTF8.GetBytes(rp); var rpIdHash = SHA256.Create().ComputeHash(rpId); var flags = AuthenticatorFlags.AT | AuthenticatorFlags.ED | AuthenticatorFlags.UP | AuthenticatorFlags.UV; const UInt16 signCount = 0xf1d0; var aaguid = new Guid("F1D0F1D0-F1D0-F1D0-F1D0-F1D0F1D0F1D0"); var credentialID = new byte[] { 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, 0xf1, 0xd0, }; CredentialPublicKey cpk = null; ECDsaCng ecdsa = null; RSACng rsa = null; byte[] privateKeySeed, publicKey, expandedPrivateKey = null; switch (kty) { case COSE.KeyType.EC2: { ecdsa = MakeECDsa(alg, crv); var ecparams = ecdsa.ExportParameters(true); cpk = MakeCredentialPublicKey(kty, alg, crv, ecparams.Q.X, ecparams.Q.Y); break; } case COSE.KeyType.RSA: { rsa = new RSACng(); var rsaparams = rsa.ExportParameters(true); cpk = MakeCredentialPublicKey(kty, alg, rsaparams.Modulus, rsaparams.Exponent); break; } case COSE.KeyType.OKP: { MakeEdDSA(out privateKeySeed, out publicKey, out expandedPrivateKey); cpk = MakeCredentialPublicKey(kty, alg, COSE.EllipticCurve.Ed25519, publicKey); break; } throw new ArgumentOutOfRangeException(string.Format("Missing or unknown kty {0}", kty.ToString())); } var acd = new AttestedCredentialData(aaguid, credentialID, cpk); var extBytes = CBORObject.NewMap().Add("testing", true).EncodeToBytes(); var exts = new Extensions(extBytes); var ad = new AuthenticatorData(rpIdHash, flags, signCount, acd, exts); var authData = ad.ToByteArray(); var challenge = new byte[128]; var rng = RandomNumberGenerator.Create(); rng.GetBytes(challenge); var clientData = new { Type = "webauthn.get", Challenge = challenge, Origin = rp, }; var clientDataJson = System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(clientData)); var sha = SHA256.Create(); var hashedClientDataJson = sha.ComputeHash(clientDataJson); byte[] data = new byte[authData.Length + hashedClientDataJson.Length]; Buffer.BlockCopy(authData, 0, data, 0, authData.Length); Buffer.BlockCopy(hashedClientDataJson, 0, data, authData.Length, hashedClientDataJson.Length); byte[] signature = null; switch (kty) { case COSE.KeyType.EC2: { signature = ecdsa.SignData(data, CryptoUtils.algMap[(int)alg]); break; } case COSE.KeyType.RSA: { RSASignaturePadding padding; switch (alg) // https://www.iana.org/assignments/cose/cose.xhtml#algorithms { case COSE.Algorithm.PS256: case COSE.Algorithm.PS384: case COSE.Algorithm.PS512: padding = RSASignaturePadding.Pss; break; case COSE.Algorithm.RS1: case COSE.Algorithm.RS256: case COSE.Algorithm.RS384: case COSE.Algorithm.RS512: padding = RSASignaturePadding.Pkcs1; break; default: throw new ArgumentOutOfRangeException(string.Format("Missing or unknown alg {0}", alg.ToString())); } signature = rsa.SignData(data, CryptoUtils.algMap[(int)alg], padding); break; } case COSE.KeyType.OKP: { data = CryptoUtils.GetHasher(HashAlgorithmName.SHA512).ComputeHash(data); signature = Chaos.NaCl.Ed25519.Sign(data, expandedPrivateKey); break; } throw new ArgumentOutOfRangeException(string.Format("Missing or unknown kty {0}", kty.ToString())); } if (kty == COSE.KeyType.EC2) { signature = EcDsaSigFromSig(signature, ecdsa.KeySize); } var userHandle = new byte[16]; rng.GetBytes(userHandle); var assertion = new AuthenticatorAssertionRawResponse.AssertionResponse() { AuthenticatorData = authData, Signature = signature, ClientDataJson = clientDataJson, UserHandle = userHandle, }; var lib = new Fido2(new Fido2Configuration() { ServerDomain = rp, ServerName = rp, Origin = rp, }); List <PublicKeyCredentialDescriptor> existingCredentials = new List <PublicKeyCredentialDescriptor>(); var cred = new PublicKeyCredentialDescriptor(); cred.Type = PublicKeyCredentialType.PublicKey; cred.Id = new byte[] { 0xf1, 0xd0 }; existingCredentials.Add(cred); var options = lib.GetAssertionOptions(existingCredentials, null, null); options.Challenge = challenge; var response = new AuthenticatorAssertionRawResponse() { Response = assertion, Type = PublicKeyCredentialType.PublicKey, Id = new byte[] { 0xf1, 0xd0 }, RawId = new byte[] { 0xf1, 0xd0 }, }; IsUserHandleOwnerOfCredentialIdAsync callback = (args) => { return(Task.FromResult(true)); }; var res = await lib.MakeAssertionAsync(response, options, cpk.GetBytes(), signCount - 1, callback); }