X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FSystem.Security%2FSystem.Security.Cryptography.Xml%2FSymmetricKeyWrap.cs;h=2dddfcee0f8ae5dce3852cc34d38270c08b91b8c;hb=82bc0ca4ced9d49ed9e1a483b415760ba8653500;hp=3a06bd675ee840f946d64382ecc4027c0f16eb82;hpb=24a7667524f1e4b5d722c45cd69e63a9f905cf56;p=mono.git diff --git a/mcs/class/System.Security/System.Security.Cryptography.Xml/SymmetricKeyWrap.cs b/mcs/class/System.Security/System.Security.Cryptography.Xml/SymmetricKeyWrap.cs index 3a06bd675ee..2dddfcee0f8 100644 --- a/mcs/class/System.Security/System.Security.Cryptography.Xml/SymmetricKeyWrap.cs +++ b/mcs/class/System.Security/System.Security.Cryptography.Xml/SymmetricKeyWrap.cs @@ -28,7 +28,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -#if NET_2_0 using System.IO; using System.Security.Cryptography; @@ -117,43 +116,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 +320,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,7 +353,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; + }*/ } } -#endif