Example #1
0
        internal BCryptHMAC(CngAlgorithm algorithm,
                            CngProvider algorithmProvider,
                            string hashName,
                            int blockSize,
                            byte[] key)
        {
            Debug.Assert(algorithm != null, "algorithm != null");
            Debug.Assert(algorithmProvider != null, "algorithmProvider != null");
            Debug.Assert(!String.IsNullOrEmpty(hashName), "!String.IsNullOrEmpty(hashName)");
            Debug.Assert(blockSize > 0, "blockSize > 0");
            Debug.Assert(key != null, "key != null");

            BlockSizeValue = blockSize;
            HashName       = hashName;

            m_algorithm = BCryptNative.OpenAlgorithm(algorithm.Algorithm,
                                                     algorithmProvider.Provider,
                                                     BCryptNative.AlgorithmProviderOptions.HmacAlgorithm);

            // Resetting the key will call Initialize for us, and get us setup with a hash handle,
            // so we don't need to create the hash handle ourselves
            Key = key;

            HashSizeValue = BCryptNative.GetInt32Property(m_hash, BCryptNative.HashPropertyName.HashLength) * 8;
        }
        internal BCryptAuthenticatedSymmetricAlgorithm(CngAlgorithm algorithm,
                                                       CngProvider implementation,
                                                       KeySizes[] legalBlockSizes,
                                                       KeySizes[] legalKeySizes)
        {
            Debug.Assert(algorithm != null, "algorithm != null");
            Debug.Assert(implementation != null, "implementation != null");
            Debug.Assert(legalBlockSizes != null, "legalBlockSizes != null");
            Debug.Assert(legalKeySizes != null, "legalKeySizes != null");

            m_algorithm      = algorithm;
            m_implementation = implementation;
            m_chainingMode   = CngChainingMode.Gcm;

            LegalBlockSizesValue = legalBlockSizes;
            LegalKeySizesValue   = legalKeySizes;

            // Create a temporary algorithm handle so that we can query it for some properties - such as the
            // block and tag sizes.
            using (SafeBCryptAlgorithmHandle algorithmHandle = SetupAlgorithm())
            {
                // Get block size in bits
                BlockSize = BCryptNative.GetInt32Property(algorithmHandle, BCryptNative.ObjectPropertyName.BlockLength) * 8;

                UpdateLegalTagSizes(algorithmHandle);
            }
        }
Example #3
0
        internal BCryptHMAC(CngAlgorithm algorithm,
                            CngProvider algorithmProvider,
                            string hashName,
                            int blockSize,
                            byte[] key)
        {
            Debug.Assert(algorithm != null, "algorithm != null");
            Debug.Assert(algorithmProvider != null, "algorithmProvider != null");
            Debug.Assert(!String.IsNullOrEmpty(hashName), "!String.IsNullOrEmpty(hashName)");
            Debug.Assert(blockSize > 0, "blockSize > 0");
            Debug.Assert(key != null, "key != null");

            BlockSizeValue = blockSize;

            // We set the HashName up to be the CNG version of the hash, since the base type will instantiate
            // the algorithm, and the CNG versions have different FIPS characteristics than the standard implementations.
            HashName = String.Format(CultureInfo.InvariantCulture,
                                     "System.Security.Cryptography.{0}Cng, {1}",
                                     hashName,
                                     typeof(SHA256Cng).Assembly.FullName);

            m_implementation = algorithmProvider;

            m_algorithm = BCryptNative.OpenAlgorithm(algorithm.Algorithm,
                                                     algorithmProvider.Provider,
                                                     BCryptNative.AlgorithmProviderOptions.HmacAlgorithm);

            // Resetting the key will call Initialize for us, and get us setup with a hash handle,
            // so we don't need to create the hash handle ourselves
            Key = key;

            HashSizeValue = BCryptNative.GetInt32Property(m_hash, BCryptNative.HashPropertyName.HashLength) * 8;
        }
Example #4
0
        public override void GetBytes(byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

            BCryptNative.GenerateRandomBytes(m_algorithm, data);
        }
Example #5
0
        public RNGCng(CngProvider algorithmProvider)
        {
            if (algorithmProvider == null)
            {
                throw new ArgumentNullException("algorithmProvider");
            }

            m_algorithm = BCryptNative.OpenAlgorithm(BCryptNative.AlgorithmName.Rng,
                                                     algorithmProvider.Provider);
        }
        private SafeBCryptAlgorithmHandle SetupAlgorithm()
        {
            // Open the algorithm handle
            SafeBCryptAlgorithmHandle algorithm =
                BCryptNative.OpenAlgorithm(m_algorithm.Algorithm, m_implementation.Provider);

            // Set the chaining mode
            BCryptNative.SetStringProperty(algorithm,
                                           BCryptNative.ObjectPropertyName.ChainingMode,
                                           m_chainingMode.ChainingMode);

            return(algorithm);
        }
Example #7
0
        private SafeBCryptAlgorithmHandle SetupAlgorithm()
        {
            SafeBCryptAlgorithmHandle algorithmHandle = BCryptNative.OpenAlgorithm(m_algorithm.Algorithm, m_algorithmProvider.Provider);

            // If we've selected a different block size than the default, set that now
            if (BlockSize / 8 != BCryptNative.GetInt32Property(algorithmHandle, BCryptNative.ObjectPropertyName.BlockLength))
            {
                BCryptNative.SetInt32Property(algorithmHandle, BCryptNative.ObjectPropertyName.BlockLength, BlockSize / 8);
            }

            BCryptNative.SetStringProperty(algorithmHandle, BCryptNative.ObjectPropertyName.ChainingMode, BCryptNative.MapChainingMode(Mode));

            return(algorithmHandle);
        }
        public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
        {
            if (inputBuffer == null)
            {
                throw new ArgumentNullException("inputBuffer");
            }
            if (inputOffset < 0)
            {
                throw new ArgumentOutOfRangeException("inputOffset");
            }
            if (inputCount < 0)
            {
                throw new ArgumentOutOfRangeException("inputCount");
            }
            if (inputCount > inputBuffer.Length - inputOffset)
            {
                throw new ArgumentOutOfRangeException("inputCount");
            }

            if (m_encrypting)
            {
                // We need to pad the final block before encrypting it
                byte[] paddedBlock = m_paddingMode.PadBlock(inputBuffer, inputOffset, inputCount);
                if (paddedBlock.Length > 0)
                {
                    return(BCryptNative.SymmetricEncrypt(m_key, m_iv, paddedBlock));
                }
                else
                {
                    return(paddedBlock);
                }
            }
            else
            {
                // We can't decrypt a partial final block
                if (inputCount % InputBlockSize != 0)
                {
                    throw new CryptographicException(Properties.Resources.CannotDecryptPartialBlock);
                }

                // Decrypt all remaining data
                byte[] plaintext       = new byte[inputCount + (m_depadBuffer != null ? m_depadBuffer.Length : 0)];
                int    plaintextLength = DecryptBlocks(inputBuffer, inputOffset, inputCount, plaintext, 0, false);

                // Remove any padding
                return(m_paddingMode.DepadBlock(plaintext, 0, plaintextLength));
            }
        }
Example #9
0
        public override void Initialize()
        {
            Debug.Assert(m_algorithm != null, "m_algorithm != null");

            base.Initialize();

            // If we have a previously used hash handle, we can clean it up now
            if (m_hash != null)
            {
                m_hash.Dispose();
            }

            m_hash = BCryptNative.CreateHash(m_algorithm, KeyValue);

            // We're allowed to reset the key at this point
            State = 0;
        }
        private int EncryptBlocks(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
        {
            Debug.Assert(inputBuffer != null, "inputBuffer != null");
            Debug.Assert(inputOffset >= 0, "inputOffset >= 0");
            Debug.Assert(inputCount >= 0 && inputCount <= inputBuffer.Length - inputOffset, "inputCount >= 0 && inputCount <= inputBuffer.Length - inputOffset");
            Debug.Assert(inputCount % InputBlockSize == 0, "inputCount % InputBlockSize == 0");
            Debug.Assert(outputBuffer != null, "outputBuffer != null");
            Debug.Assert(inputCount <= outputBuffer.Length - outputOffset, "inputCount <= outputBuffer.Length - outputOffset");

            // Pull the input into a stand alone array
            byte[] plaintext = new byte[inputCount];
            Buffer.BlockCopy(inputBuffer, inputOffset, plaintext, 0, plaintext.Length);

            // Do the encryption
            byte[] ciphertext = BCryptNative.SymmetricEncrypt(m_key, m_iv, plaintext);

            // Copy the output to the destination array
            Buffer.BlockCopy(ciphertext, 0, outputBuffer, outputOffset, ciphertext.Length);
            return(ciphertext.Length);
        }
        internal BCryptSymmetricCryptoTransform(SafeBCryptAlgorithmHandle algorithm,
                                                byte[] key,
                                                byte[] iv,
                                                PaddingMode paddingMode,
                                                bool encrypting)
        {
            Debug.Assert(algorithm != null, "algorithm != null");
            Debug.Assert(!algorithm.IsClosed && !algorithm.IsInvalid, "!algorithm.IsClosed && !algorithm.IsInvalid");
            Debug.Assert(key != null, "key != null");

            m_algorithm  = algorithm;
            m_encrypting = encrypting;

            m_paddingMode = BlockPaddingMethod.Create(paddingMode,
                                                      BCryptNative.GetInt32Property(algorithm, BCryptNative.ObjectPropertyName.BlockLength));
            m_iv = ProcessIV(iv, BCryptNative.GetInt32Property(algorithm,
                                                               BCryptNative.ObjectPropertyName.BlockLength),
                             BCryptNative.MapChainingMode(BCryptNative.GetStringProperty(algorithm, BCryptNative.ObjectPropertyName.ChainingMode)));
            m_key = BCryptNative.ImportSymmetricKey(algorithm, key);
        }
        private void UpdateLegalTagSizes(SafeBCryptAlgorithmHandle algorithm)
        {
            Debug.Assert(algorithm != null, "algorithm != null");
            Debug.Assert(!algorithm.IsClosed && !algorithm.IsInvalid, "!algorithm.IsClosed && !algorithm.IsInvalid");

            // Get the authentication tag length structure.
            BCryptNative.BCRYPT_KEY_LENGTHS_STRUCT tagLengths =
                BCryptNative.GetValueTypeProperty <SafeBCryptAlgorithmHandle, BCryptNative.BCRYPT_KEY_LENGTHS_STRUCT>(
                    algorithm,
                    BCryptNative.ObjectPropertyName.AuthTagLength);

            // BCrypt returns the tag sizes in bytes, convert them to bits for the LegalTagSizes property
            LegalTagSizesValue = new KeySizes[]
            {
                new KeySizes(tagLengths.dwMinLength * 8, tagLengths.dwMaxLength * 8, tagLengths.dwIncrement * 8)
            };

            // By default, generate the maximum authentication tag length possible for this algorithm
            TagSize = tagLengths.dwMaxLength * 8;
        }
Example #13
0
        internal void HashCoreImpl(byte[] rgb, int ib, int cb)
        {
            if (rgb == null)
            {
                throw new ArgumentNullException("rgb");
            }
            if (ib < 0 || ib > rgb.Length - cb)
            {
                throw new ArgumentOutOfRangeException("ib");
            }
            if (cb < 0 || cb > rgb.Length)
            {
                throw new ArgumentOutOfRangeException("cb");
            }

            // Tell the base class that resetting the key is no longer allowed
            State = 1;

            byte[] data = new byte[cb];
            Buffer.BlockCopy(rgb, ib, data, 0, data.Length);
            BCryptNative.HashData(m_hash, data);
        }
        private byte[] CngTransform(byte[] input, int inputOffset, int inputCount)
        {
            Debug.Assert(m_key != null, "key != null");
            Debug.Assert(!m_key.IsClosed && !m_key.IsInvalid, "!m_key.IsClosed && !m_key.IsInvalid");
            Debug.Assert(input != null, "input != null");
            Debug.Assert(inputOffset >= 0, "inputOffset >= 0");
            Debug.Assert(inputCount >= 0, "inputCount >= 0");
            Debug.Assert(inputCount <= input.Length - inputOffset, "inputCount <= input.Length - inputOffset");

            byte[] inputBuffer = null;
            try
            {
                // Build up a buffer of the only portion of the input we should be transforming
                inputBuffer = input;
                if (inputOffset > 0 || inputCount != input.Length)
                {
                    inputBuffer = new byte[inputCount];
                    Array.Copy(input, inputOffset, inputBuffer, 0, inputBuffer.Length);
                }

                if (m_encrypting)
                {
                    return(BCryptNative.SymmetricEncrypt(m_key, inputBuffer, m_chainData, ref m_authInfo));
                }
                else
                {
                    return(BCryptNative.SymmetricDecrypt(m_key, inputBuffer, this.m_chainData, ref m_authInfo));
                }
            }
            finally
            {
                if (inputBuffer != input)
                {
                    // Zeroize the input buffer if we allocated one
                    Array.Clear(inputBuffer, 0, inputBuffer.Length);
                }
            }
        }
Example #15
0
        /// <summary>
        /// Compute the PBKDF2 function on the given inputs using the CNG implementation in the <c>BCryptKeyDerivation</c> API.
        /// </summary>
        /// <param name="hashName">The hash function to use, must be one of the strings in <seealso cref="PBKDF2HashAlgorithm"/>.</param>
        /// <param name="password">The password, as a byte array (i.e., without a string termination character).</param>
        /// <param name="salt">The salt, a cryptographically random value. Should be 16-bytes or longer.</param>
        /// <param name="cIterations">The number of iterations of PBKDF2 to apply.</param>
        /// <returns>The digest of the password (also sometimes called derived key).  The length of the digest
        /// will be equal to the length of the chosen hash function output.</returns>
        /// <remarks>
        /// See http://msdn.microsoft.com/en-us/library/windows/desktop/hh448506 for a description
        /// of the wrapped function.  Larger values of cIterations will cause the function to use more
        /// CPU time, and will also increase the workfactor for an attacker in a brute-force attack.
        /// </remarks>
        public static byte[] ComputeHash(string hashName, byte[] password, byte[] salt, Int64 cIterations)
        {
            if (cIterations < 1)
            {
                throw new ArgumentException("Iteration count must be greater than zero.", "cIterations");
            }
            if (salt == null)
            {
                throw new ArgumentException("Salt must be non-null", "salt");
            }
            if (password == null)
            {
                throw new ArgumentException("Password must be non-null", "password");
            }

            if (!PBKDF2HashAlgorithm.ValidateHashName(hashName))
            {
                throw new ArgumentException("Invalid hash name for PBKDF2");
            }

            byte[] digest = null;

            double vers = Environment.OSVersion.Version.Major + Environment.OSVersion.Version.Minor * 0.1;

            if (vers > 6.1)
            {
                // The BCryptKeyDerivation API is only supported on Win8/Server 2012 and above
                digest = BCryptNative.PBKDF2BCryptKeyDerivation(hashName, password, salt, (UInt64)cIterations);
            }
            else
            {
                // Fall back to BCryptDeriveKeyPBKDF2, which is roughly 2x slower on systems without the KeyDerivation API
                digest = BCryptNative.PBKDF2BCryptDeriveKeyPBKDF2(hashName, password, salt, (UInt64)cIterations);
            }

            return(digest);
        }
Example #16
0
 internal byte[] HashFinalImpl()
 {
     return(BCryptNative.FinishHash(m_hash));
 }
        internal BCryptAuthenticatedSymmetricCryptoTransform(SafeBCryptAlgorithmHandle algorithm,
                                                             byte[] key,
                                                             byte[] nonce,
                                                             byte[] authenticatedData,
                                                             byte[] tag,
                                                             bool chainingSupported)
        {
            Debug.Assert(algorithm != null, "algorithm != null");
            Debug.Assert(!algorithm.IsClosed && !algorithm.IsInvalid, "!algorithm.IsClosed && !algorithm.IsInvalid");

            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            if (tag == null)
            {
                throw new ArgumentNullException("tag");
            }

            bool initializationComplete = false;

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                m_algorithm = algorithm;
                m_key       = BCryptNative.ImportSymmetricKey(algorithm, key);

                // Initialize the padding info structure.
                m_authInfo = new BCryptNative.BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO();
                BCryptNative.InitializeAuthnenticatedCipherModeInfo(ref m_authInfo);

                if (nonce != null)
                {
                    m_authInfo.cbNonce = nonce.Length;
                    m_authInfo.pbNonce = Marshal.AllocCoTaskMem(m_authInfo.cbNonce);
                    Marshal.Copy(nonce, 0, m_authInfo.pbNonce, m_authInfo.cbNonce);
                }

                if (authenticatedData != null)
                {
                    m_authInfo.cbAuthData = authenticatedData.Length;
                    m_authInfo.pbAuthData = Marshal.AllocCoTaskMem(m_authInfo.cbAuthData);
                    Marshal.Copy(authenticatedData, 0, m_authInfo.pbAuthData, m_authInfo.cbAuthData);
                }

                if (chainingSupported)
                {
                    m_chainingSupported = chainingSupported;

                    m_authInfo.cbMacContext = tag.Length;
                    m_authInfo.pbMacContext = Marshal.AllocCoTaskMem(m_authInfo.cbMacContext);

                    BCryptNative.BCRYPT_KEY_LENGTHS_STRUCT tagLengths =
                        BCryptNative.GetValueTypeProperty <SafeBCryptAlgorithmHandle, BCryptNative.BCRYPT_KEY_LENGTHS_STRUCT>(
                            algorithm,
                            BCryptNative.ObjectPropertyName.AuthTagLength);

                    m_chainData = new byte[tagLengths.dwMaxLength];
                }
                else
                {
                    m_inputBuffer = new MemoryStream();
                }

                m_authInfo.cbTag = tag.Length;
                m_authInfo.pbTag = Marshal.AllocCoTaskMem(m_authInfo.cbTag);
                Marshal.Copy(tag, 0, m_authInfo.pbTag, m_authInfo.cbTag);

                // Set chaining mode if supported.
                if (CanChainBlocks)
                {
                    m_authInfo.dwFlags |= BCryptNative.AuthenticatedCipherModeInfoFlags.ChainCalls;
                }

                initializationComplete = true;
            }
            finally
            {
                // If we failed to complete initialization we may have already allocated some native
                // resources.  Clean those up before leaving the constructor.
                if (!initializationComplete)
                {
                    Dispose();
                }
            }
        }
        private int DecryptBlocks(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset, bool bufferLastBlock)
        {
            Debug.Assert(inputBuffer != null, "inputBuffer != null");
            Debug.Assert(inputOffset >= 0, "inputOffset >= 0");
            Debug.Assert(inputCount >= 0 && inputCount <= inputBuffer.Length - inputOffset, "inputCount >= 0 && inputCount <= inputBuffer.Length - inputOffset");
            Debug.Assert(inputCount % InputBlockSize == 0, "inputCount % InputBlockSize == 0");
            Debug.Assert(outputBuffer != null, "outputBuffer != null");
            Debug.Assert(inputCount <= outputBuffer.Length - outputOffset, "inputCount <= outputBuffer.Length - outputOffset");

            int decryptedBytes = 0;

            byte[] ciphertext = null;

            //
            // When decrypting, it's possible for us to be called with the final blocks of data in
            // TransformBlock, and then called with an empty TransformFinalBlock.  This means that we always
            // need to keep the last block of data we see in a depad buffer and not decrypt it until the
            // next TransformBlock or TransformFinalBlock is called.  Otherwise, we could end up decrypting
            // the padding bytes on the last call to TransformBlock and passing them out to our caller as
            // plaintext, when in fact we should have stripped them.
            //

            // If the padding cannot be removed, then we don't need to buffer the final block.
            if (!m_paddingMode.CanRemovePadding)
            {
                bufferLastBlock = false;
            }

            // If we've previously saved data to decrypt, we need to do that first.  Otherwise, we need
            // to allocate a buffer to save the last block of the incoming data in.
            if (m_depadBuffer != null)
            {
                byte[] decryptedDepad = BCryptNative.SymmetricDecrypt(m_key, m_iv, m_depadBuffer);
                Buffer.BlockCopy(decryptedDepad, 0, outputBuffer, outputOffset, decryptedDepad.Length);
                decryptedBytes += decryptedDepad.Length;
                outputOffset   += decryptedDepad.Length;
            }

            // If we need to save the last block of data, do that now
            if (bufferLastBlock)
            {
                if (m_depadBuffer == null)
                {
                    m_depadBuffer = new byte[InputBlockSize];
                }

                // Copy the last block of data to the depad buffer, and decrypt the first blocks now.
                ciphertext = new byte[inputCount - m_depadBuffer.Length];
                Buffer.BlockCopy(inputBuffer, inputOffset, ciphertext, 0, ciphertext.Length);
                Buffer.BlockCopy(inputBuffer, inputOffset + inputCount - m_depadBuffer.Length, m_depadBuffer, 0, m_depadBuffer.Length);
            }
            else
            {
                // No depadding is necessary, so we can decrypt the entire input now
                m_depadBuffer = null;
                ciphertext    = new byte[inputCount];
                Buffer.BlockCopy(inputBuffer, inputOffset, ciphertext, 0, ciphertext.Length);
            }

            // Decrypt the input that's not been saved in the depad buffer
            Debug.Assert(ciphertext != null, "ciphertext != null");
            if (ciphertext.Length > 0)
            {
                byte[] plaintext = BCryptNative.SymmetricDecrypt(m_key, m_iv, ciphertext);
                Buffer.BlockCopy(plaintext, 0, outputBuffer, outputOffset, plaintext.Length);
                decryptedBytes += plaintext.Length;
            }

            return(decryptedBytes);
        }