/// <summary> /// Decrypt in aes128-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 /// </summary> /// <param name="key">key data</param> /// <param name="cipher">cipher data to be decrypted</param> /// <param name="usage">key usage number</param> /// <param name="aesKeyType">aes key type (128bit/256bit)</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use decrypted data directly if this parameter is null. /// </param> /// <returns>the decrypted data</returns> public static byte[] Decrypt( byte[] key, byte[] cipher, int usage, AesKeyType aesKeyType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == cipher) { throw new ArgumentNullException("cipher"); } // the cipher has two parts: encrypted(confounder + plain) + hmac byte[] encryptedData = ArrayUtility.SubArray <byte>( cipher, 0, cipher.Length - ConstValue.HMAC_HASH_OUTPUT_SIZE); byte[] hmacData = ArrayUtility.SubArray <byte>( cipher, cipher.Length - ConstValue.HMAC_HASH_OUTPUT_SIZE); // use ke key (the encryption key) to decrypt byte[] ke = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ke, aesKeyType); byte[] initialVector = new byte[ConstValue.AES_BLOCK_SIZE]; CipherTextStealingMode aesCtsCrypto = CryptoUtility.CreateAesCtsCrypto(ke, initialVector); byte[] decryptedData = aesCtsCrypto.DecryptFinal(encryptedData, 0, encryptedData.Length); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(decryptedData); } else { toBeSignedData = decryptedData; } // use ki key (the integrity key) to verify hmac data byte[] ki = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ki, aesKeyType); byte[] expectedHmacData = CryptoUtility.ComputeHmacSha1(ki, toBeSignedData); expectedHmacData = ArrayUtility.SubArray <byte>(expectedHmacData, 0, ConstValue.HMAC_HASH_OUTPUT_SIZE); if (!ArrayUtility.CompareArrays <byte>(hmacData, expectedHmacData)) { throw new FormatException( "Decryption: failed integrity check in hmac checksum."); } // remove confounder data decryptedData = ArrayUtility.SubArray <byte>(decryptedData, ConstValue.AES_BLOCK_SIZE, decryptedData.Length - ConstValue.AES_BLOCK_SIZE); return(decryptedData); }
/// <summary> /// RC4-HMAC / RC4-HMAC-EXP decryption /// </summary> /// <param name="key">the secret key</param> /// <param name="cipher">the encrypted cipher data</param> /// <param name="usage">key usage number</param> /// <param name="encryptionType">encryption type</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use decrypted data directly if this parameter is null. /// </param> /// <returns>the decrypted data</returns> public static byte[] Decrypt( byte[] key, byte[] cipher, int usage, EncryptionType encryptionType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == cipher) { throw new ArgumentNullException("cipher"); } // get checksum and encrypted data byte[] checksum = ArrayUtility.SubArray(cipher, 0, ConstValue.MD5_CHECKSUM_SIZE); byte[] encryptedData = ArrayUtility.SubArray(cipher, ConstValue.MD5_CHECKSUM_SIZE); // get salt and hash byte[] salt = GetSalt(usage, encryptionType); byte[] hash = CryptoUtility.ComputeMd5Hmac(key, salt); byte[] hashExp = GetExpHash(hash, encryptionType); // get rc4 decryption key byte[] rc4Key = CryptoUtility.ComputeMd5Hmac(hashExp, checksum); // decrypt ICryptoTransform decryptor = CryptoUtility.CreateRc4Decryptor(rc4Key); byte[] plain = decryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(plain); } else { toBeSignedData = plain; } // verify checksum byte[] expectedChecksum = CryptoUtility.ComputeMd5Hmac(hash, toBeSignedData); if (!ArrayUtility.CompareArrays(checksum, expectedChecksum)) { throw new FormatException("Decryption: invalid checksum."); } // remove confounder return(ArrayUtility.SubArray(plain, ConstValue.CONFOUNDER_SIZE)); }
/// <summary> /// Decrypt in aes128-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 /// </summary> /// <param name="key">key data</param> /// <param name="cipher">cipher data to be decrypted</param> /// <param name="usage">key usage number</param> /// <param name="aesKeyType">aes key type (128bit/256bit)</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use decrypted data directly if this parameter is null. /// </param> /// <returns>the decrypted data</returns> public static byte[] Decrypt( byte[] key, byte[] cipher, int usage, AesKeyType aesKeyType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == cipher) { throw new ArgumentNullException("cipher"); } // the cipher has two parts: encrypted(confounder + plain) + hmac byte[] encryptedData = ArrayUtility.SubArray<byte>( cipher, 0, cipher.Length - ConstValue.HMAC_HASH_OUTPUT_SIZE); byte[] hmacData = ArrayUtility.SubArray<byte>( cipher, cipher.Length - ConstValue.HMAC_HASH_OUTPUT_SIZE); // use ke key (the encryption key) to decrypt byte[] ke = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ke, aesKeyType); byte[] initialVector = new byte[ConstValue.AES_BLOCK_SIZE]; CipherTextStealingMode aesCtsCrypto = CryptoUtility.CreateAesCtsCrypto(ke, initialVector); byte[] decryptedData = aesCtsCrypto.DecryptFinal(encryptedData, 0, encryptedData.Length); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(decryptedData); } else { toBeSignedData = decryptedData; } // use ki key (the integrity key) to verify hmac data byte[] ki = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ki, aesKeyType); byte[] expectedHmacData = CryptoUtility.ComputeHmacSha1(ki, toBeSignedData); expectedHmacData = ArrayUtility.SubArray<byte>(expectedHmacData, 0, ConstValue.HMAC_HASH_OUTPUT_SIZE); if (!ArrayUtility.CompareArrays<byte>(hmacData, expectedHmacData)) { throw new FormatException( "Decryption: failed integrity check in hmac checksum."); } // remove confounder data decryptedData = ArrayUtility.SubArray<byte>(decryptedData, ConstValue.AES_BLOCK_SIZE, decryptedData.Length - ConstValue.AES_BLOCK_SIZE); return decryptedData; }
/// <summary> /// RC4-HMAC / RC4-HMAC-EXP decryption /// </summary> /// <param name="key">the secret key</param> /// <param name="cipher">the encrypted cipher data</param> /// <param name="usage">key usage number</param> /// <param name="encryptionType">encryption type</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use decrypted data directly if this parameter is null. /// </param> /// <returns>the decrypted data</returns> public static byte[] Decrypt( byte[] key, byte[] cipher, int usage, EncryptionType encryptionType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == cipher) { throw new ArgumentNullException("cipher"); } // get checksum and encrypted data byte[] checksum = ArrayUtility.SubArray(cipher, 0, ConstValue.MD5_CHECKSUM_SIZE); byte[] encryptedData = ArrayUtility.SubArray(cipher, ConstValue.MD5_CHECKSUM_SIZE); // get salt and hash byte[] salt = GetSalt(usage, encryptionType); byte[] hash = CryptoUtility.ComputeMd5Hmac(key, salt); byte[] hashExp = GetExpHash(hash, encryptionType); // get rc4 decryption key byte[] rc4Key = CryptoUtility.ComputeMd5Hmac(hashExp, checksum); // decrypt ICryptoTransform decryptor = CryptoUtility.CreateRc4Decryptor(rc4Key); byte[] plain = decryptor.TransformFinalBlock(encryptedData, 0, encryptedData.Length); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(plain); } else { toBeSignedData = plain; } // verify checksum byte[] expectedChecksum = CryptoUtility.ComputeMd5Hmac(hash, toBeSignedData); if (!ArrayUtility.CompareArrays(checksum, expectedChecksum)) { throw new FormatException("Decryption: invalid checksum."); } // remove confounder return ArrayUtility.SubArray(plain, ConstValue.CONFOUNDER_SIZE); }
/// <summary> /// RC4-HMAC / RC4-HMAC-EXP encryption /// </summary> /// <param name="key">the secret key</param> /// <param name="plain">the to be encrypted plain data</param> /// <param name="usage">key usage number</param> /// <param name="encryptionType">encryption type</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use plain-text data directly if this parameter is null. /// </param> /// <returns>the encrypted data</returns> public static byte[] Encrypt( byte[] key, byte[] plain, int usage, EncryptionType encryptionType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == plain) { throw new ArgumentNullException("plain"); } // add confounder byte[] confounderData = CryptoUtility.CreateConfounder(ConstValue.CONFOUNDER_SIZE); byte[] plainData = ArrayUtility.ConcatenateArrays(confounderData, plain); // add padding plainData = CryptoUtility.AddPadding(plainData, ConstValue.RC4_BLOCK_SIZE); // get salt and hash byte[] salt = GetSalt(usage, encryptionType); byte[] hash = CryptoUtility.ComputeMd5Hmac(key, salt); byte[] hashExp = GetExpHash(hash, encryptionType); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(plainData); } else { toBeSignedData = plainData; } // get checksum byte[] checksum = CryptoUtility.ComputeMd5Hmac(hash, toBeSignedData); // get rc4 encryption key byte[] rc4Key = CryptoUtility.ComputeMd5Hmac(hashExp, checksum); // encrypt ICryptoTransform encryptor = CryptoUtility.CreateRc4Encryptor(rc4Key); byte[] encryptedData = encryptor.TransformFinalBlock(plainData, 0, plainData.Length); // result = checksum + encryptedData return(ArrayUtility.ConcatenateArrays(checksum, encryptedData)); }
/// <summary> /// DES-CBC-MD5 / DES-CBC-CRC32 decryption /// </summary> /// <param name="key">the secret key</param> /// <param name="cipher">the encrypted cipher data</param> /// <param name="encryptionType">encryption type</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use decrypted data directly if this parameter is null. /// </param> /// <returns>the decrypted data</returns> public static byte[] Decrypt( byte[] key, byte[] cipher, EncryptionType encryptionType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == cipher) { throw new ArgumentNullException("cipher"); } // des-cbc decryption byte[] initialVector = GetInitialVector(key, encryptionType); ICryptoTransform decryptor = CryptoUtility.CreateDesCbcDecryptor(key, initialVector, PaddingMode.None); byte[] decryptedData = decryptor.TransformFinalBlock(cipher, 0, cipher.Length); // get checksum, set checksum field to zeros int checksumSize = GetChecksumSize(encryptionType); byte[] checksum = ArrayUtility.SubArray <byte>(decryptedData, ConstValue.DES_BLOCK_SIZE, checksumSize); Array.Clear(decryptedData, ConstValue.DES_BLOCK_SIZE, checksumSize); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(decryptedData); } else { toBeSignedData = decryptedData; } // verify checksum byte[] expectedChecksum = CalculateChecksum(toBeSignedData, encryptionType); if (!ArrayUtility.CompareArrays <byte>(checksum, expectedChecksum)) { throw new FormatException( "Decryption: inconsistent checksum."); } // remove confounder and checksum decryptedData = ArrayUtility.SubArray <byte>(decryptedData, ConstValue.DES_BLOCK_SIZE + checksumSize); return(decryptedData); }
/// <summary> /// DES-CBC-MD5 / DES-CBC-CRC32 encryption /// [RFC 3961, Section 6.2, DES-Based Encryption and Checksum Types] /// "One generates a random confounder of one block, placing it in 'confounder'; /// zeros out the 'checksum' field (of length appropriate to exactly hold the checksum /// to be computed); adds the necessary padding; calculates the appropriate checksum /// over the whole sequence, placing the result in 'checksum'; and then encrypts /// using the specified encryption type and the appropriate key." /// </summary> /// <param name="key">the secret key</param> /// <param name="plain">the to be encrypted plain data</param> /// <param name="encryptionType">encryption type</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use plain-text data directly if this parameter is null. /// </param> /// <returns>the encrypted data</returns> public static byte[] Encrypt( byte[] key, byte[] plain, EncryptionType encryptionType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == plain) { throw new ArgumentNullException("plain"); } // toBePaddedData = confounderData + emptyChecksumData + plainData int checksumSize = GetChecksumSize(encryptionType); byte[] toBeEncryptedData = ArrayUtility.ConcatenateArrays( CryptoUtility.CreateConfounder(ConstValue.DES_BLOCK_SIZE), new byte[checksumSize], plain); // add padding byte[] paddedData = CryptoUtility.AddPadding(toBeEncryptedData, ConstValue.DES_BLOCK_SIZE); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(paddedData); } else { toBeSignedData = paddedData; } // replace the empty checksum with the caculated checksum byte[] checksum = CalculateChecksum(toBeSignedData, encryptionType); Array.Copy(checksum, 0, paddedData, ConstValue.DES_BLOCK_SIZE, checksum.Length); // des-cbc encryption byte[] initialVector = GetInitialVector(key, encryptionType); ICryptoTransform encryptor = CryptoUtility.CreateDesCbcEncryptor(key, initialVector, PaddingMode.None); return(encryptor.TransformFinalBlock(paddedData, 0, paddedData.Length)); }
/// <summary> /// Encrypt in aes128-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 /// </summary> /// <param name="key">key data</param> /// <param name="plain">plain data to be encrypted</param> /// <param name="usage">key usage number</param> /// <param name="aesKeyType">aes key type (128bit/256bit)</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use plain-text data directly if this parameter is null. /// </param> /// <returns>the encrypted data</returns> public static byte[] Encrypt( byte[] key, byte[] plain, int usage, AesKeyType aesKeyType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == plain) { throw new ArgumentNullException("plain"); } // add confounder data byte[] plainData = ArrayUtility.ConcatenateArrays( CryptoUtility.CreateConfounder(ConstValue.AES_BLOCK_SIZE), plain); // use ke key (the encryption key) to encrypt the plain data byte[] ke = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ke, aesKeyType); byte[] initialVector = new byte[ConstValue.AES_BLOCK_SIZE]; CipherTextStealingMode aesCtsCrypto = CryptoUtility.CreateAesCtsCrypto(ke, initialVector); byte[] encryptedData = aesCtsCrypto.EncryptFinal(plainData, 0, plainData.Length); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(plainData); } else { toBeSignedData = plainData; } // use ki key (the integrity key) to generate checksum byte[] ki = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ki, aesKeyType); byte[] hmacData = CryptoUtility.ComputeHmacSha1(ki, toBeSignedData); hmacData = ArrayUtility.SubArray <byte>(hmacData, 0, ConstValue.HMAC_HASH_OUTPUT_SIZE); // result: encryptedData + hmacData return(ArrayUtility.ConcatenateArrays(encryptedData, hmacData)); }
/// <summary> /// RC4-HMAC / RC4-HMAC-EXP encryption /// </summary> /// <param name="key">the secret key</param> /// <param name="plain">the to be encrypted plain data</param> /// <param name="usage">key usage number</param> /// <param name="encryptionType">encryption type</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use plain-text data directly if this parameter is null. /// </param> /// <returns>the encrypted data</returns> public static byte[] Encrypt( byte[] key, byte[] plain, int usage, EncryptionType encryptionType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == plain) { throw new ArgumentNullException("plain"); } // add confounder byte[] confounderData = CryptoUtility.CreateConfounder(ConstValue.CONFOUNDER_SIZE); byte[] plainData = ArrayUtility.ConcatenateArrays(confounderData, plain); // add padding plainData = CryptoUtility.AddPadding(plainData, ConstValue.RC4_BLOCK_SIZE); // get salt and hash byte[] salt = GetSalt(usage, encryptionType); byte[] hash = CryptoUtility.ComputeMd5Hmac(key, salt); byte[] hashExp = GetExpHash(hash, encryptionType); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(plainData); } else { toBeSignedData = plainData; } // get checksum byte[] checksum = CryptoUtility.ComputeMd5Hmac(hash, toBeSignedData); // get rc4 encryption key byte[] rc4Key = CryptoUtility.ComputeMd5Hmac(hashExp, checksum); // encrypt ICryptoTransform encryptor = CryptoUtility.CreateRc4Encryptor(rc4Key); byte[] encryptedData = encryptor.TransformFinalBlock(plainData, 0, plainData.Length); // result = checksum + encryptedData return ArrayUtility.ConcatenateArrays(checksum, encryptedData); }
/// <summary> /// Decrypt the cipher text with the session key. The usage indicated /// in section 7 of RFC4210 and section 3 of RFC4757 is used to derive key /// from the session key. /// </summary> /// <param name="type">The decryption type selected.</param> /// <param name="sessionKey">An session key used to decrypt and it can be obtained /// from the KDC's response. This key size should be equal to the symmetric algorithm /// key size. This argument can be null. If it is null, null will be returned.</param> /// <param name="cipherData">The text to be decrypted. This argument can be null. /// If it is null, null will be returned.</param> /// <param name="usage">A 32 bits integer used to derive the key.</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use decrypted data directly if this parameter is null. /// </param> /// <returns>The plain text.</returns> internal static byte[] Decrypt(EncryptionType type, byte[] sessionKey, byte[] cipherData, int usage, GetToBeSignedDataFunc getToBeSignedDateCallback) { switch (type) { case EncryptionType.AES128_CTS_HMAC_SHA1_96: return(AesCtsHmacSha1Crypto.Decrypt(sessionKey, cipherData, usage, AesKeyType.Aes128BitsKey, getToBeSignedDateCallback)); case EncryptionType.AES256_CTS_HMAC_SHA1_96: return(AesCtsHmacSha1Crypto.Decrypt(sessionKey, cipherData, usage, AesKeyType.Aes256BitsKey, getToBeSignedDateCallback)); case EncryptionType.DES_CBC_CRC: return(DesCbcCrypto.Decrypt(sessionKey, cipherData, EncryptionType.DES_CBC_CRC, getToBeSignedDateCallback)); case EncryptionType.DES_CBC_MD5: return(DesCbcCrypto.Decrypt(sessionKey, cipherData, EncryptionType.DES_CBC_MD5, getToBeSignedDateCallback)); case EncryptionType.RC4_HMAC: return(Rc4HmacCrypto.Decrypt(sessionKey, cipherData, usage, EncryptionType.RC4_HMAC, getToBeSignedDateCallback)); case EncryptionType.RC4_HMAC_EXP: return(Rc4HmacCrypto.Decrypt(sessionKey, cipherData, usage, EncryptionType.RC4_HMAC_EXP, getToBeSignedDateCallback)); default: throw new ArgumentException("Unsupported encryption type."); } }
/// <summary> /// Encrypt in aes128-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 /// </summary> /// <param name="key">key data</param> /// <param name="plain">plain data to be encrypted</param> /// <param name="usage">key usage number</param> /// <param name="aesKeyType">aes key type (128bit/256bit)</param> /// <param name="getToBeSignedDateCallback"> /// A callback to get to-be-signed data. /// The method will use plain-text data directly if this parameter is null. /// </param> /// <returns>the encrypted data</returns> public static byte[] Encrypt( byte[] key, byte[] plain, int usage, AesKeyType aesKeyType, GetToBeSignedDataFunc getToBeSignedDateCallback) { // check inputs if (null == key) { throw new ArgumentNullException("key"); } if (null == plain) { throw new ArgumentNullException("plain"); } // add confounder data byte[] plainData = ArrayUtility.ConcatenateArrays( CryptoUtility.CreateConfounder(ConstValue.AES_BLOCK_SIZE), plain); // use ke key (the encryption key) to encrypt the plain data byte[] ke = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ke, aesKeyType); byte[] initialVector = new byte[ConstValue.AES_BLOCK_SIZE]; CipherTextStealingMode aesCtsCrypto = CryptoUtility.CreateAesCtsCrypto(ke, initialVector); byte[] encryptedData = aesCtsCrypto.EncryptFinal(plainData, 0, plainData.Length); byte[] toBeSignedData; if (getToBeSignedDateCallback != null) { toBeSignedData = getToBeSignedDateCallback(plainData); } else { toBeSignedData = plainData; } // use ki key (the integrity key) to generate checksum byte[] ki = AesKey.MakeDerivedKey(key, usage, DerivedKeyType.Ki, aesKeyType); byte[] hmacData = CryptoUtility.ComputeHmacSha1(ki, toBeSignedData); hmacData = ArrayUtility.SubArray<byte>(hmacData, 0, ConstValue.HMAC_HASH_OUTPUT_SIZE); // result: encryptedData + hmacData return ArrayUtility.ConcatenateArrays(encryptedData, hmacData); }