1 // CommonCrypto bindings for MonoMac and MonoTouch
4 // Sebastien Pouliot <sebastien@xamarin.com>
6 // Copyright 2012-2014 Xamarin Inc.
9 using System.Security.Cryptography;
10 using System.Runtime.InteropServices;
12 namespace Crimson.CommonCrypto {
14 // int32_t -> CommonCryptor.h
15 enum CCCryptorStatus {
18 BufferTooSmall = -4301,
19 MemoryFailure = -4302,
20 AlignmentError = -4303,
25 // uint32_t -> CommonCryptor.h
26 // note: not exposed publicly so it can stay signed
32 // uint32_t -> CommonCryptor.h
33 // note: not exposed publicly so it can stay signed
44 // uint32_t -> CommonCryptor.h
45 // note: not exposed publicly so it can stay signed
53 static class Cryptor {
55 const string libSystem = "/usr/lib/libSystem.dylib";
57 // size_t was changed to IntPtr for 32/64 bits size difference - even if mono is (moslty) used in 32bits only on OSX today
58 // not using `nint` to be able to resue this outside (if needed)
60 [DllImport (libSystem)]
61 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);
63 [DllImport (libSystem)]
64 extern internal static CCCryptorStatus CCCryptorRelease (/* CCCryptorRef */ IntPtr cryptorRef);
66 [DllImport (libSystem)]
67 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);
69 [DllImport (libSystem)]
70 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);
72 [DllImport (libSystem)]
73 extern internal static CCCryptorStatus CCCryptorFinal (/* CCCryptorRef */ IntPtr cryptorRef, /* void* */ byte[] dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
75 [DllImport (libSystem)]
76 extern internal static int CCCryptorGetOutputLength (/* CCCryptorRef */ IntPtr cryptorRef, /* size_t */ IntPtr inputLength, bool final);
78 [DllImport (libSystem)]
79 extern internal static CCCryptorStatus CCCryptorReset (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ IntPtr iv);
81 // helper method to reduce the amount of generate code for each cipher algorithm
82 static internal IntPtr Create (CCOperation operation, CCAlgorithm algorithm, CCOptions options, byte[] key, byte[] iv)
85 throw new CryptographicException ("A null key was provided");
87 // unlike the .NET framework CommonCrypto does not support two-keys triple-des (128 bits) ref: #6967
88 if ((algorithm == CCAlgorithm.TripleDES) && (key.Length == 16)) {
89 byte[] key3 = new byte [24];
90 Buffer.BlockCopy (key, 0, key3, 0, 16);
91 Buffer.BlockCopy (key, 0, key3, 16, 8);
95 IntPtr cryptor = IntPtr.Zero;
96 CCCryptorStatus status = Cryptor.CCCryptorCreate (operation, algorithm, options, key, (IntPtr) key.Length, iv, ref cryptor);
97 if (status != CCCryptorStatus.Success)
98 throw new CryptographicUnexpectedOperationException ();
102 // size_t was changed to IntPtr for 32/64 bits size difference - even if mono is (moslty) used in 32bits only on OSX today
103 [DllImport ("/System/Library/Frameworks/Security.framework/Security")]
104 extern internal static /* int */ int SecRandomCopyBytes (/* SecRandomRef */ IntPtr rnd, /* size_t */ IntPtr count, /* uint8_t* */ byte[] bytes);
106 static internal void GetRandom (byte[] buffer)
108 if (SecRandomCopyBytes (IntPtr.Zero, (IntPtr) buffer.Length, buffer) != 0)
109 throw new CryptographicException (Marshal.GetLastWin32Error ()); // errno
113 #if !MONOTOUCH && !XAMMAC
114 static class KeyBuilder {
115 static public byte[] Key (int size)
117 byte[] buffer = new byte [size];
118 Cryptor.GetRandom (buffer);
122 static public byte[] IV (int size)
124 byte[] buffer = new byte [size];
125 Cryptor.GetRandom (buffer);