예제 #1
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);
                }
            }
        }
예제 #2
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);
                }
            }
        }
예제 #3
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);
                }
            }
        }
예제 #4
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);
                }
            }
        }
예제 #5
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);
                }
            }
        }
예제 #6
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);
            }
        }
    }
예제 #7
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);
                    }
                }
            }
        }
예제 #8
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));
                }
            }
        }