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); } }
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 void GetBytes(byte[] data) { if (data == null) { throw new ArgumentNullException("data"); } BCryptNative.GenerateRandomBytes(m_algorithm, data); }
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); }
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)); } }
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; }
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); } } }
/// <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); }
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); }