Exemple #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;

            // 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;
        }
        public override int Transform(byte[] input, int inputOffset, int count, byte[] output, int outputOffset)
        {
            Debug.Assert(input != null);
            Debug.Assert(inputOffset >= 0);
            Debug.Assert(count > 0);
            Debug.Assert((count % BlockSizeInBytes) == 0);
            Debug.Assert(input.Length - inputOffset >= count);
            Debug.Assert(output != null);
            Debug.Assert(outputOffset >= 0);
            Debug.Assert(output.Length - outputOffset >= count);

            int numBytesWritten;

            if (_encrypting)
            {
                numBytesWritten = BCryptNative.BCryptEncrypt(_hKey, input, inputOffset, count, _currentIv, output, outputOffset, output.Length - outputOffset);
            }
            else
            {
                numBytesWritten = BCryptNative.BCryptDecrypt(_hKey, input, inputOffset, count, _currentIv, output, outputOffset, output.Length - outputOffset);
            }

            if (numBytesWritten != count)
            {
                // CNG gives us no way to tell BCryptDecrypt() that we're decrypting the final block, nor is it performing any
                // padding /depadding for us. So there's no excuse for a provider to hold back output for "future calls." Though
                // this isn't technically our problem to detect, we might as well detect it now for easier diagnosis.
                throw new CryptographicException(SR.Cryptography_UnexpectedTransformTruncation);
            }

            return(numBytesWritten);
        }
Exemple #3
0
        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);
            }
        }
        /// <summary>
        /// Method take BCrypt handle as input and returns the CNGKey
        /// </summary>
        /// <param name="bcryptKeyHandle">Accepts BCrypt Handle</param>
        /// <returns>Returns CNG key with NCrypt Handle</returns>
        private static CngKey LegacyBCryptHandleToNCryptHandle(SafeBCryptKeyHandle bcryptKeyHandle)
        {
            byte[] keyBlob = BCryptNative.ExportBCryptKey(bcryptKeyHandle, BCryptNative.BCRYPT_ECCPUBLIC_BLOB);
            //Now Import the key blob as NCRYPT_KEY_HANDLE
            CngKey Key = CngKey.Import(keyBlob, CngKeyBlobFormat.EccPublicBlob);

            return(Key);
        }
Exemple #5
0
        public override void GetBytes(byte[] data)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }

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

            m_algorithm = BCryptNative.OpenAlgorithm(BCryptNative.AlgorithmName.Rng,
                                                     algorithmProvider.Provider);

            m_implementation = algorithmProvider;
        }
Exemple #7
0
        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);
        }
        public static ECDsa GetECDsaPublicKey(this X509Certificate2 certificate)
        {
            if (LocalAppContextSwitches.UseLegacyPublicKeyBehavior)
            {
                return(LegacyGetECDsaPublicKey(certificate));
            }

            if (certificate == null)
            {
                throw new ArgumentNullException("certificate");
            }
            if (!IsECDsa(certificate))
            {
                return(null);
            }

            using (SafeCertContextHandle safeCertContext = X509Native.GetCertificateContext(certificate))
                using (SafeBCryptKeyHandle bcryptKeyHandle = ImportPublicKeyInfo(safeCertContext))
                {
                    if (bcryptKeyHandle.IsInvalid)
                    {
                        throw new CryptographicException("SR.GetString(SR.Cryptography_OpenInvalidHandle)");
                    }

                    string curveName = GetCurveName(bcryptKeyHandle);

                    if (curveName == null)
                    {
                        CngKeyBlobFormat blobFormat = HasExplicitParameters(bcryptKeyHandle) ?
                                                      CngKeyBlobFormat.EccFullPublicBlob : CngKeyBlobFormat.EccPublicBlob;

                        byte[] keyBlob = BCryptNative.ExportBCryptKey(bcryptKeyHandle, blobFormat.Format);
                        using (CngKey key = CngKey.Import(keyBlob, blobFormat))
                        {
                            return(new ECDsaCng(key));
                        }
                    }
                    else
                    {
                        CngKeyBlobFormat blobFormat = CngKeyBlobFormat.EccPublicBlob;
                        byte[]           keyBlob    = BCryptNative.ExportBCryptKey(bcryptKeyHandle, blobFormat.Format);
                        ECParameters     ecparams   = new ECParameters();
                        ExportNamedCurveParameters(ref ecparams, keyBlob, false);
                        ecparams.Curve = ECCurve.CreateFromFriendlyName(curveName);
                        ECDsaCng ecdsa = new ECDsaCng();
                        ecdsa.ImportParameters(ecparams);

                        return(ecdsa);
                    }
                }
        }
        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, m_chainingMode.ChainingMode);

            return(algorithmHandle);
        }
Exemple #10
0
        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("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));
            }
        }
        public BasicSymmetricCipherBCrypt(SafeBCryptAlgorithmHandle algorithm, CipherMode cipherMode, int blockSizeInBytes, byte[] key, byte[] iv, bool encrypting)
            : base(cipherMode.GetCipherIv(iv), blockSizeInBytes)
        {
            Debug.Assert(algorithm != null);

            _encrypting = encrypting;

            if (IV != null)
            {
                _currentIv = new byte[IV.Length];
            }

            _hKey = BCryptNative.BCryptImportKey(algorithm, key);

            Reset();
        }
Exemple #12
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;
        }
Exemple #13
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);
        }
Exemple #14
0
        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;
        }
        private static SafeBCryptKeyHandle ImportPublicKeyInfo(SafeCertContextHandle certContext)
        {
            IntPtr certHandle = certContext.DangerousGetHandle();

            //Read the public key blob from the certificate
            X509Native.CERT_CONTEXT pCertContext = (X509Native.CERT_CONTEXT)Marshal.PtrToStructure(certHandle, typeof(X509Native.CERT_CONTEXT));

            IntPtr pSubjectPublicKeyInfo = new IntPtr((long)pCertContext.pCertInfo +
                                                      (long)Marshal.OffsetOf(typeof(X509Native.CERT_INFO), "SubjectPublicKeyInfo"));

            X509Native.CERT_PUBLIC_KEY_INFO certPublicKeyInfo =
                (X509Native.CERT_PUBLIC_KEY_INFO)Marshal.PtrToStructure(pSubjectPublicKeyInfo, typeof(X509Native.CERT_PUBLIC_KEY_INFO));

            SafeBCryptKeyHandle publicKeyInfo = BCryptNative.ImportAsymmetricPublicKey(certPublicKeyInfo, 0);

            // certContext needs to be valid through the call to BCryptNative.ImportAsymmetricPublicKey
            // because certPublicKeyInfo structure contains pointers.
            GC.KeepAlive(certContext);
            return(publicKeyInfo);
        }
Exemple #16
0
        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);
        }
Exemple #17
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);
        }
Exemple #18
0
        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);
                }
            }
        }
Exemple #19
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);
        }
        private static ECDsa LegacyGetECDsaPublicKey(X509Certificate2 certificate)
        {
            if (certificate == null)
            {
                throw new ArgumentNullException("certificate");
            }
            if (!IsECDsa(certificate))
            {
                return(null);
            }

            SafeCertContextHandle safeCertContext = X509Native.GetCertificateContext(certificate);
            IntPtr certHandle = safeCertContext.DangerousGetHandle();

            //Read the public key blob from the certificate
            X509Native.CERT_CONTEXT pCertContext = (X509Native.CERT_CONTEXT)Marshal.PtrToStructure(certHandle, typeof(X509Native.CERT_CONTEXT));

            IntPtr pSubjectPublicKeyInfo = new IntPtr((long)pCertContext.pCertInfo +
                                                      (long)Marshal.OffsetOf(typeof(X509Native.CERT_INFO), "SubjectPublicKeyInfo"));

            X509Native.CERT_PUBLIC_KEY_INFO certPublicKeyInfo = (X509Native.CERT_PUBLIC_KEY_INFO)Marshal.PtrToStructure(pSubjectPublicKeyInfo,
                                                                                                                        typeof(X509Native.CERT_PUBLIC_KEY_INFO));
            CngKey key;

            //Import the public key blob to BCRYPT_KEY_HANDLE
            using (SafeBCryptKeyHandle bcryptKeyHandle = BCryptNative.ImportAsymmetricPublicKey(certPublicKeyInfo, 0))
            {
                if (bcryptKeyHandle.IsInvalid)
                {
                    throw new CryptographicException("SR.GetString(SR.Cryptography_OpenInvalidHandle)");
                }
                key = LegacyBCryptHandleToNCryptHandle(bcryptKeyHandle);
            }
            GC.KeepAlive(safeCertContext);
            return(new ECDsaCng(key));
        }
Exemple #21
0
 internal byte[] HashFinalImpl()
 {
     return(BCryptNative.FinishHash(m_hash));
 }
Exemple #22
0
        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();
                }
            }
        }
Exemple #23
0
        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);
        }