Пример #1
0
    // '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");
        }
    }
Пример #2
0
        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);
                }
            }
        }
Пример #3
0
 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);
Пример #4
0
        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);
                }
            }
        }
Пример #5
0
    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;
    }
Пример #6
0
    // 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
        };
    }
Пример #7
0
            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);
            }
Пример #8
0
        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);
                }
            }
        }
Пример #9
0
        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);
                }
            }
        }
Пример #10
0
        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);
                }
            }
        }
Пример #11
0
        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);
        }
Пример #12
0
    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);
            }
        }
    }
Пример #13
0
    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);
            }
        }
    }
Пример #14
0
        /// <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);
                    }
                }
            }
        }
Пример #15
0
        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++;
        }
Пример #16
0
 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);
Пример #17
0
        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));
                }
            }
        }