* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / System.Security / System.Security.Cryptography.Xml / SymmetricKeyWrap.cs
index 3a06bd675ee840f946d64382ecc4027c0f16eb82..bdcfc14ab823c061b126677b4f7918243cfe356f 100644 (file)
@@ -117,43 +117,188 @@ namespace System.Security.Cryptography.Xml {
                        return C;
                }
 
-               [MonoTODO]
                public static byte[] AESKeyWrapDecrypt (byte[] rgbKey, byte[] rgbEncryptedWrappedKeyData)
                {
-                       throw new NotImplementedException ();
+                       SymmetricAlgorithm symAlg = SymmetricAlgorithm.Create ("Rijndael");
+                       symAlg.Mode = CipherMode.ECB;
+                       symAlg.Key = rgbKey;
+
+                       int N = ( rgbEncryptedWrappedKeyData.Length / 8 ) - 1;
+
+                       // From RFC 3394 - Advanced Encryption Standard (AES) Key Wrap Algorithm
+                       //
+                       // Inputs: Ciphertext, (n+1) 64-bit values (C0, C1, ..., Cn), and Key, K (the KEK)
+                       // Outputs: Plaintext, n 64-bit values (P1, P2, ..., Pn)
+                       //
+                       // 1. Initialize variables.
+                       //    Set A = C[0] 
+
+                       byte[] A = new byte [8];
+                       Buffer.BlockCopy (rgbEncryptedWrappedKeyData, 0, A, 0, 8);
+
+                       //    For i = 1 to n
+                       //    R[i] = C[i]
+
+                       byte[] R = new byte [N * 8];
+                       Buffer.BlockCopy (rgbEncryptedWrappedKeyData, 8, R, 0, rgbEncryptedWrappedKeyData.Length - 8);
+
+                       // 2. Compute intermediate values.
+                       //    For j = 5 to 0
+                       //       For i = n to 1
+                       //          B = AES-1(K, (A^t) | R[i]) where t = n*j+i
+                       //          A = MSB (64,B)
+                       //          R[i] = LSB (64,B)
+
+                       ICryptoTransform transform = symAlg.CreateDecryptor ();
+
+                       for (int j = 5; j >= 0; j -= 1) {
+                               for (int i = N; i >= 1; i -= 1) {
+                                       byte[] T = BitConverter.GetBytes ((long) N * j + i);
+                                       if (BitConverter.IsLittleEndian)
+                                               Array.Reverse (T);
+
+                                       byte[] B = new Byte [16];
+                                       byte[] r = new Byte [8];
+                                       Buffer.BlockCopy (R, 8 * (i - 1), r, 0, 8);
+                                       byte[] ciphertext = Concatenate (Xor (A, T), r);
+                                       transform.TransformBlock (ciphertext, 0, 16, B, 0);
+                                       A = MSB (B);
+                                       Buffer.BlockCopy (LSB (B), 0, R, 8 * (i - 1), 8);
+                               }
+                       }
+
+                       // 3. Output results
+                       //    If A is an appropriate initial value
+                       //    Then
+                       //       For i = 1 to n
+                       //          P[i] = R[i]
+                       //    Else
+                       //       Return an error
+
+                       return R;
                }
 
-               [MonoTODO]
                public static byte[] TripleDESKeyWrapEncrypt (byte[] rgbKey, byte[] rgbWrappedKeyData)
                {
-                       throw new NotImplementedException ();
+                       SymmetricAlgorithm symAlg = SymmetricAlgorithm.Create ("TripleDES");
+
+                       // Algorithm from http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap
+                       // The following algorithm wraps (encrypts) a key (the wrapped key, WK) under a TRIPLEDES
+                       // key-encryption-key (KEK) as adopted from [CMS-Algorithms].
+
+                       // 1. Represent the key being wrapped as an octet sequence. If it is a TRIPLEDES key, 
+                       //    this is 24 octets (192 bits) with odd parity bit as the bottom bit of each octet.
+
+                       // rgbWrappedKeyData is the key being wrapped.
+
+                       // 2. Compute the CMS key checksum (Section 5.6.1) call this CKS.
+
+                       byte[] cks = ComputeCMSKeyChecksum (rgbWrappedKeyData);
+
+                       // 3. Let WKCKS = WK || CKS, where || is concatenation.
+
+                       byte[] wkcks = Concatenate (rgbWrappedKeyData, cks);
+
+                       // 4. Generate 8 random octets and call this IV.
+                       symAlg.GenerateIV ();
+
+                       // 5. Encrypt WKCKS in CBC mode using KEK as the key and IV as the initialization vector.
+                       //    Call the results TEMP1.
+
+                       symAlg.Mode = CipherMode.CBC;
+                       symAlg.Padding = PaddingMode.None;
+                       symAlg.Key = rgbKey;
+                       byte[] temp1 = Transform (wkcks, symAlg.CreateEncryptor ());
+
+                       // 6. Let TEMP2 = IV || TEMP1.
+
+                       byte[] temp2 = Concatenate (symAlg.IV, temp1);
+
+                       // 7. Reverse the order of the octets in TEMP2 and call the result TEMP3.
+
+                       Array.Reverse (temp2); // TEMP3 is TEMP2
+
+                       // 8. Encrypt TEMP3 in CBC mode using the KEK and an initialization vector of 0x4adda22c79e82105. 
+                       //    The resulting cipher text is the desired result.  It is 40 octets long if a 168 bit key
+                       //    is being wrapped.
+
+                       symAlg.IV = new Byte [8] {0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05};
+
+                       byte[] rtnval = Transform (temp2, symAlg.CreateEncryptor ());
+
+                       return rtnval;
                }
 
-               [MonoTODO]
                public static byte[] TripleDESKeyWrapDecrypt (byte[] rgbKey, byte[] rgbEncryptedWrappedKeyData)
                {
-                       throw new NotImplementedException ();
+                       SymmetricAlgorithm symAlg = SymmetricAlgorithm.Create ("TripleDES");
+
+                       // Algorithm from http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap
+                       // The following algorithm unwraps (decrypts) a key as adopted from [CMS-Algorithms].
+
+                       // 1. Check the length of the cipher text is reasonable given the key type.  It must be
+                       //    40 bytes for a 168 bit key and either 32, 40, or 48 bytes for a 128, 192, or 256 bit
+                       //    key. If the length is not supported or inconsistent with the algorithm for which the
+                       //    key is intended, return error.
+
+                       // 2. Decrypt the cipher text with TRIPLEDES in CBC mode using the KEK and an initialization
+                       //    vector (IV) of 0x4adda22c79e82105.  Call the output TEMP3.
+
+                       symAlg.Mode = CipherMode.CBC;
+                       symAlg.Padding = PaddingMode.None;
+                       symAlg.Key = rgbKey;
+                       symAlg.IV = new Byte [8] {0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05};
+
+                       byte[] temp3 = Transform (rgbEncryptedWrappedKeyData, symAlg.CreateDecryptor ());
+
+                       // 3. Reverse the order of the octets in TEMP3 and call the result TEMP2.
+
+                       Array.Reverse (temp3); // TEMP2 is TEMP3.
+
+                       // 4. Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
+
+                       byte[] temp1 = new Byte [temp3.Length - 8];
+                       byte[] iv = new Byte [8];
+
+                       Buffer.BlockCopy (temp3, 0, iv, 0, 8);
+                       Buffer.BlockCopy (temp3, 8, temp1, 0, temp1.Length);
+
+                       // 5. Decrypt TEMP1 using TRIPLEDES in CBC mode using the KEK and the IV found in the previous step.
+                       //    Call the result WKCKS.
+
+                       symAlg.IV = iv;
+                       byte[] wkcks = Transform (temp1, symAlg.CreateDecryptor ());
+
+                       // 6. Decompose WKCKS.  CKS is the last 8 octets and WK, the wrapped key, are those octets before
+                       //    the CKS.
+
+                       byte[] cks = new byte [8];
+                       byte[] wk = new byte [wkcks.Length - 8];
+
+                       Buffer.BlockCopy (wkcks, 0, wk, 0, wk.Length);
+                       Buffer.BlockCopy (wkcks, wk.Length, cks, 0, 8);
+
+                       // 7. Calculate the CMS key checksum over the WK and compare with the CKS extracted in the above
+                       //    step. If they are not equal, return error.
+
+                       // 8. WK is the wrapped key, now extracted for use in data decryption.
+                       return wk;
                }
 
-               private static byte[] Transform (byte[] data, ICryptoTransform t, bool flush)
+               private static byte[] Transform (byte[] data, ICryptoTransform t)
                {
                        MemoryStream output = new MemoryStream ();
                        CryptoStream crypto = new CryptoStream (output, t, CryptoStreamMode.Write);
-                       crypto.Write (data, 0, data.Length);
 
-                       byte[] buf;
+                       crypto.Write (data, 0, data.Length);
+                       crypto.FlushFinalBlock ();
 
-                       if (flush) {
-                               crypto.Close ();
-                               output.Close ();
-                               buf = output.ToArray ();
-                       } else {
-                               buf = output.ToArray ();
-                               crypto.Close ();
-                               output.Close ();
-                       }
+                       byte[] result = output.ToArray ();
+                       
+                       output.Close ();
+                       crypto.Close ();
 
-                       return buf;
+                       return result; 
                 }
 
                private static byte[] ComputeCMSKeyChecksum (byte[] data)
@@ -176,15 +321,25 @@ namespace System.Security.Cryptography.Xml {
 
                private static byte[] MSB (byte[] input)
                {
-                       byte[] output = new byte [8];
-                       Buffer.BlockCopy (input, 0, output, 0, 8);
+                       return MSB (input, 8);
+               }
+
+               private static byte[] MSB (byte[] input, int bytes)
+               {
+                       byte[] output = new byte [bytes];
+                       Buffer.BlockCopy (input, 0, output, 0, bytes);
                        return output;
                }
 
                private static byte[] LSB (byte[] input)
                {
-                       byte[] output = new byte [8];
-                       Buffer.BlockCopy (input, 8, output, 0, 8);
+                       return LSB (input, 8);
+               }
+
+               private static byte[] LSB (byte[] input, int bytes)
+               {
+                       byte[] output = new byte [bytes];
+                       Buffer.BlockCopy (input, bytes, output, 0, bytes);
                        return output;
                }
 
@@ -199,6 +354,14 @@ namespace System.Security.Cryptography.Xml {
                                output [i] = (byte) (x [i] ^ y [i]);
                        return output;
                }
+
+/*             private static byte[] Xor (byte[] x, int n)
+               {
+                       byte[] output = new Byte [x.Length];
+                       for (int i = 0; i < x.Length; i += 1)
+                               output [i] = (byte) ((int) x [i] ^ n);
+                       return output;
+               }*/
        }
 }