Beispiel #1
0
        private bool DecryptSecret(byte[] yubiResp, ChallengeInfo inf, out byte[] secret)
        {
            secret = new byte[keyLenBytes];

            if (inf.IV == null)
            {
                return(false);
            }
            if (inf.Verification == null)
            {
                return(false);
            }

            //use the response to decrypt the secret
            SHA256 sha = SHA256Managed.Create();

            byte[] key = sha.ComputeHash(yubiResp); // get a 256 bit key from the 160 bit hmac response

            StandardAesEngine aes = new StandardAesEngine();

            using (MemoryStream msDecrypt = new MemoryStream(inf.EncryptedSecret))
            {
                using (CryptoStream csDecrypt = (CryptoStream)aes.DecryptStream(msDecrypt, key, inf.IV))
                {
                    csDecrypt.Read(secret, 0, secret.Length);
                    csDecrypt.Close();
                }
                msDecrypt.Close();
            }

            byte[] secretHash = sha.ComputeHash(secret);
            for (int i = 0; i < secretHash.Length; i++)
            {
                if (secretHash[i] != inf.Verification[i])
                {
                    //wrong response
                    Array.Clear(secret, 0, secret.Length);
                    return(false);
                }
            }

            //return the secret
            sha.Clear();
            return(true);
        }
Beispiel #2
0
        /// <summary>
        /// A method for generating encrypted ChallengeInfo to be saved. For security, this method should
        /// be called every time you get a successful challenge-response pair from the Yubikey. Failure to
        /// do so will permit password re-use attacks.
        /// </summary>
        /// <param name="secret">The un-encrypted secret</param>
        /// <returns>A fully populated ChallengeInfo object ready to be saved</returns>
        public ChallengeInfo Encrypt(byte[] secret)
        {
            //generate a random challenge for use next time
            byte[] challenge = GenerateChallenge();

            //generate the expected HMAC-SHA1 response for the challenge based on the secret
            byte[] resp = GenerateResponse(challenge, secret);

            //use the response to encrypt the secret
            SHA256 sha = SHA256Managed.Create();

            byte[] key        = sha.ComputeHash(resp); // get a 256 bit key from the 160 bit hmac response
            byte[] secretHash = sha.ComputeHash(secret);

            StandardAesEngine aes           = new StandardAesEngine();
            const uint        aesIVLenBytes = 16;

            byte[] IV = CryptoRandom.Instance.GetRandomBytes(aesIVLenBytes);
            byte[] encrypted;

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = (CryptoStream)aes.EncryptStream(msEncrypt, key, IV))
                {
                    csEncrypt.Write(secret, 0, secret.Length);
                    csEncrypt.Close();
                }

                encrypted = msEncrypt.ToArray();
                msEncrypt.Close();
            }

            ChallengeInfo inf = new ChallengeInfo(encrypted, IV, challenge, secretHash, LT64);

            sha.Clear();

            return(inf);
        }
Beispiel #3
0
        public static ChallengeInfo Load(IOConnectionInfo ioc)
        {
            Stream sIn = null;
            ChallengeInfo inf = new ChallengeInfo();
            try
            {
                sIn = App.Kp2a.GetOtpAuxFileStorage(ioc).OpenFileForRead(ioc);

                XmlSerializer xs = new XmlSerializer(typeof (ChallengeInfo));
                if (!inf.LoadStream(sIn)) return null;
            }
            catch (Exception e)
            {
                Kp2aLog.Log(e.ToString());
            }
            finally
            {
                if(sIn != null) sIn.Close();
            }

            return inf;
        }
Beispiel #4
0
        /// <summary>
        /// A method for generating encrypted ChallengeInfo to be saved. For security, this method should
        /// be called every time you get a successful challenge-response pair from the Yubikey. Failure to
        /// do so will permit password re-use attacks. 
        /// </summary>
        /// <param name="secret">The un-encrypted secret</param>
        /// <returns>A fully populated ChallengeInfo object ready to be saved</returns>
        public ChallengeInfo Encrypt(byte[] secret)
        {
            //generate a random challenge for use next time
            byte[] challenge = GenerateChallenge();

            //generate the expected HMAC-SHA1 response for the challenge based on the secret
            byte[] resp = GenerateResponse(challenge, secret);

            //use the response to encrypt the secret
            SHA256 sha = SHA256Managed.Create();
            byte[] key = sha.ComputeHash(resp); // get a 256 bit key from the 160 bit hmac response
            byte[] secretHash = sha.ComputeHash(secret);

            StandardAesEngine aes = new StandardAesEngine();
            const uint aesIVLenBytes = 16	;
            byte[] IV = CryptoRandom.Instance.GetRandomBytes(aesIVLenBytes);
            byte[] encrypted;

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = (CryptoStream)aes.EncryptStream(msEncrypt, key, IV))
                {
                    csEncrypt.Write(secret, 0, secret.Length);
                    csEncrypt.Close();
                }

                encrypted = msEncrypt.ToArray();
                msEncrypt.Close();
            }

            ChallengeInfo inf = new ChallengeInfo (encrypted, IV, challenge, secretHash, LT64);

            sha.Clear();

            return inf;
        }
Beispiel #5
0
        private bool DecryptSecret(byte[] yubiResp, ChallengeInfo inf, out byte[] secret)
        {
            secret = new byte[keyLenBytes];

            if (inf.IV == null) return false;
            if (inf.Verification == null) return false;

            //use the response to decrypt the secret
            SHA256 sha = SHA256Managed.Create();
            byte[] key = sha.ComputeHash(yubiResp); // get a 256 bit key from the 160 bit hmac response

            StandardAesEngine aes = new StandardAesEngine();

            using (MemoryStream msDecrypt = new MemoryStream(inf.EncryptedSecret))
            {
                using (CryptoStream csDecrypt = (CryptoStream)aes.DecryptStream(msDecrypt, key, inf.IV))
                {
                    csDecrypt.Read(secret, 0, secret.Length);
                    csDecrypt.Close();
                }
                msDecrypt.Close();
            }

            byte[] secretHash = sha.ComputeHash(secret);
            for (int i = 0; i < secretHash.Length; i++)
            {
                if (secretHash[i] != inf.Verification[i])
                {
                    //wrong response
                    Array.Clear(secret, 0, secret.Length);
                    return false;
                }
            }

            //return the secret
            sha.Clear();
            return true;
        }
Beispiel #6
0
        /// <summary>
        /// The primary access point for challenge-response utility functions. Accepts a pre-populated ChallengeInfo object
        /// containing at least the IV, EncryptedSecret, and Verification fields. These fields are combined with the Yubikey response
        /// to decrypt and verify the secret. 
        /// </summary>
        /// <param name="inf">A pre-populated object containing minimally the IV, EncryptedSecret and Verification fields. 
        ///                   This should be populated from the database.xml auxilliary file</param>
        /// <param name="resp"	>The Yubikey's response to the issued challenge</param>
        /// <returns>The common secret, used as a composite key to encrypt a Keepass database</returns>
        public byte[] GetSecret(ChallengeInfo inf, byte[] resp)
        {
            if (resp.Length != responseLenBytes)
                return null;
            if (inf == null)
                return null;
            if (inf.Challenge == null ||
                inf.Verification == null)
                return null;

            LT64 = inf.LT64;

            byte[] secret;

            if (DecryptSecret(resp, inf, out secret))
            {
                return secret;
            }
            else
            {
                return null;
            }
        }