Last active
December 26, 2016 21:10
-
-
Save ayende/13b206b9d83e7aa126df77d6b12711f3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.IO; | |
| using System.Runtime.InteropServices; | |
| using System.Text; | |
| namespace ConsoleApplication13 | |
| { | |
| public static unsafe class OpenSsl | |
| { | |
| private const string OpenSllDll = | |
| @"C:\Users\ayende\Downloads\openssl-1.0.0e-x64_86-win64\openssl-1.0.0e-x64_86-win64\libeay32.dll"; | |
| [DllImport(OpenSllDll)] | |
| private static extern void ERR_load_crypto_strings(); | |
| [DllImport(OpenSllDll)] | |
| private static extern void OPENSSL_add_all_algorithms_noconf(); | |
| static OpenSsl() | |
| { | |
| ERR_load_crypto_strings(); | |
| OPENSSL_add_all_algorithms_noconf(); | |
| } | |
| public struct EncryptEvpChiperContext : IDisposable | |
| { | |
| private IntPtr _ctx; | |
| internal EncryptEvpChiperContext(IntPtr ctx) | |
| { | |
| _ctx = ctx; | |
| } | |
| public void EncryptBlock(byte[] src, byte[] dest) | |
| { | |
| fixed (byte* pSrc = src) | |
| fixed (byte* pDest = dest) | |
| { | |
| int outl; | |
| var rc = EVP_EncryptUpdate(_ctx, pDest, out outl, pSrc, src.Length); | |
| if (rc == 0) | |
| ThrowError(); | |
| } | |
| } | |
| public void Dispose() | |
| { | |
| if (_ctx != IntPtr.Zero) | |
| { | |
| int outl; | |
| var rc = EVP_EncryptFinal_ex(_ctx, null, out outl); | |
| if (rc == 0) | |
| ThrowError(); | |
| EVP_CIPHER_CTX_free(_ctx); | |
| _ctx = IntPtr.Zero; | |
| } | |
| } | |
| } | |
| public struct DecryptEvpChiperContext : IDisposable | |
| { | |
| private IntPtr _ctx; | |
| internal DecryptEvpChiperContext(IntPtr ctx) | |
| { | |
| _ctx = ctx; | |
| } | |
| public void DecryptBlock(byte[] src, byte[] dest) | |
| { | |
| fixed (byte* pSrc = src) | |
| fixed (byte* pDest = dest) | |
| { | |
| int outl; | |
| var rc = EVP_DecryptUpdate(_ctx, pDest, out outl, pSrc, src.Length); | |
| if (rc == 0) | |
| ThrowError(); | |
| if (outl != src.Length) | |
| throw new InvalidOperationException("data mismatch?"); | |
| } | |
| } | |
| public void Dispose() | |
| { | |
| if (_ctx != IntPtr.Zero) | |
| { | |
| int outl; | |
| var rc = EVP_DecryptFinal_ex(_ctx, null, out outl); | |
| if (rc == 0) | |
| ThrowError(); | |
| EVP_CIPHER_CTX_free(_ctx); | |
| _ctx = IntPtr.Zero; | |
| } | |
| } | |
| } | |
| public static EncryptEvpChiperContext EncryptUsing(byte[] key, byte[] iv) | |
| { | |
| var ctx = EVP_CIPHER_CTX_new(); | |
| if (ctx == IntPtr.Zero) | |
| { | |
| ThrowError(); | |
| } | |
| fixed (byte* pKey = key) | |
| fixed (byte* pIv = iv) | |
| { | |
| var rc = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), IntPtr.Zero, pKey, pIv); | |
| if (rc == 0) | |
| { | |
| EVP_CIPHER_CTX_free(ctx); | |
| ThrowError(); | |
| } | |
| EVP_CIPHER_CTX_set_padding(ctx, 0); | |
| } | |
| return new EncryptEvpChiperContext(ctx); | |
| } | |
| public static DecryptEvpChiperContext DecryptUsing(byte[] key, byte[] iv) | |
| { | |
| var ctx = EVP_CIPHER_CTX_new(); | |
| if (ctx == IntPtr.Zero) | |
| { | |
| ThrowError(); | |
| } | |
| fixed (byte* pKey = key) | |
| fixed (byte* pIv = iv) | |
| { | |
| var rc = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), IntPtr.Zero, pKey, pIv); | |
| if (rc == 0) | |
| { | |
| EVP_CIPHER_CTX_free(ctx); | |
| ThrowError(); | |
| } | |
| EVP_CIPHER_CTX_set_padding(ctx, 0); | |
| } | |
| return new DecryptEvpChiperContext(ctx); | |
| } | |
| private static void ThrowError() | |
| { | |
| var sb = new MemoryStream(); | |
| ERR_print_errors_cb((str, len, data) => | |
| { | |
| for (int i = 0; i < (int)len; i++) | |
| { | |
| sb.WriteByte(*(str + i)); | |
| } | |
| }, null); | |
| throw new InvalidOperationException(Encoding.UTF8.GetString(sb.ToArray())); | |
| } | |
| private delegate void PrintErrorsCallback(byte* str, IntPtr len, byte* data); | |
| [DllImport(OpenSllDll)] | |
| private static extern void ERR_print_errors_cb(PrintErrorsCallback cb, byte* data); | |
| [DllImport(OpenSllDll)] | |
| private static extern IntPtr EVP_CIPHER_CTX_new(); | |
| [DllImport(OpenSllDll)] | |
| private static extern void EVP_CIPHER_CTX_free(IntPtr ctx); | |
| [DllImport(OpenSllDll)] | |
| private static extern int EVP_EncryptInit_ex(IntPtr ctx, IntPtr type, | |
| IntPtr impl, byte* key, byte* iv); | |
| [DllImport(OpenSllDll)] | |
| private static extern int EVP_DecryptInit_ex(IntPtr ctx, IntPtr type, | |
| IntPtr impl, byte* key, byte* iv); | |
| [DllImport(OpenSllDll)] | |
| private static extern IntPtr EVP_aes_256_cbc(); | |
| [DllImport(OpenSllDll)] | |
| private static extern int EVP_EncryptUpdate(IntPtr ctx, byte* dest, out int outl, byte* src, int inl); | |
| [DllImport(OpenSllDll)] | |
| private static extern int EVP_EncryptFinal_ex(IntPtr ctx, byte* dest, out int outl); | |
| [DllImport(OpenSllDll)] | |
| private static extern int EVP_DecryptUpdate(IntPtr ctx, byte* dest, out int outl, byte* src, int inl); | |
| [DllImport(OpenSllDll)] | |
| private static extern int EVP_DecryptFinal_ex(IntPtr ctx, byte* outm, out int outl); | |
| [DllImport(OpenSllDll)] | |
| private static extern int EVP_CIPHER_CTX_set_padding(IntPtr x, int padding); | |
| } | |
| class Program | |
| { | |
| static void Main() | |
| { | |
| /* A 256 bit key */ | |
| byte[] key = Encoding.UTF8.GetBytes("01234567890123456789012345678901"); | |
| /* A 128 bit IV */ | |
| byte[] iv = Encoding.UTF8.GetBytes("01234567890123456"); | |
| /* Message to be encrypted */ | |
| byte[] plaintext = Encoding.UTF8.GetBytes(new string('a', 4096)); | |
| byte[] chiper = new byte[4096]; | |
| var ms = new MemoryStream(); | |
| using (var ctx = OpenSsl.EncryptUsing(key, iv)) | |
| { | |
| for (int i = 0; i < 10; i++) | |
| { | |
| ctx.EncryptBlock(plaintext, chiper); | |
| ms.Write(chiper, 0, chiper.Length); | |
| } | |
| } | |
| using (var ctx = OpenSsl.DecryptUsing(key, iv)) | |
| using (var stdout = Console.OpenStandardOutput()) | |
| { | |
| ms.Position = 0; | |
| for (int i = 0; i < 10; i++) | |
| { | |
| ms.Read(chiper, 0, chiper.Length); | |
| ctx.DecryptBlock(chiper, plaintext); | |
| stdout.Write(plaintext, 0, plaintext.Length); | |
| } | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment