1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
|
// CommonCrypto bindings for MonoMac and MonoTouch
//
// Authors:
// Sebastien Pouliot <sebastien@xamarin.com>
//
// Copyright 2012-2014 Xamarin Inc.
using System;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
namespace Crimson.CommonCrypto {
// int32_t -> CommonCryptor.h
enum CCCryptorStatus {
Success = 0,
ParamError = -4300,
BufferTooSmall = -4301,
MemoryFailure = -4302,
AlignmentError = -4303,
DecodeError = -4304,
Unimplemented = -4305
}
// uint32_t -> CommonCryptor.h
// note: not exposed publicly so it can stay signed
enum CCOperation {
Encrypt = 0,
Decrypt,
}
// uint32_t -> CommonCryptor.h
// note: not exposed publicly so it can stay signed
enum CCAlgorithm {
AES128 = 0,
DES,
TripleDES,
CAST,
RC4,
RC2,
Blowfish
}
// uint32_t -> CommonCryptor.h
// note: not exposed publicly so it can stay signed
[Flags]
enum CCOptions {
None = 0,
PKCS7Padding = 1,
ECBMode = 2
}
static class Cryptor {
const string libSystem = "/usr/lib/libSystem.dylib";
// size_t was changed to IntPtr for 32/64 bits size difference - even if mono is (moslty) used in 32bits only on OSX today
// not using `nint` to be able to resue this outside (if needed)
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorCreate (CCOperation op, CCAlgorithm alg, CCOptions options, /* const void* */ byte[] key, /* size_t */ IntPtr keyLength, /* const void* */ byte[] iv, /* CCCryptorRef* */ ref IntPtr cryptorRef);
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorRelease (/* CCCryptorRef */ IntPtr cryptorRef);
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorUpdate (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ byte[] dataIn, /* size_t */ IntPtr dataInLength, /* void* */ byte[] dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorUpdate (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ IntPtr dataIn, /* size_t */ IntPtr dataInLength, /* void* */ IntPtr dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorFinal (/* CCCryptorRef */ IntPtr cryptorRef, /* void* */ byte[] dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
[DllImport (libSystem)]
extern internal static int CCCryptorGetOutputLength (/* CCCryptorRef */ IntPtr cryptorRef, /* size_t */ IntPtr inputLength, bool final);
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorReset (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ IntPtr iv);
// helper method to reduce the amount of generate code for each cipher algorithm
static internal IntPtr Create (CCOperation operation, CCAlgorithm algorithm, CCOptions options, byte[] key, byte[] iv)
{
if (key == null)
throw new CryptographicException ("A null key was provided");
// unlike the .NET framework CommonCrypto does not support two-keys triple-des (128 bits) ref: #6967
if ((algorithm == CCAlgorithm.TripleDES) && (key.Length == 16)) {
byte[] key3 = new byte [24];
Buffer.BlockCopy (key, 0, key3, 0, 16);
Buffer.BlockCopy (key, 0, key3, 16, 8);
key = key3;
}
IntPtr cryptor = IntPtr.Zero;
CCCryptorStatus status = Cryptor.CCCryptorCreate (operation, algorithm, options, key, (IntPtr) key.Length, iv, ref cryptor);
if (status != CCCryptorStatus.Success)
throw new CryptographicUnexpectedOperationException ();
return cryptor;
}
// size_t was changed to IntPtr for 32/64 bits size difference - even if mono is (moslty) used in 32bits only on OSX today
[DllImport ("/System/Library/Frameworks/Security.framework/Security")]
unsafe extern internal static /* int */ int SecRandomCopyBytes (/* SecRandomRef */ IntPtr rnd, /* size_t */ IntPtr count, /* uint8_t* */ byte *data);
unsafe static internal void GetRandom (byte[] buffer)
{
fixed (byte* fixed_bytes = buffer) {
if (SecRandomCopyBytes (IntPtr.Zero, (IntPtr)buffer.Length, fixed_bytes) != 0)
throw new CryptographicException (Marshal.GetLastWin32Error ()); // errno
}
}
static internal unsafe void GetRandom (byte* data, IntPtr data_length)
{
if (SecRandomCopyBytes (IntPtr.Zero, data_length, data) != 0)
throw new CryptographicException (Marshal.GetLastWin32Error ()); // errno
}
}
#if !MONOTOUCH && !XAMMAC
static class KeyBuilder {
static public byte[] Key (int size)
{
byte[] buffer = new byte [size];
Cryptor.GetRandom (buffer);
return buffer;
}
static public byte[] IV (int size)
{
byte[] buffer = new byte [size];
Cryptor.GetRandom (buffer);
return buffer;
}
}
#endif
}
|