2004-03-26 Sebastien Pouliot <sebastien@ximian.com>
[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 #if NET_1_2
11
12 using System.IO;
13 using System.Security.Cryptography;
14
15 namespace System.Security.Cryptography.Xml { 
16
17         internal class SymmetricKeyWrap {
18
19                 public SymmetricKeyWrap ()
20                 {
21                 }
22
23                 public static byte[] AESKeyWrapEncrypt (byte[] rgbKey, byte[] rgbWrappedKeyData)
24                 {
25                         SymmetricAlgorithm symAlg = SymmetricAlgorithm.Create ("Rijndael");
26
27                         // Apparently no one felt the need to document that this requires Electronic Codebook mode.
28                         symAlg.Mode = CipherMode.ECB;
29
30                         // This was also not documented anywhere.
31                         symAlg.IV = new byte [16] {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
32         
33                         ICryptoTransform transform = symAlg.CreateEncryptor (rgbKey, symAlg.IV);
34
35                         int N = rgbWrappedKeyData.Length / 8;
36                         byte[] A;
37                         byte[] B = new Byte [16];
38                         byte [] C = new byte [8 * (N + 1)];
39
40                         // 1. if N is 1:
41                         //       B = AES(K)enc(0xA6A6A6A6A6A6A6A6|P(1))
42                         //       C(0) = MSB(B)
43                         //       C(1) = LSB(B)
44                         if (N == 1) {
45                                 A = new byte [8] {0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6};
46                                 transform.TransformBlock (Concatenate (A, rgbWrappedKeyData), 0, 16, B, 0);
47                                 Buffer.BlockCopy (MSB(B), 0, C, 0, 8);
48                                 Buffer.BlockCopy (LSB(B), 0, C, 8, 8);
49                         } else {
50                                 // if N > 1, perform the following steps:
51                                 // 2. Initialize variables:
52                                 //       Set A to 0xA6A6A6A6A6A6A6A6
53                                 //       For i = 1 to N,
54                                 //          R(i) = P(i)
55                                 A = new byte [8] {0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6};
56         
57                                 byte[][] R = new byte [N + 1][];
58                                 for (int i = 1; i <= N; i += 1) {
59                                         R [i] = new byte [8];
60                                         Buffer.BlockCopy (rgbWrappedKeyData, 8 * (i - 1), R [i], 0, 8);
61                                 }
62
63                                 // 3. Calculate intermediate values:
64                                 //       For j = 0 to 5
65                                 //          For i = 1 to N
66                                 //             t = i + j * N
67                                 //             B = AES(K)enc(A|R(i))
68                                 //             A = XOR(t, MSB(B))
69                                 //             R(i) = LSB(B)
70
71                                 for (int j = 0; j <= 5; j += 1) {
72                                         for (int i = 1; i <= N; i += 1) {
73                                                 transform.TransformBlock (Concatenate (A, R [i]), 0, 16, B, 0);
74         
75                                                 // Yawn.  It was nice of those at NIST to document how exactly we should XOR 
76                                                 // an integer value with a byte array.  Not.
77                                                 byte[] T = BitConverter.GetBytes ((long) (N * j + i));
78
79                                                 // This is nice.
80                                                 if (BitConverter.IsLittleEndian)
81                                                         Array.Reverse (T);
82
83                                                 A = Xor (T, MSB(B));
84                                                 R [i] = LSB (B);
85                                         }
86                                 }
87
88                                 // 4. Output the results:
89                                 //       Set C(0) = A
90                                 //       For i = 1 to N
91                                 //          C(i) = R(i)
92                                 Buffer.BlockCopy (A, 0, C, 0, 8);
93                                 for (int i = 1; i <= N; i += 1)
94                                         Buffer.BlockCopy (R [i], 0, C, 8 * i, 8);
95                         }
96                         return C;
97                 }
98
99                 [MonoTODO]
100                 public static byte[] AESKeyWrapDecrypt (byte[] rgbKey, byte[] rgbEncryptedWrappedKeyData)
101                 {
102                         throw new NotImplementedException ();
103                 }
104
105                 [MonoTODO]
106                 public static byte[] TripleDESKeyWrapEncrypt (byte[] rgbKey, byte[] rgbWrappedKeyData)
107                 {
108                         throw new NotImplementedException ();
109                 }
110
111                 [MonoTODO]
112                 public static byte[] TripleDESKeyWrapDecrypt (byte[] rgbKey, byte[] rgbEncryptedWrappedKeyData)
113                 {
114                         throw new NotImplementedException ();
115                 }
116
117                 private static byte[] Transform (byte[] data, ICryptoTransform t, bool flush)
118                 {
119                         MemoryStream output = new MemoryStream ();
120                         CryptoStream crypto = new CryptoStream (output, t, CryptoStreamMode.Write);
121                         crypto.Write (data, 0, data.Length);
122
123                         byte[] buf;
124
125                         if (flush) {
126                                 crypto.Close ();
127                                 output.Close ();
128                                 buf = output.ToArray ();
129                         } else {
130                                 buf = output.ToArray ();
131                                 crypto.Close ();
132                                 output.Close ();
133                         }
134
135                         return buf;
136                 }
137
138                 private static byte[] ComputeCMSKeyChecksum (byte[] data)
139                 {
140                         byte[] hash = HashAlgorithm.Create ("SHA1").ComputeHash (data);
141                         byte[] output = new byte [8];
142
143                         Buffer.BlockCopy (hash, 0, output, 0, 8);
144
145                         return output;
146                 }
147
148                 private static byte[] Concatenate (byte[] buf1, byte[] buf2)
149                 {
150                         byte[] output = new byte [buf1.Length + buf2.Length];
151                         Buffer.BlockCopy (buf1, 0, output, 0, buf1.Length);
152                         Buffer.BlockCopy (buf2, 0, output, buf1.Length, buf2.Length);
153                         return output;
154                 }
155
156                 private static byte[] MSB (byte[] input)
157                 {
158                         byte[] output = new byte [8];
159                         Buffer.BlockCopy (input, 0, output, 0, 8);
160                         return output;
161                 }
162
163                 private static byte[] LSB (byte[] input)
164                 {
165                         byte[] output = new byte [8];
166                         Buffer.BlockCopy (input, 8, output, 0, 8);
167                         return output;
168                 }
169
170                 private static byte[] Xor (byte[] x, byte[] y)
171                 {
172                         // This should *not* happen.
173                         if (x.Length != y.Length)
174                                 throw new CryptographicException ("Error performing Xor: arrays different length.");
175
176                         byte[] output = new byte [x.Length];
177                         for (int i = 0; i < x.Length; i += 1)
178                                 output [i] = (byte) (x [i] ^ y [i]);
179                         return output;
180                 }
181         }
182 }
183
184 #endif