С++ Base64 Sha1 — рукопожатие WebSocket

В настоящее время я пытаюсь запустить сервер С++, который может взаимодействовать с WebSocket. Рукопожатие состоит из пары шагов, и у меня не получается с последним.

Первым шагом является создание строки в кодировке SHA1, и я успешно получил правильную шестнадцатеричную строку. (Пример http://en.wikipedia.org/wiki/WebSocket и http://tools.ietf.org/html/rfc6455).

Мой вывод в обоих случаях такой же, как указано в документации:

Wikipedia: 1d 29 ab 73 4b 0c 95 85 24 00 69 a6 e4 e3 e9 1b 61 da 19 69
My Server: 1d 29 ab 73 4b 0c 95 85 24 00 69 a6 e4 e3 e9 1b 61 da 19 69

IETF Docu: b3 7a 4f 2c c0 62 4f 16 90 f6 46 06 cf 38 59 45 b2 be c4 ea
My Server: b3 7a 4f 2c c0 62 4f 16 90 f6 46 06 cf 38 59 45 b2 be c4 ea

Так что это правильно. Когда я теперь делаю кодировку Base64, я прихожу к следующим результатам:

Wikipedia: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
My Server: MWQyOWFiNzM0YjBjOTU4NTI0MDA2OWE2ZTRlM2U5MWI2MWRhMTk2OQ==

IETF Docu: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
My Server: YjM3YTRmMmNjMDYyNGYxNjkwZjY0NjA2Y2YzODU5NDViMmJlYzRlYQ==

А это совсем другое. Я подтвердил, что мой алгоритм Base64 работает с некоторыми онлайн-конвертерами, и все они выдавали результат, который делал мой сервер. Итак, проблема заключается в формате ввода. Я нашел запись на форуме javascript, где у одного была такая же проблема, и ответ заключался в том, что вместо передачи 40-символьной шестнадцатеричной строки мы должны передать 20-символьное двоичное представление.

Я знаю, что openssl SHA1 возвращает двоичное представление, но я не могу использовать библиотеку по определенным причинам. Библиотека SHA1, которую я использую, помещает закодированный вывод в массив int. Результат выглядит следующим образом (пример IETF):

result[0] = 3011137324
result[1] = 3227668246
result[2] = 2432058886
result[3] = 3476576581
result[4] = 2998846698

Я конвертирую это, чем в шестнадцатеричный код следующим образом:

std::ostringstream oss;
oss << std::setfill('0');
            for (int i = 0; i < 5; ++i) {
                    oss << std::setw(8) << std::hex << result[i];
            }

Теперь большой вопрос. Как я могу преобразовать свою шестнадцатеричную строку в двоичную?

Заранее большое спасибо . Маркус

ИЗМЕНИТЬ

Если кому-то интересен код: https://github.com/MarkusPfundstein/C---Websocket-Server


person markus_p    schedule 13.05.2012    source источник


Ответы (3)


Я тестировал веб-сокет в c и обнаружил, что байты были в неправильном порядке. Адаптация порядка (в обратном порядке) решила мою проблему с кодировкой base64, в результате чего была получена правильная принятая ключевая строка:

unsigned char byteResult [20];
    for(i = 0; i < 5; i++) {
        byteResult[(i * 4) + 3] = sha.result[i] & 0x000000ff;
        byteResult[(i * 4) + 2] = (sha.result[i] & 0x0000ff00) >> 8;
        byteResult[(i * 4) + 1] = (sha.result[i] & 0x00ff0000) >> 16;
        byteResult[(i * 4) + 0] = (sha.result[i] & 0xff000000) >> 24;
    }
person João Reis    schedule 16.08.2012
comment
Спасибо. здесь вы можете увидеть, как я это исправил (метод Connection::Authenticate() github.com/MarkusPfundstein/C---Websocket-Server/blob/master/ - person markus_p; 16.08.2012

Большинство кодировщиков Baser64 ожидают байтовый массив/поток двоичных данных. Вы хотите разбить свои целые числа на байты, используя битовые маски и логические сдвиги. В 32-битных системах каждый int содержит 4 байта, вы можете извлечь их следующим образом:

for(i = 0; i < 5; i++) {

    byteResult[(i * 4) + 0] = result[i] & 0x000000ff;
    byteResult[(i * 4) + 1] = (result[i] & 0x0000ff00) >> 8;
    byteResult[(i * 4) + 2] = (result[i] & 0x00ff0000) >> 16;
    byteResult[(i * 4) + 3] = (result[i] & 0xff000000) >> 24;
}

Где byteResult - это byte[] в 4 раза больше, чем массив результатов. Я предполагаю порядок, в котором байты были упакованы в целые числа здесь, это может быть наоборот.

Передайте этот byte[] в кодировщик Base64.

person Malcolm Smith    schedule 13.05.2012
comment
классно попробую в ближайшее время - person markus_p; 13.05.2012
comment
Мне очень жаль, но это не работает :( Результатом является массив из 5, поэтому мне не нужно перечислять до тех пор, пока i ‹ 5 ? Это также дает очень странный результат. - person markus_p; 13.05.2012
comment
извините, вы совершенно правы, должно быть 5 - ответ обновлен. Также см. мою заметку о порядке байтов. В чем странность вывода? - person Malcolm Smith; 13.05.2012
comment
это байтовый результат: ,Oz�Ob�F�EY8�ľ�b37a4f2cc0624f1690f64606cf385945b2bec4ea - person markus_p; 13.05.2012
comment
хорошо - байты должны выглядеть странно, это хэш SHA1 ввода - его необработанные двоичные данные, а не текст. Версия этих байтов в кодировке Base64 не соответствует тому, что вы ищете? - person Malcolm Smith; 14.05.2012
comment
Какие входные данные принимает ваш кодировщик Base64? Вы передаете ему byte[] напрямую? - person Malcolm Smith; 14.05.2012
comment
эй, друг, ты, я передал это напрямую. В конце концов я использовал openssl, чтобы решить проблему, но большое спасибо за ваши усилия. - person markus_p; 16.05.2012

Немного связанная с этим заметка (я вижу, вы уже открыли для себя способ EVP BIO base64). ..):

result[0] = 3011137324
...
oss << std::setw(8) << std::hex << result[i];

Если я правильно понимаю, это приводит к выводу b37a4f2c, который является вашим примером документа IETF. Будьте очень осторожны здесь, потому что вы рассказываете об опасностях открытой воды для конкретной платформы endianess. 0n3011137324 — это действительно 0xb37a4f2c, но только на машинах с прямым порядком байтов, таких как архитектуры Intel. Вероятно, вам было бы лучше переинтерпретировать преобразование &result[0] в unsigned char*, а затем обрабатывать это как массив байтов, а не массив (беззнаковых) целых чисел.

person Remus Rusanu    schedule 16.08.2012