Ejemplo n.º 1
0
        /// <summary>
        ///     Gets a validation function that returns the output of a configured verification method.
        ///     Input: <c>tag || salt || AD || message</c>
        /// </summary>
        /// <returns>Callable validation function.</returns>
        /// <param name="keyConfirmation">Key confirmation configuration defining validation method to be employed.</param>
        /// <param name="tag"></param>
        /// <param name="message"></param>
        /// <param name="outputSizeBytes">Expected length of output of verification function in bytes.</param>
        /// <exception cref="ConfigurationInvalidException">
        ///     Some aspect of configuration invalid - detailed inside exception message.
        /// </exception>
        internal static Func <byte[], byte[]> GetValidator(IAuthenticationConfiguration keyConfirmation,
                                                           byte[] tag, byte[] message, int?outputSizeBytes = null)
        {
            AuthenticationFunctionType functionType = keyConfirmation.FunctionType;

            if (functionType == AuthenticationFunctionType.None)
            {
                throw new ConfigurationInvalidException("Authentication function type cannot be None.");
            }
            if (String.IsNullOrEmpty(keyConfirmation.FunctionName))
            {
                throw new ConfigurationInvalidException("Authentication function name cannot be null or empty.");
            }

            const string lengthIncompatibleString = "Expected length incompatible with function specified.";

            Func <byte[], byte[]> validator; // Used as an adaptor between different validation methods

            switch (functionType)
            {
            case AuthenticationFunctionType.Kdf:
            {
                if (outputSizeBytes == null)
                {
                    throw new ArgumentNullException("outputSizeBytes", "Cannot be null if KDF is being used.");
                }
                KeyDerivationFunction kdfEnum;
                try {
                    kdfEnum = keyConfirmation.FunctionName.ToEnum <KeyDerivationFunction>();
                } catch (EnumerationParsingException ex) {
                    throw new ConfigurationInvalidException("Key derivation function is unsupported/unknown.", ex);
                }

                validator = key =>
                {
                    int superSaltSize = keyConfirmation.Salt.Length +
                                        (keyConfirmation.AdditionalData != null ? keyConfirmation.AdditionalData.Length : 0) +
                                        (tag != null ? tag.Length : 0) +
                                        (message != null ? message.Length : 0);

                    var superSalt = new byte[superSaltSize];
                    tag.DeepCopy_NoChecks(0, superSalt, 0, tag.Length);
                    int index = tag.Length;

                    // Compose the rest of the input to the KDF (as a super-salt)
                    if (keyConfirmation.Salt.IsNullOrZeroLength() == false)
                    {
                        keyConfirmation.Salt.DeepCopy_NoChecks(0, superSalt, index, keyConfirmation.Salt.Length);
                        index += keyConfirmation.Salt.Length;
                    }
                    if (keyConfirmation.AdditionalData.IsNullOrZeroLength() == false)
                    {
                        keyConfirmation.AdditionalData.DeepCopy_NoChecks(0, superSalt, index,
                                                                         keyConfirmation.AdditionalData.Length);
                        index += keyConfirmation.AdditionalData.Length;
                    }
                    if (message.IsNullOrZeroLength() == false)
                    {
                        message.DeepCopy_NoChecks(0, superSalt, index, message.Length);
                    }

                    return(KdfFactory.DeriveKeyWithKdf(kdfEnum, key, superSalt,
                                                       outputSizeBytes.Value, keyConfirmation.FunctionConfiguration));
                };
                break;
            }

            case AuthenticationFunctionType.Mac:
                MacFunction macFEnum;
                try {
                    macFEnum = keyConfirmation.FunctionName.ToEnum <MacFunction>();
                } catch (EnumerationParsingException ex) {
                    throw new ConfigurationInvalidException("MAC function is unsupported/unknown.", ex);
                }
                validator = key => {
                    IMac macF = AuthenticatorFactory.CreateMacPrimitive(macFEnum, key, tag,
                                                                        keyConfirmation.FunctionConfiguration, keyConfirmation.Nonce);

                    if (outputSizeBytes != null && outputSizeBytes != macF.OutputSize)
                    {
                        throw new ArgumentException(lengthIncompatibleString, "outputSizeBytes");
                    }

                    if (keyConfirmation.Salt.IsNullOrZeroLength() == false)
                    {
                        macF.BlockUpdate(keyConfirmation.Salt, 0, keyConfirmation.Salt.Length);
                    }
                    if (keyConfirmation.AdditionalData.IsNullOrZeroLength() == false)
                    {
                        macF.BlockUpdate(keyConfirmation.AdditionalData, 0, keyConfirmation.AdditionalData.Length);
                    }
                    if (message.IsNullOrZeroLength() == false)
                    {
                        macF.BlockUpdate(message, 0, message.Length);
                    }

                    var output = new byte[macF.OutputSize];
                    macF.DoFinal(output, 0);
                    return(output);
                };
                break;

            default:
                throw new NotSupportedException("Function type not supported for key confirmation.");
            }

            return(validator);
        }