как расшифровать сообщение клиента протокола Radius peap о завершении рукопожатия

я использую набор шифров TLS_RSA_WITH_3DES_EDE_CBC_SHA для сервера RADIUS, получил зашифрованное сообщение рукопожатия (40 байт) сразу после ChangeCipherSpec от клиента, я пытался использовать 3des с режимом cbc для расшифровки этих байтов, но с исключением (неверные данные), попытался найти peap tls v1.0 на https://tools.ietf.org/html/rfc2246 но не нашел подробной информации о шифровании/дешифровании рукопожатия. любая помощь будет замечательной, большое спасибо!!

вот код, который я использовал для вычисления главного секрета и ключевых материалов.

    public static byte[] ComputeMasterSecret(byte[] pre_master_secret, byte[] client_random, byte[] server_random)
    {
        byte[] label = Encoding.ASCII.GetBytes("master secret");

        var seed = new List<byte>();
        seed.AddRange(client_random);
        seed.AddRange(server_random);

        var master_secret = PRF(pre_master_secret, label, seed.ToArray(), 48);

        return master_secret;
    }

    public static KeyMaterial ComputeKeys(byte[] master_secret, byte[] client_random, byte[] server_random)
    {
        /*
         * The cipher spec which is defined in this document which requires
        the most material is 3DES_EDE_CBC_SHA: it requires 2 x 24 byte
        keys, 2 x 20 byte MAC secrets, and 2 x 8 byte IVs, for a total of

        104 bytes of key material.
        */


        byte[] label = Encoding.ASCII.GetBytes("key expansion");

        var seed = new List<byte>();
        seed.AddRange(client_random);
        seed.AddRange(server_random);

        byte[] key_material = PRF(master_secret, label, seed.ToArray(), 104);  //need 104 for TLS_RSA_WITH_3DES_EDE_CBC_SHA cipher suite


        var km = new KeyMaterial();
        int idx = 0;
        km.ClientWriteMACSecret = Utils.CopyArray(key_material, idx, 20);
        idx += 20;

        km.ServerWriteMACSecret = Utils.CopyArray(key_material, idx, 20);
        idx += 20;

        km.ClientWriteKey = Utils.CopyArray(key_material, idx, 24);
        idx += 24;

        km.ServerWriteKey = Utils.CopyArray(key_material, idx, 24);
        idx += 24;

        km.ClientWriteIV = Utils.CopyArray(key_material, idx, 8);
        idx += 8;

        km.ServerWriteIV = Utils.CopyArray(key_material, idx, 8);

        return km;
    }

    public static byte[] PRF(byte[] secret, byte[] label, byte[] seed, int outputLength)
    {
        List<byte> s1 = new List<byte>();
        List<byte> s2 = new List<byte>();

        int size = (int)Math.Ceiling((double)secret.Length / 2);

        for(int i=0;i < size; i++)
        {
            s1.Add(secret[i]);
            s2.Insert(0, secret[secret.Length - i - 1]);
        }

        var tbc = new List<byte>();
        tbc.AddRange(label);
        tbc.AddRange(seed);

        var md5Result = MD5Hash(s1.ToArray(), tbc.ToArray(), outputLength);

        var sha1Result = SHA1Hash(s2.ToArray(), tbc.ToArray(), outputLength);


        var result = new List<byte>();
        for (int i = 0; i < outputLength; i++)
            result.Add((byte)(md5Result[i] ^ sha1Result[i]));

        return result.ToArray();
    }

    /// <summary>
    /// P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
    ///                        HMAC_hash(secret, A(2) + seed) +
    ///                        HMAC_hash(secret, A(3) + seed) + ...

    /// Where + indicates concatenation.

    ///  A() is defined as:
    /// A(0) = seed
    /// A(i) = HMAC_hash(secret, A(i-1))
    /// </summary>
    /// <param name="secret"></param>
    /// <param name="seed"></param>
    /// <param name="iterations"></param>
    /// <returns></returns>
    private static byte[] MD5Hash(byte[] secret, byte[] seed, int outputLength)
    {
        int iterations = (int)Math.Ceiling((double)outputLength / 16);

        HMACMD5 HMD5 = new HMACMD5(secret);

        var result = new List<byte>();
        byte[] A = null;
        for (int i = 0; i <= iterations; i++)
            if (A == null)
                A = seed;
            else
            {
                A = HMD5.ComputeHash(A);

                var tBuff = new List<byte>();
                tBuff.AddRange(A);
                tBuff.AddRange(seed);

                var tb = HMD5.ComputeHash(tBuff.ToArray());

                result.AddRange(tb);
            }

        return result.ToArray();
    }

    private static byte[] SHA1Hash(byte[] secret, byte[] seed, int outputLength)
    {
        int iterations = (int)Math.Ceiling((double)outputLength / 20);

        HMACSHA1 HSHA1 = new HMACSHA1(secret);
        var result = new List<byte>();
        byte[] A = null;

        for (int i = 0; i <= iterations; i++)
            if (A == null)
                A = seed;
            else
            {
                A = HSHA1.ComputeHash(A);

                var tBuff = new List<byte>();
                tBuff.AddRange(A);
                tBuff.AddRange(seed);

                var tb = HSHA1.ComputeHash(tBuff.ToArray());

                result.AddRange(tb);
            }

        return result.ToArray();
    }

person YanXi    schedule 26.12.2017    source источник


Ответы (1)


Аутентификация/шифрование и дешифрование/проверка записи, содержащей сообщение о завершенном рукопожатии, такие же, как и для всех других записей в SSL/TLS, за исключением того, что она является первой после CCS.

Сначала (во время рукопожатия) предварительный секрет из обмена ключами используется для получения главного секрета и нескольких рабочих ключей и IV, в зависимости от пакета. Это немного зависит от версии протокола; для TLS1.0 см. rfc2246, разделы 8.1.1 (для простого RSA), 6.3 (для всех обменов ключами) и 5.

При использовании шифра GenericBlock (CBC), который является единственным вариантом помимо RC4 в TLS1.0 и 1.1, используется фрагментация 6.2.3.1 (не требуется для этой записи) 6.2.3.2 дополнительное сжатие (обычно не используется в настоящее время из-за атаки, такие как CRIME, и в любом случае довольно бесполезны для трафика EAP) и 6.2.3.2.

В частности, сначала добавляется HMAC (для этого набора HMAC-SHA1), затем заполнение, затем результат шифруется с использованием шифра данных (3DES-CBC) с IV, который для первой записи (которая Finished) исходит из ключа шаг вывода выше и для последующих записей происходит от последнего блока предыдущей записи. (Последний недостаток — это недостаток, о котором впервые сообщил Rogaway и которым воспользовался BEAST.)

Расшифровка и верификация очевидным образом обращают этот процесс вспять. Примечание. В rfc2246 не указано, что получатель должен проверять все байты заполнения, но это, очевидно, предназначено; rfc4346 (1.1) указывает это без изменения содержимого. (rfc4346 действительно изменяет обработку IV, чтобы исправить недостаток Rogaway. В SSLv3 указано случайное заполнение, за исключением последнего байта длины, поэтому его нельзя проверить; это POODLE недостаток.)

Некоторые библиотеки/API, предоставляющие режим CBC для блочных шифров (включая 3DES) для произвольных данных, по умолчанию используют заполнение PKCS5/7. Заполнение, используемое TLS, похоже на заполнение PKCS5/7, но НЕ совместимо с ним, поэтому при использовании этих библиотек вам, возможно, придется самостоятельно обрабатывать заполнение и распаковку, следуя инструкциям в 6.2.3.2 — или коду в любой из примерно дюжины реализаций TLS с открытым исходным кодом.

person dave_thompson_085    schedule 27.12.2017
comment
спасибо за полезную информацию, я рассчитал мастер-ключ и ключевые материалы с помощью вышеуказанных функций, и я использую C #, я проверил класс TripleDES из точки сети, совместимый с PCKS7. поскольку TLS не совместим с PKCS5/7, это означает, что после того, как я обработаю заполнение и распаковку, я смогу расшифровать эти 40 байтов? - person YanXi; 28.12.2017
comment
@YanXi: Я ожидаю этого, хотя лично у меня нет опыта работы с dotNET. - person dave_thompson_085; 28.12.2017
comment
еще раз спасибо, заполнение должно быть выполнено до шифрования процесса данных, не так ли? так разве я не могу расшифровать данные, ничего не делая? если после процесса шифрования необходимо выполнить еще одно заполнение, есть ли дополнительная информация о том, как tls 1.0 заполняет и распаковывает с помощью 3DES-CBC? - person YanXi; 28.12.2017
comment
@YanXi: да, заполнение TLS выполняется перед (незаполненным) шифрованием CBC (но после HMAC) и распаковкой после дешифрования (но перед HMAC) - person dave_thompson_085; 29.12.2017
comment
спасибо, тогда я должен быть в состоянии расшифровать данные без каких-либо дополнений или распаковок, но по какой-то причине я не мог расшифровать данные, говоря о неверных данных, я ничего не делал с зашифрованными данными, просто попробуйте расшифровать данные из данных слоя записи. - person YanXi; 29.12.2017
comment
@YanXi: тогда что-то не так, потому что любой зашифрованный текст, кратный размеру блока, действителен для 3DES-CBC без распаковки; только с распаковкой можно обнаружить (много) плохих данных на криптоуровне. Я предлагаю вам сравнить с другой реализацией; если нет другого, который вы можете легко вызвать в Windows, вы можете получить автономный OpenSSL с slproweb.com/products /Win32OpenSSL.html и используйте enc -d -des-ede3-cbc -K hex -iv hex для каждой страницы руководства (обратите внимание на верхний -K, а не на нижний -k) с данными в файлах или каналах. - person dave_thompson_085; 29.12.2017
comment
еще раз спасибо, я узнал, что класс Triple des из .net фиксирован только до 64 блоков, нет возможности изменить размер блока. и AES из .net тоже фиксируется на 128, странно, но с шифрованием aes я могу расшифровать данные без исключения, но не видит правильно, - person YanXi; 29.12.2017
comment
и я также узнал, что функция computerkey должна быть server_random + client random, НЕ такой же, как главный секрет компьютера, может быть, многие разработчики не уловили этого, но все еще не расшифровали данные правильно, так сложно . - person YanXi; 29.12.2017
comment
@YanXi: размер блока DES и 3DES составляет 64 бита, а AES — 128 бит для всех реализаций. Но размер блока имеет значение только в некоторых режимах: открытый текст и зашифрованный текст должны быть едиными блоками для ECB или CBC, но не для CTR GCM CCM и т. д. (И не используйте ECB, если вы действительно не знаете, что вам нужно). делает.) Если у вас есть разница между 3DES и AES, это может быть связано с тем, что dotNET применяет исходное, но теперь устаревшее требование для DES и 3DES, чтобы байты key имели нечетную четность; если это так, отрегулируйте младший бит каждого ключевого байта, чтобы удовлетворить это. (См. очень краткое примечание в Приложении B к rfc2246 et seq.) ... - person dave_thompson_085; 30.12.2017
comment
... Если вы можете, я предлагаю провести сеанс с Java с sysprop javax.net.debug=ssl, который подробно показывает ключевой материал, который он извлекает, а затем убедитесь, что ваша логика дает тот же результат с теми же входными данными. - person dave_thompson_085; 30.12.2017
comment
спасибо за всю вашу помощь, я наконец-то расшифровал данные, это из-за extended_master_secret, используйте хэш сеанса вместо случайных чисел для главного секрета. - person YanXi; 31.12.2017