[bcl] Add CommonCrypto to corlib, Mono.Security and System.Core.
[mono.git] / mcs / class / corlib / CommonCrypto / RijndaelManaged.cs
1 //
2 // RijndaelManaged.cs: Use CommonCrypto AES when possible, 
3 //      fallback on RijndaelManagedTransform otherwise
4 //
5 // Authors:
6 //      Sebastien Pouliot  <sebastien@xamarin.com>
7 //
8 // Copyright 2012 Xamarin Inc.
9 //
10
11 using System;
12 using System.Security.Cryptography;
13
14 using Mono.Security.Cryptography;
15 using Crimson.CommonCrypto;
16
17 namespace System.Security.Cryptography {
18         
19         public sealed class RijndaelManaged : Rijndael {
20                 
21                 public RijndaelManaged ()
22                 {
23                 }
24                 
25                 public override void GenerateIV ()
26                 {
27                         IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
28                 }
29                 
30                 public override void GenerateKey ()
31                 {
32                         KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
33                 }
34                 
35                 public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV) 
36                 {
37                         // AES is Rijndael with a 128 bits block size, so we can use CommonCrypto in this case
38                         if (BlockSize == 128) {
39                                 IntPtr decryptor = IntPtr.Zero;
40                                 switch (Mode) {
41                                 case CipherMode.CBC:
42                                         decryptor = Cryptor.Create (CCOperation.Decrypt, CCAlgorithm.AES128, CCOptions.None, rgbKey, rgbIV);
43                                         return new FastCryptorTransform (decryptor, this, false, rgbIV);
44                                 case CipherMode.ECB:
45                                         decryptor = Cryptor.Create (CCOperation.Decrypt, CCAlgorithm.AES128, CCOptions.ECBMode, rgbKey, rgbIV);
46                                         return new FastCryptorTransform (decryptor, this, false, rgbIV);
47                                 default:
48                                         // CFB cipher mode is not supported by the (old) API we used (for compatibility) so we fallback for them
49                                         // FIXME: benchmark if we're better with RijndaelManagedTransform or CryptorTransform for CFB mode
50                                         break;
51                                 }
52                         }
53
54             return NewEncryptor(rgbKey,
55                                 ModeValue,
56                                 rgbIV,
57                                 FeedbackSizeValue,
58                                 RijndaelManagedTransformMode.Decrypt);
59                 }
60                 
61                 public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV) 
62                 {
63                         if (BlockSize == 128) {
64                                 IntPtr encryptor = IntPtr.Zero;
65                                 switch (Mode) {
66                                 case CipherMode.CBC:
67                                         encryptor = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.AES128, CCOptions.None, rgbKey, rgbIV);
68                                         return new FastCryptorTransform (encryptor, this, true, rgbIV);
69                                 case CipherMode.ECB:
70                                         encryptor = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.AES128, CCOptions.ECBMode, rgbKey, rgbIV);
71                                         return new FastCryptorTransform (encryptor, this, true, rgbIV);
72                                 default:
73                                         // CFB cipher mode is not supported by the (old) API we used (for compatibility) so we fallback for them
74                                         // FIXME: benchmark if we're better with RijndaelManagedTransform or CryptorTransform for CFB mode
75                                         break;
76                                 }
77                         }
78
79             return NewEncryptor(rgbKey,
80                                 ModeValue,
81                                 rgbIV,
82                                 FeedbackSizeValue,
83                                 RijndaelManagedTransformMode.Encrypt);
84         }
85
86
87         private ICryptoTransform NewEncryptor (byte[] rgbKey,
88                                                CipherMode mode,
89                                                byte[] rgbIV,
90                                                int feedbackSize,
91                                                RijndaelManagedTransformMode encryptMode) {
92             // Build the key if one does not already exist
93             if (rgbKey == null) {
94                 rgbKey = Utils.GenerateRandom(KeySizeValue / 8);
95             }
96
97             // If not ECB mode, make sure we have an IV. In CoreCLR we do not support ECB, so we must have
98             // an IV in all cases.
99 #if !FEATURE_CRYPTO
100             if (mode != CipherMode.ECB) {
101 #endif // !FEATURE_CRYPTO
102                 if (rgbIV == null) {
103                     rgbIV = Utils.GenerateRandom(BlockSizeValue / 8);
104                 }
105 #if !FEATURE_CRYPTO
106             }
107 #endif // !FEATURE_CRYPTO
108
109             // Create the encryptor/decryptor object
110             return new RijndaelManagedTransform (rgbKey,
111                                                  mode,
112                                                  rgbIV,
113                                                  BlockSizeValue,
114                                                  feedbackSize,
115                                                  PaddingValue,
116                                                  encryptMode);
117         }                            
118         }
119 }