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)] CCCryptorCreate(CCOperation op, CCAlgorithm alg, CCOptions options, byte[] key, IntPtr keyLength, byte[] iv, ref IntPtr cryptorRef)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)] CCCryptorRelease( IntPtr cryptorRef)64 extern internal static CCCryptorStatus CCCryptorRelease (/* CCCryptorRef */ IntPtr cryptorRef); 65 66 [DllImport (libSystem)] CCCryptorUpdate( IntPtr cryptorRef, byte[] dataIn, IntPtr dataInLength, byte[] dataOut, IntPtr dataOutAvailable, ref IntPtr dataOutMoved)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)] CCCryptorUpdate( IntPtr cryptorRef, IntPtr dataIn, IntPtr dataInLength, IntPtr dataOut, IntPtr dataOutAvailable, ref IntPtr dataOutMoved)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)] CCCryptorFinal( IntPtr cryptorRef, byte[] dataOut, IntPtr dataOutAvailable, ref IntPtr dataOutMoved)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)] CCCryptorGetOutputLength( IntPtr cryptorRef, IntPtr inputLength, bool final)76 extern internal static int CCCryptorGetOutputLength (/* CCCryptorRef */ IntPtr cryptorRef, /* size_t */ IntPtr inputLength, bool final); 77 78 [DllImport (libSystem)] CCCryptorReset( IntPtr cryptorRef, IntPtr iv)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 Create(CCOperation operation, CCAlgorithm algorithm, CCOptions options, byte[] key, byte[] iv)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")] SecRandomCopyBytes( IntPtr rnd, IntPtr count, byte[] bytes)104 extern internal static /* int */ int SecRandomCopyBytes (/* SecRandomRef */ IntPtr rnd, /* size_t */ IntPtr count, /* uint8_t* */ byte[] bytes); 105 GetRandom(byte[] buffer)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 { Key(int size)115 static public byte[] Key (int size) 116 { 117 byte[] buffer = new byte [size]; 118 Cryptor.GetRandom (buffer); 119 return buffer; 120 } 121 IV(int size)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 } 131