예제 #1
0
        /// <summary>
        /// Validates a token pair against a given action.
        /// </summary>
        /// <param name="tokenPair">Token pair to validate.</param>
        /// <param name="actionId">ID of the action to validate.</param>
        /// <returns>Whether the token pair is valid.</returns>
        public bool ValidateTokenPair(ActionTokenPair tokenPair, string actionId)
        {
            if (tokenPair == null ||
                tokenPair.Client == null ||
                tokenPair.Server == null ||
                !tokenPair.Client.IsClientPart ||
                tokenPair.Server.IsClientPart)
            {
                return(false);
            }

            var aclen = AbstractionUtilities.UTF8.GetByteCount(actionId);
            var tkc   = tokenPair.Client;
            var tks   = tokenPair.Server;

            if (!AbstractionUtilities.CompareVectorized(tkc.State, tks.State))
            {
                return(false);
            }

            var         state     = tkc.State;
            Span <byte> sigclient = stackalloc byte[SignatureSize];
            Span <byte> sigserver = stackalloc byte[SignatureSize];

            if (!this.GenerateSignatures(actionId, state, tkc.Key, tks.Key, sigclient, sigserver))
            {
                return(false);
            }

            if (!AbstractionUtilities.CompareVectorized(sigclient, tkc.Signature) ||
                !AbstractionUtilities.CompareVectorized(sigserver, tks.Signature))
            {
                return(false);
            }

            // round-trip some random data
            // if the data round-trips successfully, the tokens are a pair
            // otherwise they are not, and validation fails
            Span <byte> round0 = stackalloc byte[128];
            Span <byte> round1 = stackalloc byte[128];
            Span <byte> roundE = stackalloc byte[256];

            round1.Fill(0);
            using (var rng = new SecureRandom())
                rng.GetNonZeroBytes(round0);

            using (var rsa = RSA.Create(RsaSize))
            {
                rsa.ImportRSAPublicKey(tkc.Key, out _);
                if (!rsa.TryEncrypt(round0, roundE, RSAEncryptionPadding.OaepSHA256, out _)) // will always be 256
                {
                    return(false);
                }
            }

            using (var rsa = RSA.Create(RsaSize))
            {
                rsa.ImportRSAPrivateKey(tks.Key, out _);
                if (!rsa.TryDecrypt(roundE, round1, RSAEncryptionPadding.OaepSHA256, out var decw) || decw != round0.Length)
                {
                    return(false);
                }
            }

            return(AbstractionUtilities.CompareVectorized(round0, round1));
        }