internal static byte[] SymmetricEncrypt(SafeBCryptKeyHandle key, byte[] iv, byte[] input) { Debug.Assert(key != null, "key != null"); Debug.Assert(!key.IsClosed && !key.IsInvalid, "!key.IsClosed && !key.IsInvalid"); Debug.Assert(input != null, "input != null"); // Do the encryption byte[] output = new byte[input.Length]; int outputSize = 0; ErrorCode error = UnsafeNativeMethods.BCryptEncrypt(key, input, input.Length, IntPtr.Zero, iv, iv != null ? iv.Length : 0, output, output.Length, out outputSize, 0); if (error != ErrorCode.Success) { throw new CryptographicException((int)error); } // If we didn't use the whole output array, trim down to the portion that was used if (outputSize != output.Length) { byte[] trimmedOutput = new byte[outputSize]; Buffer.BlockCopy(output, 0, trimmedOutput, 0, trimmedOutput.Length); output = trimmedOutput; } return(output); }
internal static extern ErrorCode BCryptImportKey(SafeBCryptAlgorithmHandle hAlgorithm, IntPtr hImportKey, [MarshalAs(UnmanagedType.LPWStr)] string pszBlobType, [Out] out SafeBCryptKeyHandle phKey, [In, Out] IntPtr pbKeyObject, // BYTE * int cbKeyObject, [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput, int cbInput, int dwFlags);
internal static extern ErrorCode BCryptEncrypt(SafeBCryptKeyHandle hKey, [In, MarshalAs(UnmanagedType.LPArray)] byte[] pbInput, int cbInput, IntPtr pPaddingInfo, [In, Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbIV, int cbIV, [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput, int cbOutput, [Out] out int pcbResult, int dwFlags);
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); }
internal static SafeBCryptKeyHandle ImportSymmetricKey(SafeBCryptAlgorithmHandle algorithm, byte[] key) { Debug.Assert(algorithm != null, "algorithm != null"); Debug.Assert(!algorithm.IsClosed && !algorithm.IsInvalid, "!algorithm.IsClosed && !algorithm.IsInvalid"); Debug.Assert(key != null, "buffer != null"); IntPtr keyDataBuffer = IntPtr.Zero; SafeBCryptKeyHandle keyHandle = null; RuntimeHelpers.PrepareConstrainedRegions(); try { // Build up the key blob structure in memory. BCryptImportKey requries a // BCRYPT_KEY_DATA_BLOB header immediately followed by the raw key data. byte[] keyBlob = new byte[Marshal.SizeOf(typeof(BCRYPT_KEY_DATA_BLOB)) + key.Length]; unsafe { fixed(byte *pbKeyBlob = keyBlob) { BCRYPT_KEY_DATA_BLOB *pkeyDataBlob = (BCRYPT_KEY_DATA_BLOB *)pbKeyBlob; pkeyDataBlob->dwMagic = KeyBlobMagicNumber.KeyDataBlob; pkeyDataBlob->dwVersion = 1; pkeyDataBlob->cbKeyData = key.Length; } } Buffer.BlockCopy(key, 0, keyBlob, Marshal.SizeOf(typeof(BCRYPT_KEY_DATA_BLOB)), key.Length); // Figure out how big of a key data buffer we need and allocate space on the native heap for // it. We cannot use a managed array here because the address needs to stay constant for // the lifetime of the algorithm handle. Pinning for a potentially long lifetime is // undesirable, so we use a native heap allocation instead. int keyDataSize = GetInt32Property(algorithm, ObjectPropertyName.ObjectLength); RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { keyDataBuffer = Marshal.AllocCoTaskMem(keyDataSize); } // Import the key ErrorCode error = UnsafeNativeMethods.BCryptImportKey(algorithm, IntPtr.Zero, KeyBlobType.KeyDataBlob, out keyHandle, keyDataBuffer, keyDataSize, keyBlob, keyBlob.Length, 0); if (error != ErrorCode.Success) { throw new CryptographicException((int)error); } // Give the key ownership of the key data buffer keyHandle.DataBuffer = keyDataBuffer; return(keyHandle); } finally { // If we allocated a key data buffer, but never transfered ownership to the key handle, then // we need to free it now otherwise it will leak. if (keyDataBuffer != IntPtr.Zero) { if (keyHandle == null || keyHandle.DataBuffer == IntPtr.Zero) { Marshal.FreeCoTaskMem(keyDataBuffer); } } } }
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(); } } }