/// <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>
 /// <returns>the decrypted data</returns>
 public static byte[] Decrypt(
     byte[] key,
     byte[] cipher,
     int usage,
     AesKeyType aesKeyType)
 {
     return Decrypt(key, cipher, usage, aesKeyType, null);
 }
        /// <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>
        /// Get Hmac-Sha1-Aes Checksum
        /// </summary>
        /// <param name="key">the key</param>
        /// <param name="input">input data</param>
        /// <param name="usage">usage number</param>
        /// <param name="aesKeyType">aes key type which decides key size</param>
        /// <returns>the calculated checksum</returns>
        public static byte[] GetMic(
            byte[] key,
            byte[] input,
            int usage,
            AesKeyType aesKeyType)
        {
            // make the kc key from aes key generation
            byte[] kcKey = AesKey.MakeDerivedKey(
                key, usage, DerivedKeyType.Kc, aesKeyType);

            // get mic from kc key and input
            byte[] hash = CryptoUtility.ComputeHmacSha1(kcKey, input);
            return ArrayUtility.SubArray(hash, 0, ConstValue.HMAC_HASH_OUTPUT_SIZE);
        }
Exemplo n.º 4
0
        /// <summary>
        /// DR is the random-octet generation function described in RFC 3961
        /// [RFC 3961 section 5.1 A Key Derivation Function]
        /// </summary>
        /// <param name="baseKey">the base key which is to be derived from</param>
        /// <param name="wellKnownConstant">the "well-known constant"</param>
        /// <param name="aesKeyType">AES key type which decides key size</param>
        /// <returns>the pseudorandom octets</returns>
        private static byte[] DR(
            byte[] baseKey,
            byte[] wellKnownConstant,
            AesKeyType aesKeyType)
        {
            // to be encrypted data
            byte[] toBeEncrypted = new byte[wellKnownConstant.Length];
            wellKnownConstant.CopyTo(toBeEncrypted, 0);

            // n-fold the "well-known constant" if needed
            if (wellKnownConstant.Length != ConstValue.AES_BLOCK_SIZE)
            {
                toBeEncrypted = NFold(wellKnownConstant, ConstValue.AES_BLOCK_SIZE * ConstValue.BYTE_SIZE);
            }

            // AES key size
            uint aesKeySize = (uint)aesKeyType / ConstValue.BYTE_SIZE;

            // initialize key array
            byte[] rawkey = new byte[aesKeySize];

            // count means the total number of bytes has been copy to the rawkey.
            // length means how length of bytes should be copy to the rawkey array.
            uint count = 0;
            uint length = 0;

            // The initialCipherVector should be all zeros.
            byte[] initialCipherVector = new byte[ConstValue.AES_BLOCK_SIZE];

            // AES-CTS encryptor
            CipherTextStealingMode aesCtsCrypto = CryptoUtility.CreateAesCtsCrypto(baseKey, initialCipherVector);
            while (count < aesKeySize)
            {
                byte[] cipherBlock = aesCtsCrypto.EncryptFinal(toBeEncrypted, 0, toBeEncrypted.Length);
                length = (aesKeySize - count <= cipherBlock.Length ? (aesKeySize - count) : Convert.ToUInt32(cipherBlock.Length));
                Array.Copy(cipherBlock, 0, rawkey, count, length);
                count += length;
                toBeEncrypted = cipherBlock;
            }
            return rawkey;
        }
Exemplo n.º 5
0
        /// <summary>
        /// Generate an encryption key from password and salt
        /// [RFC 3962 Section 4 Key Generation from Pass Phrases or Random Data]
        /// (The pseudorandom function used by PBKDF2 will be a SHA-1 HMAC of 
        /// the passphrase and salt, as described in Appendix B.1 to PKCS#5)
        /// </summary>
        /// <param name="password">password</param>
        /// <param name="salt">salt</param>
        /// <param name="iterationCount">interation count</param>
        /// <param name="keyType">AES key type which decides key size</param>
        /// <returns>the encrypted key in bytes</returns>
        internal static byte[] MakeStringToKey(
            string password,
            string salt,
            uint iterationCount,
            AesKeyType keyType)
        {
            if (null == password)
            {
                throw new ArgumentNullException("password");
            }
            if (null == salt)
            {
                throw new ArgumentNullException("salt");
            }

            byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
            byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
            int keySize = (int)keyType / ConstValue.BYTE_SIZE;

            // generate the intermediate key
            Rfc2898DeriveBytes PBKDF2 = new Rfc2898DeriveBytes(passwordBytes, saltBytes, (int)iterationCount);
            byte[] intermediateKey = PBKDF2.GetBytes(keySize);
            intermediateKey = RandomToKey(intermediateKey);

            // generate the final key
            return DK(intermediateKey, KERBEROS_CONSTANT, keyType);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Generate a derived key from base key
        /// [RFC 3961 Section 5.1 A Key Derivation Function]
        /// </summary>
        /// <param name="baseKey">the base key</param>
        /// <param name="usage">key usage</param>
        /// <param name="derivedKeyType">the derived key type</param>
        /// <param name="aesKeyType">AES key type which decides key size</param>
        /// <returns>the derived key in bytes</returns>
        internal static byte[] MakeDerivedKey(
            byte[] baseKey,
            int usage,
            DerivedKeyType derivedKeyType,
            AesKeyType aesKeyType)
        {
            if (null == baseKey)
            {
                throw new ArgumentNullException("baseKey");
            }

            // generate the well-known constant
            byte[] wellKnownConstant = GetWellKnownConstant(usage, derivedKeyType);

            // generate the derived key
            return DK(baseKey, wellKnownConstant, aesKeyType);
        }
Exemplo n.º 7
0
        /// <summary>
        /// DK is the key-derivation function described in RFC 3961
        /// [RFC 3961 section 5.1 A Key Derivation Function]
        /// </summary>
        /// <param name="baseKey">the base key</param>
        /// <param name="wellKnownConstant">the "well-known constant"</param>
        /// <param name="aesKeyType">AES key type which decides key size</param>
        /// <returns>the derived key in bytes</returns>
        public static byte[] DK(
            byte[] baseKey,
            byte[] wellKnownConstant,
            AesKeyType aesKeyType)
        {
            // caculate DR value
            byte[] drBytes = DR(baseKey, wellKnownConstant, aesKeyType);

            // caculate Random
            return RandomToKey(drBytes);
        }
        /// <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>
 /// 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>
 /// <returns>the encrypted data</returns>
 public static byte[] Encrypt(
     byte[] key,
     byte[] plain,
     int usage,
     AesKeyType aesKeyType)
 {
     return Encrypt(key, plain, usage, aesKeyType, null);
 }