This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / class / System.Security / System.Security.Cryptography.Xml / SymmetricKeyWrap.cs
1 //
2 // SymmetricKeyWrap.cs - Implements symmetric key wrap algorithms
3 //
4 // Author:
5 //      Tim Coleman (tim@timcoleman.com)
6 //
7 // Copyright (C) Tim Coleman, 2004
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 #if NET_2_0
32
33 using System.IO;
34 using System.Security.Cryptography;
35
36 namespace System.Security.Cryptography.Xml { 
37
38         internal class SymmetricKeyWrap {
39
40                 public SymmetricKeyWrap ()
41                 {
42                 }
43
44                 public static byte[] AESKeyWrapEncrypt (byte[] rgbKey, byte[] rgbWrappedKeyData)
45                 {
46                         SymmetricAlgorithm symAlg = SymmetricAlgorithm.Create ("Rijndael");
47
48                         // Apparently no one felt the need to document that this requires Electronic Codebook mode.
49                         symAlg.Mode = CipherMode.ECB;
50
51                         // This was also not documented anywhere.
52                         symAlg.IV = new byte [16] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
53         
54                         ICryptoTransform transform = symAlg.CreateEncryptor (rgbKey, symAlg.IV);
55
56                         int N = rgbWrappedKeyData.Length / 8;
57                         byte[] A;
58                         byte[] B = new Byte [16];
59                         byte [] C = new byte [8 * (N + 1)];
60
61                         // 1. if N is 1:
62                         //       B = AES(K)enc(0xA6A6A6A6A6A6A6A6|P(1))
63                         //       C(0) = MSB(B)
64                         //       C(1) = LSB(B)
65                         if (N == 1) {
66                                 A = new byte [8] {0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6};
67                                 transform.TransformBlock (Concatenate (A, rgbWrappedKeyData), 0, 16, B, 0);
68                                 Buffer.BlockCopy (MSB(B), 0, C, 0, 8);
69                                 Buffer.BlockCopy (LSB(B), 0, C, 8, 8);
70                         } else {
71                                 // if N > 1, perform the following steps:
72                                 // 2. Initialize variables:
73                                 //       Set A to 0xA6A6A6A6A6A6A6A6
74                                 //       For i = 1 to N,
75                                 //          R(i) = P(i)
76                                 A = new byte [8] {0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6};
77         
78                                 byte[][] R = new byte [N + 1][];
79                                 for (int i = 1; i <= N; i += 1) {
80                                         R [i] = new byte [8];
81                                         Buffer.BlockCopy (rgbWrappedKeyData, 8 * (i - 1), R [i], 0, 8);
82                                 }
83
84                                 // 3. Calculate intermediate values:
85                                 //       For j = 0 to 5
86                                 //          For i = 1 to N
87                                 //             t = i + j * N
88                                 //             B = AES(K)enc(A|R(i))
89                                 //             A = XOR(t, MSB(B))
90                                 //             R(i) = LSB(B)
91
92                                 for (int j = 0; j <= 5; j += 1) {
93                                         for (int i = 1; i <= N; i += 1) {
94                                                 transform.TransformBlock (Concatenate (A, R [i]), 0, 16, B, 0);
95         
96                                                 // Yawn.  It was nice of those at NIST to document how exactly we should XOR 
97                                                 // an integer value with a byte array.  Not.
98                                                 byte[] T = BitConverter.GetBytes ((long) (N * j + i));
99
100                                                 // This is nice.
101                                                 if (BitConverter.IsLittleEndian)
102                                                         Array.Reverse (T);
103
104                                                 A = Xor (T, MSB(B));
105                                                 R [i] = LSB (B);
106                                         }
107                                 }
108
109                                 // 4. Output the results:
110                                 //       Set C(0) = A
111                                 //       For i = 1 to N
112                                 //          C(i) = R(i)
113                                 Buffer.BlockCopy (A, 0, C, 0, 8);
114                                 for (int i = 1; i <= N; i += 1)
115                                         Buffer.BlockCopy (R [i], 0, C, 8 * i, 8);
116                         }
117                         return C;
118                 }
119
120                 [MonoTODO]
121                 public static byte[] AESKeyWrapDecrypt (byte[] rgbKey, byte[] rgbEncryptedWrappedKeyData)
122                 {
123                         throw new NotImplementedException ();
124                 }
125
126                 [MonoTODO]
127                 public static byte[] TripleDESKeyWrapEncrypt (byte[] rgbKey, byte[] rgbWrappedKeyData)
128                 {
129                         throw new NotImplementedException ();
130                 }
131
132                 [MonoTODO]
133                 public static byte[] TripleDESKeyWrapDecrypt (byte[] rgbKey, byte[] rgbEncryptedWrappedKeyData)
134                 {
135                         throw new NotImplementedException ();
136                 }
137
138                 private static byte[] Transform (byte[] data, ICryptoTransform t, bool flush)
139                 {
140                         MemoryStream output = new MemoryStream ();
141                         CryptoStream crypto = new CryptoStream (output, t, CryptoStreamMode.Write);
142                         crypto.Write (data, 0, data.Length);
143
144                         byte[] buf;
145
146                         if (flush) {
147                                 crypto.Close ();
148                                 output.Close ();
149                                 buf = output.ToArray ();
150                         } else {
151                                 buf = output.ToArray ();
152                                 crypto.Close ();
153                                 output.Close ();
154                         }
155
156                         return buf;
157                 }
158
159                 private static byte[] ComputeCMSKeyChecksum (byte[] data)
160                 {
161                         byte[] hash = HashAlgorithm.Create ("SHA1").ComputeHash (data);
162                         byte[] output = new byte [8];
163
164                         Buffer.BlockCopy (hash, 0, output, 0, 8);
165
166                         return output;
167                 }
168
169                 private static byte[] Concatenate (byte[] buf1, byte[] buf2)
170                 {
171                         byte[] output = new byte [buf1.Length + buf2.Length];
172                         Buffer.BlockCopy (buf1, 0, output, 0, buf1.Length);
173                         Buffer.BlockCopy (buf2, 0, output, buf1.Length, buf2.Length);
174                         return output;
175                 }
176
177                 private static byte[] MSB (byte[] input)
178                 {
179                         byte[] output = new byte [8];
180                         Buffer.BlockCopy (input, 0, output, 0, 8);
181                         return output;
182                 }
183
184                 private static byte[] LSB (byte[] input)
185                 {
186                         byte[] output = new byte [8];
187                         Buffer.BlockCopy (input, 8, output, 0, 8);
188                         return output;
189                 }
190
191                 private static byte[] Xor (byte[] x, byte[] y)
192                 {
193                         // This should *not* happen.
194                         if (x.Length != y.Length)
195                                 throw new CryptographicException ("Error performing Xor: arrays different length.");
196
197                         byte[] output = new byte [x.Length];
198                         for (int i = 0; i < x.Length; i += 1)
199                                 output [i] = (byte) (x [i] ^ y [i]);
200                         return output;
201                 }
202         }
203 }
204
205 #endif