Skip to content

Instantly share code, notes, and snippets.

@ayende ayende/open-ssl-sample.cs
Last active Dec 26, 2016

Embed
What would you like to do?
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
You can’t perform that action at this time.