Example #1
0
        private static unsafe byte[] CreateSessionData(byte[] sessionSecret, SrpUserCredential user)
        {
            byte[] initializationVector = SaltGenerator.Create(16);
            int    len      = sessionSecret.Length;
            int    blockLen = (len + 15) & ~15; //Add 15, then round down. (Effectively rounds up to the nearest 128 bit boundary).

            byte[] dataToEncrypt = new byte[blockLen];
            sessionSecret.CopyTo(dataToEncrypt, 0);

            //fill the remainder of the block with random bits
            if (len != blockLen)
            {
                SaltGenerator.Create(blockLen - len).CopyTo(dataToEncrypt, len);
            }

            byte[] ticket = new byte[1 + 16 + 8 + 16 + 2 + blockLen + 32];

            using (Aes aes = Cipher.CreateAes())
            {
                aes.Key     = user.ServerEncryptionkey;
                aes.IV      = initializationVector;
                aes.Mode    = CipherMode.CBC;
                aes.Padding = PaddingMode.None;
                ICryptoTransform decrypt       = aes.CreateEncryptor();
                byte[]           encryptedData = decrypt.TransformFinalBlock(dataToEncrypt, 0, dataToEncrypt.Length);

                fixed(byte *lp = ticket)
                {
                    using (BinaryStreamPointerWrapper stream = new BinaryStreamPointerWrapper(lp, ticket.Length))
                    {
                        stream.Write((byte)1);
                        stream.Write((short)len);
                        stream.Write(user.ServerKeyName);
                        stream.Write(DateTime.UtcNow);
                        stream.Write(initializationVector);
                        stream.Write(encryptedData);
                        stream.Write(HMAC <Sha256Digest> .Compute(user.ServerHMACKey, ticket, 0, ticket.Length - 32));
                    }
                }
            }
            return(ticket);
        }
Example #2
0
 public byte[] ComputeClientSignature(byte[] authMessage)
 {
     byte[] result = new byte[m_clientSignature.GetMacSize()];
     if (Monitor.TryEnter(m_clientSignature))
     {
         try
         {
             m_clientSignature.BlockUpdate(authMessage, 0, authMessage.Length);
             m_clientSignature.DoFinal(result, 0);
         }
         finally
         {
             Monitor.Exit(m_clientSignature);
         }
     }
     else
     {
         return(HMAC.Compute(Scram.CreateDigest(HashMethod), StoredKey, authMessage));
     }
     return(result);
 }
Example #3
0
        /// <summary>
        /// Attempts to load the session resume ticket.
        /// </summary>
        /// <param name="ticket">The serialized data for the key</param>
        /// <param name="user">The user's credentials so the proper encryption key can be used</param>
        /// <param name="sessionSecret">the session secret decoded if successful. null otherwise</param>
        /// <returns>
        /// True if the ticket is authentic
        /// </returns>
        unsafe static bool TryLoadTicket(byte[] ticket, SrpUserCredential user, out byte[] sessionSecret)
        {
            sessionSecret = null;

            //Ticket Structure:
            //  byte      TicketVersion = 1
            //  int16     Username Length
            //  int16     Session Key Length
            //  Guid      ServerKeyName
            //  DateTime  AuthenticationTime
            //  byte[16]  IV
            //  byte[]    Username
            //  byte[]    Encrypted Session Data (Round [Session Key Length] up to a 128 bit number to get the length of the encrypted data)
            //  byte[32]  HMAC (Sha2-256)

            if (ticket == null || ticket.Length < 1 + 16 + 8 + 16 + 2 + 32)
                return(false);

            fixed(byte *lp = ticket)
            {
                var stream = new BinaryStreamPointerWrapper(lp, ticket.Length);

                if (stream.ReadUInt8() != 1)
                {
                    return(false);
                }

                int sessionKeyLength = stream.ReadUInt16();

                if (sessionKeyLength < 0 || sessionKeyLength > 1024) //Max session key is 8192 SRP.
                {
                    return(false);
                }

                int encryptedDataLength = (sessionKeyLength + 15) & ~15; //Add 15, then round down. (Effecitvely rounds up to the nearest 128 bit boundary).

                if (ticket.Length != 1 + 2 + 16 + 8 + 16 + encryptedDataLength + 32)
                {
                    return(false);
                }

                if (!user.ServerKeyName.SecureEquals(stream.ReadGuid()))
                {
                    return(false);
                }

                long maxTicketAge = DateTime.UtcNow.Ticks + TimeSpan.TicksPerMinute * 10; //Allows for time syncing issues that might move the server's time back by a few minutes.
                long minTicketAge = maxTicketAge - TimeSpan.TicksPerDay;

                long issueTime = stream.ReadInt64();

                if (issueTime < minTicketAge || issueTime > maxTicketAge)
                {
                    return(false);
                }

                byte[] initializationVector = stream.ReadBytes(16);

                //Verify the signature if everything else looks good.
                //This is last because it is the most computationally complex.
                //This limits denial of service attackes.
                byte[] hmac = HMAC <Sha256Digest> .Compute(user.ServerHMACKey, ticket, 0, ticket.Length - 32);

                if (!hmac.SecureEquals(ticket, ticket.Length - 32, 32))
                {
                    return(false);
                }

                byte[] encryptedData = stream.ReadBytes(encryptedDataLength);
                var    aes           = new RijndaelManaged();

                aes.Key     = user.ServerEncryptionkey;
                aes.IV      = initializationVector;
                aes.Mode    = CipherMode.CBC;
                aes.Padding = PaddingMode.None;
                var decrypt = aes.CreateDecryptor();

                sessionSecret = decrypt.TransformFinalBlock(encryptedData, 0, encryptedData.Length);

                return(true);
            }
        }
Example #4
0
 internal static byte[] ComputeHMAC(HashMethod hashMethod, byte[] key, byte[] message)
 {
     return(HMAC.Compute(CreateDigest(hashMethod), key, message));
 }