public GcmAuthenticatedEncryptor(Secret keyDerivationKey, BCryptAlgorithmHandle symmetricAlgorithmHandle, uint symmetricAlgorithmKeySizeInBytes, IBCryptGenRandom genRandom = null)
        {
            // Is the key size appropriate?
            AlgorithmAssert.IsAllowableSymmetricAlgorithmKeySize(checked(symmetricAlgorithmKeySizeInBytes * 8));
            CryptoUtil.Assert(symmetricAlgorithmHandle.GetCipherBlockLength() == 128 / 8, "GCM requires a block cipher algorithm with a 128-bit block size.");

            _genRandom = genRandom ?? BCryptGenRandomImpl.Instance;
            _sp800_108_ctr_hmac_provider = SP800_108_CTR_HMACSHA512Util.CreateProvider(keyDerivationKey);
            _symmetricAlgorithmHandle = symmetricAlgorithmHandle;
            _symmetricAlgorithmSubkeyLengthInBytes = symmetricAlgorithmKeySizeInBytes;
            _contextHeader = CreateContextHeader();
        }
        public CbcAuthenticatedEncryptor(Secret keyDerivationKey, BCryptAlgorithmHandle symmetricAlgorithmHandle, uint symmetricAlgorithmKeySizeInBytes, BCryptAlgorithmHandle hmacAlgorithmHandle, IBCryptGenRandom genRandom = null)
        {
            _genRandom = genRandom ?? BCryptGenRandomImpl.Instance;
            _sp800_108_ctr_hmac_provider = SP800_108_CTR_HMACSHA512Util.CreateProvider(keyDerivationKey);
            _symmetricAlgorithmHandle = symmetricAlgorithmHandle;
            _symmetricAlgorithmBlockSizeInBytes = symmetricAlgorithmHandle.GetCipherBlockLength();
            _symmetricAlgorithmSubkeyLengthInBytes = symmetricAlgorithmKeySizeInBytes;
            _hmacAlgorithmHandle = hmacAlgorithmHandle;
            _hmacAlgorithmDigestLengthInBytes = hmacAlgorithmHandle.GetHashDigestLength();
            _hmacAlgorithmSubkeyLengthInBytes = _hmacAlgorithmDigestLengthInBytes; // for simplicity we'll generate HMAC subkeys with a length equal to the digest length

            // Argument checking on the algorithms and lengths passed in to us
            AlgorithmAssert.IsAllowableSymmetricAlgorithmBlockSize(checked(_symmetricAlgorithmBlockSizeInBytes * 8));
            AlgorithmAssert.IsAllowableSymmetricAlgorithmKeySize(checked(_symmetricAlgorithmSubkeyLengthInBytes * 8));
            AlgorithmAssert.IsAllowableValidationAlgorithmDigestSize(checked(_hmacAlgorithmDigestLengthInBytes * 8));

            _contextHeader = CreateContextHeader();
        }
        private static BCryptKeyHandle PasswordToPbkdfKeyHandleStep2(BCryptAlgorithmHandle pbkdf2AlgHandle, byte* pbPassword, uint cbPassword, KeyDerivationPrf prf)
        {
            const uint PBKDF2_MAX_KEYLENGTH_IN_BYTES = 2048; // GetSupportedKeyLengths() on a Win8 box; value should never be lowered in any future version of Windows
            if (cbPassword <= PBKDF2_MAX_KEYLENGTH_IN_BYTES)
            {
                // Common case: the password is small enough to be consumed directly by the PBKDF2 algorithm.
                return pbkdf2AlgHandle.GenerateSymmetricKey(pbPassword, cbPassword);
            }
            else
            {
                // Rare case: password is very long; we must hash manually.
                // PBKDF2 uses the PRFs in HMAC mode, and when the HMAC input key exceeds the hash function's
                // block length the key is hashed and run back through the key initialization function.

                BCryptAlgorithmHandle prfAlgorithmHandle; // cached; don't dispose
                switch (prf)
                {
                    case KeyDerivationPrf.HMACSHA1:
                        prfAlgorithmHandle = CachedAlgorithmHandles.SHA1;
                        break;
                    case KeyDerivationPrf.HMACSHA256:
                        prfAlgorithmHandle = CachedAlgorithmHandles.SHA256;
                        break;
                    case KeyDerivationPrf.HMACSHA512:
                        prfAlgorithmHandle = CachedAlgorithmHandles.SHA512;
                        break;
                    default:
                        throw CryptoUtil.Fail("Unrecognized PRF.");
                }

                // Final sanity check: don't hash the password if the HMAC key initialization function wouldn't have done it for us.
                if (cbPassword <= prfAlgorithmHandle.GetHashBlockLength() /* in bytes */)
                {
                    return pbkdf2AlgHandle.GenerateSymmetricKey(pbPassword, cbPassword);
                }

                // Hash the password and use the hash as input to PBKDF2.
                uint cbPasswordDigest = prfAlgorithmHandle.GetHashDigestLength();
                CryptoUtil.Assert(cbPasswordDigest > 0, "cbPasswordDigest > 0");
                fixed (byte* pbPasswordDigest = new byte[cbPasswordDigest])
                {
                    try
                    {
                        using (var hashHandle = prfAlgorithmHandle.CreateHash())
                        {
                            hashHandle.HashData(pbPassword, cbPassword, pbPasswordDigest, cbPasswordDigest);
                        }
                        return pbkdf2AlgHandle.GenerateSymmetricKey(pbPasswordDigest, cbPasswordDigest);
                    }
                    finally
                    {
                        UnsafeBufferUtil.SecureZeroMemory(pbPasswordDigest, cbPasswordDigest);
                    }
                }
            }
        }
        private static BCryptKeyHandle PasswordToPbkdfKeyHandle(string password, BCryptAlgorithmHandle pbkdf2AlgHandle, KeyDerivationPrf prf)
        {
            byte dummy; // CLR doesn't like pinning zero-length buffers, so this provides a valid memory address when working with zero-length buffers

            // Convert password string to bytes.
            // Allocate on the stack whenever we can to save allocations.
            int cbPasswordBuffer = Encoding.UTF8.GetMaxByteCount(password.Length);
            fixed (byte* pbHeapAllocatedPasswordBuffer = (cbPasswordBuffer > Constants.MAX_STACKALLOC_BYTES) ? new byte[cbPasswordBuffer] : null)
            {
                byte* pbPasswordBuffer = pbHeapAllocatedPasswordBuffer;
                if (pbPasswordBuffer == null)
                {
                    if (cbPasswordBuffer == 0)
                    {
                        pbPasswordBuffer = &dummy;
                    }
                    else
                    {
                        byte* pbStackAllocPasswordBuffer = stackalloc byte[cbPasswordBuffer]; // will be released when the frame unwinds
                        pbPasswordBuffer = pbStackAllocPasswordBuffer;
                    }
                }

                try
                {
                    int cbPasswordBufferUsed; // we're not filling the entire buffer, just a partial buffer
                    fixed (char* pszPassword = password)
                    {
                        cbPasswordBufferUsed = Encoding.UTF8.GetBytes(pszPassword, password.Length, pbPasswordBuffer, cbPasswordBuffer);
                    }

                    return PasswordToPbkdfKeyHandleStep2(pbkdf2AlgHandle, pbPasswordBuffer, (uint)cbPasswordBufferUsed, prf);
                }
                finally
                {
                    UnsafeBufferUtil.SecureZeroMemory(pbPasswordBuffer, cbPasswordBuffer);
                }
            }
        }
 // We don't actually need to hold a reference to the algorithm handle, as the native CNG library
 // already holds the reference for us. But once we create a hash from an algorithm provider, odds
 // are good that we'll create another hash from the same algorithm provider at some point in the
 // future. And since algorithm providers are expensive to create, we'll hold a strong reference
 // to all known in-use providers. This way the cached algorithm provider handles utility class
 // doesn't keep creating providers over and over.
 internal void SetAlgorithmProviderHandle(BCryptAlgorithmHandle algProviderHandle)
 {
     _algProviderHandle = algProviderHandle;
 }
Exemple #6
0
 // We don't actually need to hold a reference to the algorithm handle, as the native CNG library
 // already holds the reference for us. But once we create a key from an algorithm provider, odds
 // are good that we'll create another key from the same algorithm provider at some point in the
 // future. And since algorithm providers are expensive to create, we'll hold a strong reference
 // to all known in-use providers. This way the cached algorithm provider handles utility class
 // doesn't keep creating providers over and over.
 internal void SetAlgorithmProviderHandle(BCryptAlgorithmHandle algProviderHandle)
 {
     _algProviderHandle = algProviderHandle;
 }
 // Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle for you.
 protected override bool ReleaseHandle()
 {
     _algProviderHandle = null;
     return(UnsafeNativeMethods.BCryptDestroyKey(handle) == 0);
 }
 // Do not provide a finalizer - SafeHandle's critical finalizer will call ReleaseHandle for you.
 protected override bool ReleaseHandle()
 {
     _algProviderHandle = null;
     return (UnsafeNativeMethods.BCryptDestroyKey(handle) == 0);
 }