Merge pull request #2810 from kumpera/fix_hazard_free
[mono.git] / mcs / class / corlib / CommonCrypto / CommonCrypto.cs
1 // CommonCrypto bindings for MonoMac and MonoTouch
2 //
3 // Authors:
4 //      Sebastien Pouliot  <sebastien@xamarin.com>
5 //
6 // Copyright 2012-2014 Xamarin Inc.
7
8 using System;
9 using System.Security.Cryptography;
10 using System.Runtime.InteropServices;
11
12 namespace Crimson.CommonCrypto {
13
14         // int32_t -> CommonCryptor.h
15         enum CCCryptorStatus {
16             Success                     = 0,
17         ParamError              = -4300,
18             BufferTooSmall      = -4301,
19         MemoryFailure   = -4302,
20         AlignmentError  = -4303,
21         DecodeError             = -4304,
22         Unimplemented   = -4305
23         }
24         
25         // uint32_t -> CommonCryptor.h
26         // note: not exposed publicly so it can stay signed
27         enum CCOperation {
28                 Encrypt = 0, 
29                 Decrypt,     
30         }
31
32         // uint32_t -> CommonCryptor.h
33         // note: not exposed publicly so it can stay signed
34         enum CCAlgorithm {
35                 AES128 = 0,
36                 DES,        
37                 TripleDES,       
38                 CAST,       
39                 RC4,
40                 RC2,   
41                 Blowfish    
42         }
43         
44         // uint32_t -> CommonCryptor.h
45         // note: not exposed publicly so it can stay signed
46         [Flags]
47         enum CCOptions {
48                 None                    = 0,
49                 PKCS7Padding    = 1,
50                 ECBMode                 = 2
51         }
52         
53         static class Cryptor {
54                 
55                 const string libSystem = "/usr/lib/libSystem.dylib";
56                 
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)
59                 
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);
62
63                 [DllImport (libSystem)]
64                 extern internal static CCCryptorStatus CCCryptorRelease (/* CCCryptorRef */ IntPtr cryptorRef);
65
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);
68
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);
71
72                 [DllImport (libSystem)]
73                 extern internal static CCCryptorStatus CCCryptorFinal (/* CCCryptorRef */ IntPtr cryptorRef, /* void* */ byte[] dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
74
75                 [DllImport (libSystem)]
76                 extern internal static int CCCryptorGetOutputLength (/* CCCryptorRef */ IntPtr cryptorRef, /* size_t */ IntPtr inputLength, bool final);
77
78                 [DllImport (libSystem)]
79                 extern internal static CCCryptorStatus CCCryptorReset (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ IntPtr iv);
80                 
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)
83                 {
84                         if (key == null)
85                                 throw new CryptographicException ("A null key was provided");
86                         
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);
92                                 key = key3;
93                         }
94                         
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 ();
99                         return cryptor;
100                 }
101
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);
105                 
106                 static internal void GetRandom (byte[] buffer)
107                 {
108                         if (SecRandomCopyBytes (IntPtr.Zero, (IntPtr) buffer.Length, buffer) != 0)
109                                 throw new CryptographicException (Marshal.GetLastWin32Error ()); // errno
110                 }
111         }
112         
113 #if !MONOTOUCH && !XAMMAC
114         static class KeyBuilder {
115                 static public byte[] Key (int size) 
116                 {
117                         byte[] buffer = new byte [size];
118                         Cryptor.GetRandom (buffer);
119                         return buffer;
120                 }
121         
122                 static public byte[] IV (int size) 
123                 {
124                         byte[] buffer = new byte [size];
125                         Cryptor.GetRandom (buffer);
126                         return buffer;
127                 }
128         }
129 #endif
130 }