Ejemplo n.º 1
0
 internal static unsafe bool EvpCipherReset(SafeEvpCipherCtxHandle ctx, ReadOnlySpan <byte> iv)
 {
     fixed(byte *pIv = &MemoryMarshal.GetReference(iv))
     {
         return(EvpCipherReset(ctx, pIv, iv.Length));
     }
 }
Ejemplo n.º 2
0
        private void OpenKey(byte[] key, byte[] iv)
        {
            Func <IntPtr> algorithmFunc = FindAlgorithmSelector(key.Length * 8);

            _ctx = SafeEvpCipherCtxHandle.Create();

            // The algorithm pointer is a static pointer, so not having any cleanup code is correct.
            IntPtr algorithm = algorithmFunc();

            bool status = Interop.libcrypto.EVP_CipherInit_ex(
                _ctx,
                algorithm,
                IntPtr.Zero,
                key,
                iv,
                _encryptor ? 1 : 0);

            CheckBoolReturn(status);

            // OpenSSL will happily do PKCS#7 padding for us, but since we support padding modes
            // that it doesn't (PaddingMode.Zeros) we'll just always pad the blocks ourselves.
            status = Interop.libcrypto.EVP_CIPHER_CTX_set_padding(_ctx, 0);

            CheckBoolReturn(status);
        }
Ejemplo n.º 3
0
 internal static void CipherSetNonceLength(SafeEvpCipherCtxHandle ctx, int nonceLength)
 {
     if (!AndroidCryptoNative_CipherSetNonceLength(ctx, nonceLength))
     {
         throw new CryptographicException();
     }
 }
Ejemplo n.º 4
0
 internal static void EvpCipherSetCcmNonceLength(SafeEvpCipherCtxHandle ctx, int nonceLength)
 {
     if (!CryptoNative_EvpCipherSetCcmNonceLength(ctx, nonceLength))
     {
         throw CreateOpenSslCryptographicException();
     }
 }
Ejemplo n.º 5
0
        public OpenSslCipherLite(
            IntPtr algorithm,
            CipherMode cipherMode,
            int blockSizeInBytes,
            int paddingSizeInBytes,
            ReadOnlySpan <byte> key,
            int effectiveKeyLength,
            ReadOnlySpan <byte> iv,
            bool encrypting)
        {
            Debug.Assert(algorithm != IntPtr.Zero);

            BlockSizeInBytes   = blockSizeInBytes;
            PaddingSizeInBytes = paddingSizeInBytes;
            _ctx = Interop.Crypto.EvpCipherCreate(
                algorithm,
                ref MemoryMarshal.GetReference(key),
                key.Length * 8,
                effectiveKeyLength,
                ref MemoryMarshal.GetReference(iv),
                encrypting ? 1 : 0);

            Interop.Crypto.CheckValidOpenSslHandle(_ctx);

            // OpenSSL will happily do PKCS#7 padding for us, but since we support padding modes
            // that it doesn't (PaddingMode.Zeros) we'll just always pad the blocks ourselves.
            CheckBoolReturn(Interop.Crypto.EvpCipherCtxSetPadding(_ctx, 0));
        }
Ejemplo n.º 6
0
 internal static extern bool EVP_CipherInit_ex(
     SafeEvpCipherCtxHandle ctx,
     IntPtr cipher,
     IntPtr engineNull,
     byte[] key,
     byte[] iv,
     int enc);
Ejemplo n.º 7
0
 internal static bool EvpCipherFinalEx(
     SafeEvpCipherCtxHandle ctx,
     Span <byte> output,
     out int bytesWritten)
 {
     return(EvpCipherFinalEx(ctx, ref MemoryMarshal.GetReference(output), out bytesWritten));
 }
Ejemplo n.º 8
0
        private void OpenKey(CipherMode cipherMode, byte[] key)
        {
            // The algorithm pointer is a static pointer, so not having any cleanup code is correct.
            IntPtr algorithm;

            switch (cipherMode)
            {
            case CipherMode.CBC:
                algorithm = Interop.Crypto.EvpDes3Cbc();
                break;

            case CipherMode.ECB:
                algorithm = Interop.Crypto.EvpDes3Ecb();
                break;

            default:
                // This is what AesCngCryptoTransform::GetCipherAlgorithm throws when it doesn't understand the value.
                throw new NotSupportedException();
            }

            _ctx = Interop.Crypto.EvpCipherCreate(
                algorithm,
                key,
                IV,
                _encrypting ? 1 : 0);

            if (_ctx == null)
            {
                throw Interop.Crypto.CreateOpenSslCryptographicException();
            }

            // OpenSSL will happily do PKCS#7 padding for us, but since we support padding modes
            // that it doesn't (PaddingMode.Zeros) we'll just always pad the blocks ourselves.
            CheckBoolReturn(Interop.Crypto.EvpCipherCtxSetPadding(_ctx, 0));
        }
Ejemplo n.º 9
0
        private void ImportKey(ReadOnlySpan <byte> key)
        {
            _ctxHandle = Interop.Crypto.EvpCipherCreatePartial(GetCipher(key.Length * 8));

            Interop.Crypto.CheckValidOpenSslHandle(_ctxHandle);
            Interop.Crypto.EvpCipherSetKeyAndIV(
                _ctxHandle,
                key,
                Span <byte> .Empty,
                Interop.Crypto.EvpCipherDirection.NoChange);
        }
Ejemplo n.º 10
0
        private void EncryptInternal(
            ReadOnlySpan <byte> nonce,
            ReadOnlySpan <byte> plaintext,
            Span <byte> ciphertext,
            Span <byte> tag,
            ReadOnlySpan <byte> associatedData = default)
        {
            using (SafeEvpCipherCtxHandle ctx = Interop.Crypto.EvpCipherCreatePartial(GetCipher(_key.Length * 8)))
            {
                Interop.Crypto.CheckValidOpenSslHandle(ctx);

                // We need to set mode to encryption before setting the tag and nonce length
                // otherwise older versions of OpenSSL (i.e. 1.0.1f which can be found on Ubuntu 14.04) will fail
                Interop.Crypto.EvpCipherSetKeyAndIV(ctx, Span <byte> .Empty, Span <byte> .Empty, Interop.Crypto.EvpCipherDirection.Encrypt);
                Interop.Crypto.EvpCipherSetCcmTagLength(ctx, tag.Length);
                Interop.Crypto.EvpCipherSetCcmNonceLength(ctx, nonce.Length);
                Interop.Crypto.EvpCipherSetKeyAndIV(ctx, _key, nonce, Interop.Crypto.EvpCipherDirection.NoChange);

                if (associatedData.Length != 0)
                {
                    // length needs to be known ahead of time in CCM mode
                    Interop.Crypto.EvpCipherSetInputLength(ctx, plaintext.Length);

                    if (!Interop.Crypto.EvpCipherUpdate(ctx, Span <byte> .Empty, out _, associatedData))
                    {
                        throw Interop.Crypto.CreateOpenSslCryptographicException();
                    }
                }

                if (!Interop.Crypto.EvpCipherUpdate(ctx, ciphertext, out int ciphertextBytesWritten, plaintext))
                {
                    throw Interop.Crypto.CreateOpenSslCryptographicException();
                }

                if (!Interop.Crypto.EvpCipherFinalEx(
                        ctx,
                        ciphertext.Slice(ciphertextBytesWritten),
                        out int bytesWritten))
                {
                    throw Interop.Crypto.CreateOpenSslCryptographicException();
                }

                ciphertextBytesWritten += bytesWritten;

                if (ciphertextBytesWritten != ciphertext.Length)
                {
                    Debug.Fail($"CCM encrypt wrote {ciphertextBytesWritten} of {ciphertext.Length} bytes.");
                    throw new CryptographicException();
                }

                Interop.Crypto.EvpCipherGetCcmTag(ctx, tag);
            }
        }
Ejemplo n.º 11
0
 internal static void CipherUpdateAAD(
     SafeEvpCipherCtxHandle ctx,
     ReadOnlySpan <byte> input)
 {
     if (!CipherUpdateAAD(
             ctx,
             ref MemoryMarshal.GetReference(input),
             input.Length))
     {
         throw new CryptographicException();
     }
 }
Ejemplo n.º 12
0
 internal static bool EvpCipherUpdate(
     SafeEvpCipherCtxHandle ctx,
     Span <byte> output,
     out int bytesWritten,
     ReadOnlySpan <byte> input)
 {
     return(EvpCipherUpdate(
                ctx,
                ref MemoryMarshal.GetReference(output),
                out bytesWritten,
                ref MemoryMarshal.GetReference(input),
                input.Length));
 }
Ejemplo n.º 13
0
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_ctx != null)
                {
                    _ctx.Dispose();
                    _ctx = null !;
                }
            }

            base.Dispose(disposing);
        }
Ejemplo n.º 14
0
        private void OpenKey(IntPtr algorithm, byte[] key)
        {
            _ctx = Interop.Crypto.EvpCipherCreate(
                algorithm,
                key,
                IV,
                _encrypting ? 1 : 0);

            Interop.Crypto.CheckValidOpenSslHandle(_ctx);

            // OpenSSL will happily do PKCS#7 padding for us, but since we support padding modes
            // that it doesn't (PaddingMode.Zeros) we'll just always pad the blocks ourselves.
            CheckBoolReturn(Interop.Crypto.EvpCipherCtxSetPadding(_ctx, 0));
        }
Ejemplo n.º 15
0
        private void ImportKey(ReadOnlySpan <byte> key)
        {
            // Constructors should check key size before calling ImportKey.
            Debug.Assert(key.Length == KeySizeInBytes);
            _ctxHandle = Interop.Crypto.EvpCipherCreatePartial(Interop.Crypto.EvpChaCha20Poly1305());

            Interop.Crypto.CheckValidOpenSslHandle(_ctxHandle);
            Interop.Crypto.EvpCipherSetKeyAndIV(
                _ctxHandle,
                key,
                Span <byte> .Empty,
                Interop.Crypto.EvpCipherDirection.NoChange);

            Interop.Crypto.CipherSetNonceLength(_ctxHandle, NonceSizeInBytes);
        }
Ejemplo n.º 16
0
 internal static void EvpCipherSetKeyAndIV(
     SafeEvpCipherCtxHandle ctx,
     ReadOnlySpan <byte> key,
     ReadOnlySpan <byte> iv,
     EvpCipherDirection direction)
 {
     if (!EvpCipherSetKeyAndIV(
             ctx,
             ref MemoryMarshal.GetReference(key),
             ref MemoryMarshal.GetReference(iv),
             direction))
     {
         throw new CryptographicException();
     }
 }
Ejemplo n.º 17
0
        private void OpenKey(IntPtr algorithm, byte[] key, int effectiveKeyLength)
        {
            _ctx = Interop.Crypto.EvpCipherCreate(
                algorithm,
                ref MemoryMarshal.GetReference(key.AsSpan()),
                key.Length * 8,
                effectiveKeyLength,
                ref MemoryMarshal.GetReference(IV.AsSpan()),
                _encrypting ? 1 : 0);

            Interop.Crypto.CheckValidOpenSslHandle(_ctx);

            // OpenSSL will happily do PKCS#7 padding for us, but since we support padding modes
            // that it doesn't (PaddingMode.Zeros) we'll just always pad the blocks ourselves.
            CheckBoolReturn(Interop.Crypto.EvpCipherCtxSetPadding(_ctx, 0));
        }
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_ctx != null)
                {
                    _ctx.Dispose();
                    _ctx = null;
                }

                if (_decryptBuffer != null)
                {
                    Array.Clear(_decryptBuffer, 0, _decryptBuffer.Length);
                    _decryptBuffer = null;
                }
            }

            base.Dispose(disposing);
        }
Ejemplo n.º 19
0
        private void DecryptInternal(
            ReadOnlySpan <byte> nonce,
            ReadOnlySpan <byte> ciphertext,
            ReadOnlySpan <byte> tag,
            Span <byte> plaintext,
            ReadOnlySpan <byte> associatedData)
        {
            using (SafeEvpCipherCtxHandle ctx = Interop.Crypto.EvpCipherCreatePartial(GetCipher(_key.Length * 8)))
            {
                Interop.Crypto.CheckValidOpenSslHandle(ctx);
                Interop.Crypto.EvpCipherSetCcmNonceLength(ctx, nonce.Length);
                Interop.Crypto.EvpCipherSetCcmTag(ctx, tag);

                Interop.Crypto.EvpCipherSetKeyAndIV(ctx, _key, nonce, Interop.Crypto.EvpCipherDirection.Decrypt);

                if (associatedData.Length != 0)
                {
                    // length needs to be known ahead of time in CCM mode
                    Interop.Crypto.EvpCipherSetInputLength(ctx, ciphertext.Length);

                    if (!Interop.Crypto.EvpCipherUpdate(ctx, Span <byte> .Empty, out _, associatedData))
                    {
                        throw Interop.Crypto.CreateOpenSslCryptographicException();
                    }
                }

                if (!Interop.Crypto.EvpCipherUpdate(ctx, plaintext, out int plaintextBytesWritten, ciphertext))
                {
                    plaintext.Clear();
                    throw new CryptographicException(SR.Cryptography_AuthTagMismatch);
                }

                if (plaintextBytesWritten != plaintext.Length)
                {
                    Debug.Fail($"CCM decrypt wrote {plaintextBytesWritten} of {plaintext.Length} bytes.");
                    throw new CryptographicException();
                }

                // The OpenSSL documentation says not to call EvpCipherFinalEx for CCM decryption, and calling it will report failure.
                // https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Decryption_using_CCM_mode
            }
        }
        private void OpenKey(byte[] key, byte[] iv)
        {
            Func <IntPtr> algorithmFunc = FindAlgorithmSelector(key.Length * 8);

            // The algorithm pointer is a static pointer, so not having any cleanup code is correct.
            IntPtr algorithm = algorithmFunc();

            _ctx = Interop.Crypto.EvpCipherCreate(
                algorithm,
                key,
                iv,
                _encryptor ? 1 : 0);

            if (_ctx == null)
            {
                throw Interop.Crypto.CreateOpenSslCryptographicException();
            }

            // OpenSSL will happily do PKCS#7 padding for us, but since we support padding modes
            // that it doesn't (PaddingMode.Zeros) we'll just always pad the blocks ourselves.
            bool status = Interop.Crypto.EvpCipherCtxSetPadding(_ctx, 0);

            CheckBoolReturn(status);
        }
Ejemplo n.º 21
0
 internal static extern unsafe bool EvpCipherUpdate(
     SafeEvpCipherCtxHandle ctx,
     byte * @out,
     out int outl,
     byte * @in,
     int inl);
Ejemplo n.º 22
0
 internal static extern bool EvpCipherCtxSetPadding(SafeEvpCipherCtxHandle x, int padding);
Ejemplo n.º 23
0
 internal static extern bool EvpCipherReset(SafeEvpCipherCtxHandle ctx);
Ejemplo n.º 24
0
 private static extern bool CipherUpdateAAD(
     SafeEvpCipherCtxHandle ctx,
     ref byte @in,
     int inl);
Ejemplo n.º 25
0
 private static extern bool AndroidCryptoNative_CipherSetNonceLength(
     SafeEvpCipherCtxHandle ctx, int nonceLength);
Ejemplo n.º 26
0
 internal static extern unsafe bool EvpCipherFinalEx(
     SafeEvpCipherCtxHandle ctx,
     byte *outm,
     out int outl);
Ejemplo n.º 27
0
 internal static extern bool CipherSetTagLength(
     SafeEvpCipherCtxHandle ctx,
     int tagLength);
Ejemplo n.º 28
0
 private static extern bool EvpCipherUpdate(
     SafeEvpCipherCtxHandle ctx,
     ref byte @out,
     out int outl,
     ref byte @in,
     int inl);
Ejemplo n.º 29
0
        private void EncryptCore(
            ReadOnlySpan <byte> nonce,
            ReadOnlySpan <byte> plaintext,
            Span <byte> ciphertext,
            Span <byte> tag,
            ReadOnlySpan <byte> associatedData = default)
        {
            // Convert key length to bits.
            using (SafeEvpCipherCtxHandle ctx = Interop.Crypto.EvpCipherCreatePartial(GetCipher(_key.Length * 8)))
            {
                if (ctx.IsInvalid)
                {
                    throw new CryptographicException();
                }

                if (!Interop.Crypto.CipherSetTagLength(ctx, tag.Length))
                {
                    throw new CryptographicException();
                }

                Interop.Crypto.CipherSetNonceLength(ctx, nonce.Length);
                Interop.Crypto.EvpCipherSetKeyAndIV(ctx, _key, nonce, Interop.Crypto.EvpCipherDirection.Encrypt);

                if (associatedData.Length != 0)
                {
                    Interop.Crypto.CipherUpdateAAD(ctx, associatedData);
                }

                byte[]? rented = null;
                try
                {
                    Span <byte> ciphertextAndTag = stackalloc byte[0];
                    // Arbitrary limit.
                    const int StackAllocMax = 128;
                    if (checked (ciphertext.Length + tag.Length) <= StackAllocMax)
                    {
                        ciphertextAndTag = stackalloc byte[ciphertext.Length + tag.Length];
                    }
                    else
                    {
                        rented           = CryptoPool.Rent(ciphertext.Length + tag.Length);
                        ciphertextAndTag = new Span <byte>(rented, 0, ciphertext.Length + tag.Length);
                    }

                    if (!Interop.Crypto.EvpCipherUpdate(ctx, ciphertextAndTag, out int ciphertextBytesWritten, plaintext))
                    {
                        throw new CryptographicException();
                    }

                    if (!Interop.Crypto.EvpCipherFinalEx(
                            ctx,
                            ciphertextAndTag.Slice(ciphertextBytesWritten),
                            out int bytesWritten))
                    {
                        throw new CryptographicException();
                    }

                    ciphertextBytesWritten += bytesWritten;

                    // NOTE: Android appends tag to the end of the ciphertext in case of CCM/GCM and "encryption" mode

                    if (ciphertextBytesWritten != ciphertextAndTag.Length)
                    {
                        Debug.Fail($"CCM encrypt wrote {ciphertextBytesWritten} of {ciphertextAndTag.Length} bytes.");
                        throw new CryptographicException();
                    }

                    ciphertextAndTag[..ciphertext.Length].CopyTo(ciphertext);
Ejemplo n.º 30
0
 private static extern bool EvpCipherSetKeyAndIV(
     SafeEvpCipherCtxHandle ctx,
     ref byte key,
     ref byte iv,
     EvpCipherDirection direction);