// 'pbNonce' must point to a 96-bit buffer. // 'pbTag' must point to a 128-bit buffer. // 'pbEncryptedData' must point to a buffer the same length as 'pbPlaintextData'. private void DoGcmEncrypt(byte *pbKey, uint cbKey, byte *pbNonce, byte *pbPlaintextData, uint cbPlaintextData, byte *pbEncryptedData, byte *pbTag) { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authCipherInfo; BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Init(out authCipherInfo); authCipherInfo.pbNonce = pbNonce; authCipherInfo.cbNonce = NONCE_SIZE_IN_BYTES; authCipherInfo.pbTag = pbTag; authCipherInfo.cbTag = TAG_SIZE_IN_BYTES; using (var keyHandle = _symmetricAlgorithmHandle.GenerateSymmetricKey(pbKey, cbKey)) { uint cbResult; var ntstatus = UnsafeNativeMethods.BCryptEncrypt( hKey: keyHandle, pbInput: pbPlaintextData, cbInput: cbPlaintextData, pPaddingInfo: &authCipherInfo, pbIV: null, cbIV: 0, pbOutput: pbEncryptedData, cbOutput: cbPlaintextData, pcbResult: out cbResult, dwFlags: 0); UnsafeNativeMethods.ThrowExceptionForBCryptStatus(ntstatus); CryptoUtil.Assert(cbResult == cbPlaintextData, "cbResult == cbPlaintextData"); } }
public static unsafe void Decrypt( SafeKeyHandle keyHandle, ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> associatedData, ReadOnlySpan <byte> ciphertext, ReadOnlySpan <byte> tag, Span <byte> plaintext, bool clearPlaintextOnFailure) { // bcrypt sometimes misbehaves when given nullptr buffers; ensure non-nullptr fixed(byte *plaintextBytes = &GetNonNullPinnableReference(plaintext)) fixed(byte *nonceBytes = &GetNonNullPinnableReference(nonce)) fixed(byte *ciphertextBytes = &GetNonNullPinnableReference(ciphertext)) fixed(byte *tagBytes = &GetNonNullPinnableReference(tag)) fixed(byte *associatedDataBytes = &GetNonNullPinnableReference(associatedData)) { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Create(); authInfo.pbNonce = nonceBytes; authInfo.cbNonce = nonce.Length; authInfo.pbTag = tagBytes; authInfo.cbTag = tag.Length; authInfo.pbAuthData = associatedDataBytes; authInfo.cbAuthData = associatedData.Length; NTSTATUS ntStatus = BCryptDecrypt( keyHandle, ciphertextBytes, ciphertext.Length, new IntPtr(&authInfo), null, 0, plaintextBytes, plaintext.Length, out int plaintextBytesWritten, 0); Debug.Assert(ciphertext.Length == plaintextBytesWritten); switch (ntStatus) { case NTSTATUS.STATUS_SUCCESS: return; case NTSTATUS.STATUS_AUTH_TAG_MISMATCH: if (clearPlaintextOnFailure) { CryptographicOperations.ZeroMemory(plaintext); } throw new CryptographicException(SR.Cryptography_AuthTagMismatch); default: throw CreateCryptographicException(ntStatus); } } }
public static extern uint BCryptEncrypt(IntPtr hKey, byte[] pbInput, int cbInput, ref BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO pPaddingInfo, byte[] pbIV, int cbIV, byte[] pbOutput, int cbOutput, ref int pcbResult, uint dwFlags);
public static unsafe void Decrypt( SafeAlgorithmHandle algorithm, SafeKeyHandleBCrypt keyHandle, ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> associatedData, ReadOnlySpan <byte> ciphertext, ReadOnlySpan <byte> tag, Span <byte> plaintext, bool clearPlaintextOnFailure) { fixed(byte *plaintextBytes = plaintext) fixed(byte *nonceBytes = nonce) fixed(byte *ciphertextBytes = ciphertext) fixed(byte *tagBytes = tag) fixed(byte *associatedDataBytes = associatedData) { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Create(); authInfo.pbNonce = nonceBytes; authInfo.cbNonce = nonce.Length; authInfo.pbTag = tagBytes; authInfo.cbTag = tag.Length; authInfo.pbAuthData = associatedDataBytes; authInfo.cbAuthData = associatedData.Length; NTSTATUS ntStatus = Cng.Interop.BCryptDecrypt( keyHandle, ciphertextBytes, ciphertext.Length, new IntPtr(&authInfo), null, 0, plaintextBytes, plaintext.Length, out int plaintextBytesWritten, 0); Debug.Assert(ciphertext.Length == plaintextBytesWritten); switch (ntStatus) { case NTSTATUS.STATUS_SUCCESS: return; case NTSTATUS.STATUS_AUTH_TAG_MISMATCH: if (clearPlaintextOnFailure) { CryptographicOperations.ZeroMemory(plaintext); } throw new CryptographicException(SR.Cryptography_AuthTagMismatch); default: throw CreateCryptographicException(ntStatus); } } }
public void IntPtrStructPropertyAccessor() { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO s = default(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO); s.pbAuthData_IntPtr = IntPtr.Zero; BCRYPT_OAEP_PADDING_INFO oaep = default(BCRYPT_OAEP_PADDING_INFO); oaep.pbLabel_IntPtr = IntPtr.Zero; }
// corresponds to the BCRYPT_INIT_AUTH_MODE_INFO macro in bcrypt.h public static void Init(out BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO info) { const uint BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION = 1; info = new BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO { cbSize = (uint)sizeof(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO), dwInfoVersion = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION }; }
public static BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO Create() { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO ret = new BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO(); ret.cbSize = sizeof(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO); const uint BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION = 1; ret.dwInfoVersion = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO_VERSION; return(ret); }
internal static unsafe void Encrypt( SafeKeyHandle keyHandle, byte[] nonce, byte[] associatedData, byte[] plaintext, byte[] ciphertext, byte[] tag) { fixed(byte *plaintextBytes = plaintext) fixed(byte *nonceBytes = nonce) fixed(byte *ciphertextBytes = ciphertext) fixed(byte *tagBytes = tag) fixed(byte *associatedDataBytes = associatedData) { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Create(); authInfo.pbNonce = nonceBytes; authInfo.cbNonce = nonce.Length; authInfo.pbTag = tagBytes; authInfo.cbTag = tag.Length; authInfo.pbAuthData = associatedDataBytes; if (associatedData == null) { authInfo.cbAuthData = 0; } else { authInfo.cbAuthData = associatedData.Length; } NTSTATUS ntStatus = Interop.BCrypt.BCryptEncrypt( keyHandle, plaintextBytes, plaintext.Length, new IntPtr(&authInfo), null, 0, ciphertextBytes, ciphertext.Length, out int ciphertextBytesWritten, 0); Debug.Assert(plaintext.Length == ciphertextBytesWritten); if (ntStatus != NTSTATUS.STATUS_SUCCESS) { throw Interop.BCrypt.CreateCryptographicException(ntStatus); } } }
public static unsafe void Encrypt( SafeKeyHandle keyHandle, ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> associatedData, ReadOnlySpan <byte> plaintext, Span <byte> ciphertext, Span <byte> tag) { // bcrypt sometimes misbehaves when given nullptr buffers; ensure non-nullptr fixed(byte *plaintextBytes = &GetNonNullPinnableReference(plaintext)) fixed(byte *nonceBytes = &GetNonNullPinnableReference(nonce)) fixed(byte *ciphertextBytes = &GetNonNullPinnableReference(ciphertext)) fixed(byte *tagBytes = &GetNonNullPinnableReference(tag)) fixed(byte *associatedDataBytes = &GetNonNullPinnableReference(associatedData)) { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Create(); authInfo.pbNonce = nonceBytes; authInfo.cbNonce = nonce.Length; authInfo.pbTag = tagBytes; authInfo.cbTag = tag.Length; authInfo.pbAuthData = associatedDataBytes; authInfo.cbAuthData = associatedData.Length; NTSTATUS ntStatus = BCryptEncrypt( keyHandle, plaintextBytes, plaintext.Length, new IntPtr(&authInfo), null, 0, ciphertextBytes, ciphertext.Length, out int ciphertextBytesWritten, 0); Debug.Assert(plaintext.Length == ciphertextBytesWritten); if (ntStatus != NTSTATUS.STATUS_SUCCESS) { throw CreateCryptographicException(ntStatus); } } }
public static unsafe void Encrypt( SafeAlgorithmHandle algorithm, SafeKeyHandle keyHandle, ReadOnlySpan <byte> nonce, ReadOnlySpan <byte> associatedData, ReadOnlySpan <byte> plaintext, Span <byte> ciphertext, Span <byte> tag) { fixed(byte *plaintextBytes = plaintext) fixed(byte *nonceBytes = nonce) fixed(byte *ciphertextBytes = ciphertext) fixed(byte *tagBytes = tag) fixed(byte *associatedDataBytes = associatedData) { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Create(); authInfo.pbNonce = nonceBytes; authInfo.cbNonce = nonce.Length; authInfo.pbTag = tagBytes; authInfo.cbTag = tag.Length; authInfo.pbAuthData = associatedDataBytes; authInfo.cbAuthData = associatedData.Length; NTSTATUS ntStatus = BCryptEncrypt( keyHandle, plaintextBytes, plaintext.Length, new IntPtr(&authInfo), null, 0, ciphertextBytes, ciphertext.Length, out int ciphertextBytesWritten, 0); Debug.Assert(plaintext.Length == ciphertextBytesWritten); if (ntStatus != NTSTATUS.STATUS_SUCCESS) { throw CreateCryptographicException(ntStatus); } } }
public unsafe void Encrypt(ref WritableBuffer buffer, ReadableBuffer plainText, RecordType recordType) { var cInfo = new BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO(); cInfo.dwInfoVersion = 1; cInfo.cbSize = sizeof(BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO); cInfo.cbNonce = _iVLength; cInfo.pbNonce = _ivPointer; var iv = stackalloc byte[_blockLength]; var macRecord = stackalloc byte[_maxTagLength]; var tag = stackalloc byte[_overhead]; cInfo.dwFlags = AuthenticatedCipherModeInfoFlags.ChainCalls; cInfo.cbMacContext = _maxTagLength; cInfo.pbMacContext = (IntPtr)macRecord; cInfo.pbTag = (IntPtr)tag; cInfo.cbTag = _overhead; cInfo.pbAuthData = _ivPointer; cInfo.cbAuthData = 0; var totalDataLength = plainText.Length; int outLength; GCHandle inHandle, outHandle; foreach (var b in plainText) { totalDataLength = totalDataLength - b.Length; if (b.Length == 0 && totalDataLength > 0) { continue; } buffer.Ensure(b.Length); var inPtr = b.GetPointer(out inHandle); var outPtr = buffer.Memory.GetPointer(out outHandle); try { outLength = buffer.Memory.Length; int amountWritten; Interop.Windows.ExceptionHelper.CheckReturnCode(BCryptEncrypt(_key, inPtr, b.Length, &cInfo, iv, _blockLength, outPtr, b.Length, out amountWritten, 0)); cInfo.dwFlags = AuthenticatedCipherModeInfoFlags.InProgress; buffer.Advance(amountWritten); } finally { if (inHandle.IsAllocated) { inHandle.Free(); } if (outHandle.IsAllocated) { outHandle.Free(); } } if (totalDataLength == 0) { break; } } buffer.Ensure(Overhead + sizeof(RecordType)); var writePtr = buffer.Memory.GetPointer(out outHandle); outLength = buffer.Memory.Length; if (_paddingSize == 0) { cInfo.dwFlags = AuthenticatedCipherModeInfoFlags.None; } Interop.Windows.ExceptionHelper.CheckReturnCode(BCryptEncrypt(_key, &recordType, sizeof(RecordType), &cInfo, iv, _iVLength, writePtr, buffer.Memory.Length, out outLength, 0)); buffer.Advance(outLength); if (_paddingSize > 0) { outLength = _paddingSize; writePtr = buffer.Memory.GetPointer(out outHandle); cInfo.dwFlags = AuthenticatedCipherModeInfoFlags.None; Interop.Windows.ExceptionHelper.CheckReturnCode(BCryptEncrypt(_key, (void *)s_zeroBuffer, _paddingSize, &cInfo, iv, _iVLength, writePtr, buffer.Memory.Length, out outLength, 0)); buffer.Advance(outLength); } writePtr = buffer.Memory.GetPointer(out outHandle); buffer.Write(new Span <byte>(tag, _overhead)); buffer.Advance(_overhead); }
protected override byte[] DecryptImpl(byte *pbCiphertext, uint cbCiphertext, byte *pbAdditionalAuthenticatedData, uint cbAdditionalAuthenticatedData) { // Argument checking: input must at the absolute minimum contain a key modifier, nonce, and tag if (cbCiphertext < KEY_MODIFIER_SIZE_IN_BYTES + NONCE_SIZE_IN_BYTES + TAG_SIZE_IN_BYTES) { throw Error.CryptCommon_PayloadInvalid(); } // Assumption: pbCipherText := { keyModifier || nonce || encryptedData || authenticationTag } var cbPlaintext = checked (cbCiphertext - (KEY_MODIFIER_SIZE_IN_BYTES + NONCE_SIZE_IN_BYTES + TAG_SIZE_IN_BYTES)); var retVal = new byte[cbPlaintext]; fixed(byte *pbRetVal = retVal) { // Calculate offsets byte *pbKeyModifier = pbCiphertext; byte *pbNonce = &pbKeyModifier[KEY_MODIFIER_SIZE_IN_BYTES]; byte *pbEncryptedData = &pbNonce[NONCE_SIZE_IN_BYTES]; byte *pbAuthTag = &pbEncryptedData[cbPlaintext]; // Use the KDF to recreate the symmetric block cipher key // We'll need a temporary buffer to hold the symmetric encryption subkey byte *pbSymmetricDecryptionSubkey = stackalloc byte[checked ((int)_symmetricAlgorithmSubkeyLengthInBytes)]; try { _sp800_108_ctr_hmac_provider.DeriveKeyWithContextHeader( pbLabel: pbAdditionalAuthenticatedData, cbLabel: cbAdditionalAuthenticatedData, contextHeader: _contextHeader, pbContext: pbKeyModifier, cbContext: KEY_MODIFIER_SIZE_IN_BYTES, pbDerivedKey: pbSymmetricDecryptionSubkey, cbDerivedKey: _symmetricAlgorithmSubkeyLengthInBytes); // Perform the decryption operation using (var decryptionSubkeyHandle = _symmetricAlgorithmHandle.GenerateSymmetricKey(pbSymmetricDecryptionSubkey, _symmetricAlgorithmSubkeyLengthInBytes)) { byte dummy; byte *pbPlaintext = (pbRetVal != null) ? pbRetVal : &dummy; // CLR doesn't like pinning empty buffers BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo; BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Init(out authInfo); authInfo.pbNonce = pbNonce; authInfo.cbNonce = NONCE_SIZE_IN_BYTES; authInfo.pbTag = pbAuthTag; authInfo.cbTag = TAG_SIZE_IN_BYTES; // The call to BCryptDecrypt will also validate the authentication tag uint cbDecryptedBytesWritten; var ntstatus = UnsafeNativeMethods.BCryptDecrypt( hKey: decryptionSubkeyHandle, pbInput: pbEncryptedData, cbInput: cbPlaintext, pPaddingInfo: &authInfo, pbIV: null, // IV not used; nonce provided in pPaddingInfo cbIV: 0, pbOutput: pbPlaintext, cbOutput: cbPlaintext, pcbResult: out cbDecryptedBytesWritten, dwFlags: 0); UnsafeNativeMethods.ThrowExceptionForBCryptStatus(ntstatus); CryptoUtil.Assert(cbDecryptedBytesWritten == cbPlaintext, "cbDecryptedBytesWritten == cbPlaintext"); // At this point, retVal := { decryptedPayload } // And we're done! return(retVal); } } finally { // The buffer contains key material, so delete it. UnsafeBufferUtil.SecureZeroMemory(pbSymmetricDecryptionSubkey, _symmetricAlgorithmSubkeyLengthInBytes); } } }
public unsafe void EncryptDecrypt_AesCcm() { var random = new Random(); using (var provider = BCryptOpenAlgorithmProvider(AlgorithmIdentifiers.BCRYPT_AES_ALGORITHM)) { BCryptSetProperty(provider, PropertyNames.BCRYPT_CHAINING_MODE, ChainingModes.Ccm); byte[] plainText; byte[] cipherText; var nonceBuffer = new byte[12]; random.NextBytes(nonceBuffer); var tagLengths = BCryptGetProperty <BCRYPT_AUTH_TAG_LENGTHS_STRUCT>(provider, PropertyNames.BCRYPT_AUTH_TAG_LENGTH); var tagBuffer = new byte[tagLengths.MaxLength]; int blockSize = BCryptGetProperty <int>(provider, PropertyNames.BCRYPT_BLOCK_LENGTH); plainText = new byte[blockSize]; random.NextBytes(plainText); byte[] keyMaterial = new byte[blockSize]; RandomNumberGenerator.Create().GetBytes(keyMaterial); using (var key = BCryptGenerateSymmetricKey(provider, keyMaterial)) { var authInfo = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Create(); fixed(byte *pTagBuffer = &tagBuffer[0]) fixed(byte *pNonce = &nonceBuffer[0]) { authInfo.pbNonce = pNonce; authInfo.cbNonce = nonceBuffer.Length; authInfo.pbTag = pTagBuffer; authInfo.cbTag = tagBuffer.Length; // Mix up calling the IntPtr and native pointer overloads so we test both. int cipherTextLength; BCryptEncrypt(key, plainText, plainText.Length, &authInfo, null, 0, null, 0, out cipherTextLength, BCryptEncryptFlags.None).ThrowOnError(); cipherText = new byte[cipherTextLength]; BCryptEncrypt(key, plainText, plainText.Length, &authInfo, null, 0, cipherText, cipherText.Length, out cipherTextLength, BCryptEncryptFlags.None).ThrowOnError(); } Assert.NotEqual <byte>(plainText, cipherText); } // Renew the key to prove we can decrypt it with a fresh key. using (var key = BCryptGenerateSymmetricKey(provider, keyMaterial)) { byte[] decryptedText; var authInfo = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Create(); fixed(byte *pTagBuffer = &tagBuffer[0]) fixed(byte *pNonce = &nonceBuffer[0]) { authInfo.pbNonce = pNonce; authInfo.cbNonce = nonceBuffer.Length; authInfo.pbTag = pTagBuffer; authInfo.cbTag = tagBuffer.Length; int plainTextLength; BCryptDecrypt(key, cipherText, cipherText.Length, &authInfo, null, 0, null, 0, out plainTextLength, BCryptEncryptFlags.None).ThrowOnError(); decryptedText = new byte[plainTextLength]; BCryptEncrypt(key, cipherText, cipherText.Length, &authInfo, null, 0, decryptedText, decryptedText.Length, out plainTextLength, BCryptEncryptFlags.None).ThrowOnError(); Array.Resize(ref decryptedText, plainTextLength); } Assert.Equal <byte>(plainText, decryptedText); } } }
/// <summary> /// Encrypts the data using AES-GCM /// </summary> /// <param name="pbData">data to encrypt</param> /// <param name="pbKey">key to use for encryption</param> /// <param name="pbNonce">GCM nonce</param> /// <param name="pbTag">GCM authentication tag</param> /// <param name="pbAuthData">associated autentication data</param> /// <returns>the encrypted data</returns> public unsafe static byte[] GcmEncrypt(byte[] pbData, byte[] pbKey, byte[] pbNonce, byte[] pbTag, byte[] pbAuthData = null) { pbAuthData = pbAuthData ?? new byte[0]; NTSTATUS status = 0; using (var provider = BCryptOpenAlgorithmProvider(AlgorithmIdentifiers.BCRYPT_AES_ALGORITHM)) { BCryptSetProperty(provider, PropertyNames.BCRYPT_CHAINING_MODE, ChainingModes.Gcm); var tagLengths = BCryptGetProperty <BCRYPT_AUTH_TAG_LENGTHS_STRUCT>(provider, PropertyNames.BCRYPT_AUTH_TAG_LENGTH); if (pbTag.Length < tagLengths.dwMinLength || pbTag.Length > tagLengths.dwMaxLength || (pbTag.Length - tagLengths.dwMinLength) % tagLengths.dwIncrement != 0) { throw new ArgumentException("Invalid tag length"); } using (var key = BCryptGenerateSymmetricKey(provider, pbKey)) { var authInfo = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Create(); fixed(byte *pTagBuffer = pbTag) fixed(byte *pNonce = pbNonce) fixed(byte *pAuthData = pbAuthData) { authInfo.pbNonce = pNonce; authInfo.cbNonce = pbNonce.Length; authInfo.pbTag = pTagBuffer; authInfo.cbTag = pbTag.Length; authInfo.pbAuthData = pAuthData; authInfo.cbAuthData = pbAuthData.Length; // Initialize cipher text byte count int pcbCipherText = pbData.Length; // Allocate cipher text buffer byte[] pbCipherText = new byte[pcbCipherText]; fixed(byte *plainText = pbData) fixed(byte *cipherText = pbCipherText) { // Encrypt the data status = BCryptEncrypt( key, plainText, pbData.Length, &authInfo, null, 0, cipherText, pbCipherText.Length, out pcbCipherText, 0); } if (status != NTSTATUS.Code.STATUS_SUCCESS) { throw new CryptographicException($"BCryptEncrypt failed result {status:X} "); } return(pbCipherText); } } } }
public unsafe void EncryptWithAuthData(ref WritableBuffer buffer, RecordType recordType, ushort tlsVersion, int plaintextLength) { var additionalData = stackalloc byte[13]; var additionalSpan = new Span <byte>(additionalData, 13); additionalSpan.Write64BitNumber(_sequenceNumber); additionalSpan = additionalSpan.Slice(8); additionalSpan.Write(recordType); additionalSpan = additionalSpan.Slice(1); additionalSpan.Write(tlsVersion); additionalSpan = additionalSpan.Slice(2); additionalSpan.Write16BitNumber((ushort)plaintextLength); var cInfo = new BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO(); cInfo.dwInfoVersion = 1; cInfo.cbSize = Marshal.SizeOf <BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO>(); cInfo.cbNonce = _iVLength; cInfo.pbNonce = _ivPointer; cInfo.dwFlags = AuthenticatedCipherModeInfoFlags.ChainCalls; cInfo.pbAuthData = (IntPtr)additionalData; cInfo.cbAuthData = 13; var iv = stackalloc byte[16]; var macRecord = stackalloc byte[16]; var tag = stackalloc byte[16]; cInfo.cbMacContext = 16; cInfo.pbMacContext = (IntPtr)macRecord; cInfo.pbTag = (IntPtr)tag; cInfo.cbTag = 16; //var totalDataLength = plainText.Length; //foreach (var b in plainText) //{ // totalDataLength = totalDataLength - b.Length; // if (b.Length == 0 && totalDataLength > 0) // { // continue; // } // if (totalDataLength == 0) // { // cInfo.dwFlags = AuthenticatedCipherModeInfoFlags.None; // } // buffer.Ensure(b.Length); // void* outPointer; // if (!buffer.Memory.TryGetPointer(out outPointer)) // { // throw new NotImplementedException("Need to implement a pinned array if we can get a pointer"); // } // void* inPointer; // if (!b.TryGetPointer(out inPointer)) // { // throw new NotImplementedException("Need to implement a pinned array if we can't get a pointer"); // } // int amountWritten; // Interop.Windows.ExceptionHelper.CheckReturnCode( // BCryptEncrypt(_key, inPointer, b.Length, &cInfo, iv, 16, outPointer, buffer.Memory.Length, out amountWritten, 0)); // buffer.Advance(amountWritten); // cInfo.dwFlags = AuthenticatedCipherModeInfoFlags.InProgress; // if (totalDataLength == 0) // { // break; // } //} //buffer.Ensure(16); //buffer.Write(new Span<byte>(tag, 16)); //IncrementSequence(); //_sequenceNumber++; }
internal static extern uint BCryptDecrypt(IntPtr hKey, byte[] pbInput, int cbInput, ref BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO pPaddingInfo, byte[] pbIV, int cbIV, byte[] pbOutput, int cbOutput, ref int pcbResult, int dwFlags);
public static unsafe void Decrypt( SafeKeyHandle keyHandle, byte[] nonce, byte[] associatedData, byte[] ciphertext, byte[] tag, byte[] plaintext, bool clearPlaintextOnFailure) { fixed(byte *plaintextBytes = plaintext) fixed(byte *nonceBytes = nonce) fixed(byte *ciphertextBytes = ciphertext) fixed(byte *tagBytes = tag) fixed(byte *associatedDataBytes = associatedData) { BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO authInfo = BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO.Create(); authInfo.pbNonce = nonceBytes; authInfo.cbNonce = nonce.Length; authInfo.pbTag = tagBytes; authInfo.cbTag = tag.Length; authInfo.pbAuthData = associatedDataBytes; if (associatedData == null) { authInfo.cbAuthData = 0; } else { authInfo.cbAuthData = associatedData.Length; } NTSTATUS ntStatus = Interop.BCrypt.BCryptDecrypt( keyHandle, ciphertextBytes, ciphertext.Length, new IntPtr(&authInfo), null, 0, plaintextBytes, plaintext.Length, out int plaintextBytesWritten, 0); Debug.Assert(ciphertext.Length == plaintextBytesWritten); switch (ntStatus) { case NTSTATUS.STATUS_SUCCESS: return; case NTSTATUS.STATUS_AUTH_TAG_MISMATCH: if (clearPlaintextOnFailure) { CryptographicOperations.ZeroMemory(plaintext); } throw LogHelper.LogExceptionMessage(new CryptographicException(LogHelper.FormatInvariant(LogMessages.IDX10714))); default: throw LogHelper.LogExceptionMessage(Interop.BCrypt.CreateCryptographicException(ntStatus)); } } }