// // System.Security.Cryptography.DES // // Author: // Sergey Chaban (serge@wildwestsoftware.com) // Sebastien Pouliot // // Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com) // Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System.Globalization; using System.Runtime.InteropServices; // References: // a. FIPS PUB 46-3: Data Encryption Standard // http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf namespace System.Security.Cryptography { #if NET_2_0 [ComVisible (true)] #endif public abstract class DES : SymmetricAlgorithm { private const int keySizeByte = 8; #if NET_2_0 protected DES () #else public DES () #endif { KeySizeValue = 64; BlockSizeValue = 64; FeedbackSizeValue = 8; LegalKeySizesValue = new KeySizes[1]; LegalKeySizesValue[0] = new KeySizes(64, 64, 0); LegalBlockSizesValue = new KeySizes[1]; LegalBlockSizesValue[0] = new KeySizes(64, 64, 0); } public static new DES Create () { return Create ("System.Security.Cryptography.DES"); } public static new DES Create (string algo) { return (DES) CryptoConfig.CreateFromName (algo); } // Ek(Ek(m)) = m internal static readonly byte[,] weakKeys = { { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, { 0x1F, 0x1F, 0x1F, 0x1F, 0x0F, 0x0F, 0x0F, 0x0F }, { 0xE1, 0xE1, 0xE1, 0xE1, 0xF1, 0xF1, 0xF1, 0xF1 }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, }; // Ek1(Ek2(m)) = m internal static readonly byte[,] semiWeakKeys = { { 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x0E }, // map to packed key 011F011F010E010E { 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xF0, 0x00, 0xF0 }, // map to packed key 01E001E001F101F1 { 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE }, // map to packed key 01FE01FE01FE01FE { 0x1E, 0x00, 0x1E, 0x00, 0x0E, 0x00, 0x0E, 0x00 }, // map to packed key 1F011F010E010E01 { 0x1E, 0xE0, 0x1E, 0xE0, 0x0E, 0xF0, 0x0E, 0xF0 }, // map to packed key 1FE01FE00EF10EF1 { 0x1E, 0xFE, 0x1E, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE }, // map to packed key 1FFE1FFE0EFE0EFE { 0xE0, 0x00, 0xE0, 0x00, 0xF0, 0x00, 0xF0, 0x00 }, // map to packed key E001E001F101F101 { 0xE0, 0x1E, 0xE0, 0x1E, 0xF0, 0x0E, 0xF0, 0x0E }, // map to packed key E01FE01FF10EF10E { 0xE0, 0xFE, 0xE0, 0xFE, 0xF0, 0xFE, 0xF0, 0xFE }, // map to packed key E0FEE0FEF1FEF1FE { 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00 }, // map to packed key FE01FE01FE01FE01 { 0xFE, 0x1E, 0xFE, 0x1E, 0xFE, 0x0E, 0xFE, 0x0E }, // map to packed key FE1FFE1FFE0EFE0E { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF0, 0xFE, 0xF0 }, // map to packed key FEE0FEE0FEF1FEF1 }; public static bool IsWeakKey (byte[] rgbKey) { #if NET_2_0 if (rgbKey == null) throw new CryptographicException (Locale.GetText ("Null Key")); #endif if (rgbKey.Length != keySizeByte) throw new CryptographicException (Locale.GetText ("Wrong Key Length")); // (fast) pre-check with "weak bytes" for (int i=0; i < rgbKey.Length; i++) { switch (rgbKey [i] | 0x11) { case 0x11: case 0x1F: case 0xF1: case 0xFF: break; default: return false; } } // compare with known weak keys for (int i=0; i < (weakKeys.Length >> 3); i++) { int j = 0; for (; j < rgbKey.Length; j++) { if ((rgbKey [j] ^ weakKeys [i,j]) > 1) break; } if (j==8) return true; } return false; } public static bool IsSemiWeakKey (byte[] rgbKey) { #if NET_2_0 if (rgbKey == null) throw new CryptographicException (Locale.GetText ("Null Key")); #endif if (rgbKey.Length != keySizeByte) throw new CryptographicException (Locale.GetText ("Wrong Key Length")); // (fast) pre-check with "weak bytes" for (int i=0; i < rgbKey.Length; i++) { switch (rgbKey [i] | 0x11) { case 0x11: case 0x1F: case 0xF1: case 0xFF: break; default: return false; } } // compare with known weak keys for (int i=0; i < (semiWeakKeys.Length >> 3); i++) { int j = 0; for (; j < rgbKey.Length; j++) { if ((rgbKey [j] ^ semiWeakKeys [i,j]) > 1) break; } if (j==8) return true; } return false; } public override byte[] Key { get { if (KeyValue == null) { // GenerateKey is responsible to return a valid key // e.g. no weak or semi-weak keys GenerateKey (); } return (byte[]) KeyValue.Clone (); } set { if (value == null) throw new ArgumentNullException ("Key"); if (value.Length != keySizeByte) throw new ArgumentException (Locale.GetText ("Wrong Key Length")); if (IsWeakKey (value)) throw new CryptographicException (Locale.GetText ("Weak Key")); if (IsSemiWeakKey (value)) throw new CryptographicException (Locale.GetText ("Semi Weak Key")); KeyValue = (byte[]) value.Clone (); } } } }