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 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); } } }
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 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 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)); } } }