internal static unsafe bool EvpCipherReset(SafeEvpCipherCtxHandle ctx, ReadOnlySpan <byte> iv) { fixed(byte *pIv = &MemoryMarshal.GetReference(iv)) { return(EvpCipherReset(ctx, pIv, iv.Length)); } }
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); }
internal static void CipherSetNonceLength(SafeEvpCipherCtxHandle ctx, int nonceLength) { if (!AndroidCryptoNative_CipherSetNonceLength(ctx, nonceLength)) { throw new CryptographicException(); } }
internal static void EvpCipherSetCcmNonceLength(SafeEvpCipherCtxHandle ctx, int nonceLength) { if (!CryptoNative_EvpCipherSetCcmNonceLength(ctx, nonceLength)) { throw CreateOpenSslCryptographicException(); } }
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)); }
internal static extern bool EVP_CipherInit_ex( SafeEvpCipherCtxHandle ctx, IntPtr cipher, IntPtr engineNull, byte[] key, byte[] iv, int enc);
internal static bool EvpCipherFinalEx( SafeEvpCipherCtxHandle ctx, Span <byte> output, out int bytesWritten) { return(EvpCipherFinalEx(ctx, ref MemoryMarshal.GetReference(output), out bytesWritten)); }
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)); }
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); }
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); } }
internal static void CipherUpdateAAD( SafeEvpCipherCtxHandle ctx, ReadOnlySpan <byte> input) { if (!CipherUpdateAAD( ctx, ref MemoryMarshal.GetReference(input), input.Length)) { throw new CryptographicException(); } }
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)); }
protected override void Dispose(bool disposing) { if (disposing) { if (_ctx != null) { _ctx.Dispose(); _ctx = null !; } } base.Dispose(disposing); }
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)); }
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); }
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(); } }
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); }
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); }
internal static extern unsafe bool EvpCipherUpdate( SafeEvpCipherCtxHandle ctx, byte * @out, out int outl, byte * @in, int inl);
internal static extern bool EvpCipherCtxSetPadding(SafeEvpCipherCtxHandle x, int padding);
internal static extern bool EvpCipherReset(SafeEvpCipherCtxHandle ctx);
private static extern bool CipherUpdateAAD( SafeEvpCipherCtxHandle ctx, ref byte @in, int inl);
private static extern bool AndroidCryptoNative_CipherSetNonceLength( SafeEvpCipherCtxHandle ctx, int nonceLength);
internal static extern unsafe bool EvpCipherFinalEx( SafeEvpCipherCtxHandle ctx, byte *outm, out int outl);
internal static extern bool CipherSetTagLength( SafeEvpCipherCtxHandle ctx, int tagLength);
private static extern bool EvpCipherUpdate( SafeEvpCipherCtxHandle ctx, ref byte @out, out int outl, ref byte @in, int inl);
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);
private static extern bool EvpCipherSetKeyAndIV( SafeEvpCipherCtxHandle ctx, ref byte key, ref byte iv, EvpCipherDirection direction);