예제 #1
0
        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);
        }
예제 #2
0
        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() },
            });
        }
예제 #3
0
        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);
        }
예제 #4
0
 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);
        }
예제 #6
0
        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);
        }