Вычисление значения websocket Sec-WebSocket-Accept с использованием libtomcrypt
RFC6455 определяет метод вычисления Sec-WebSocket-Accept
заголовок ответа от значения Sec-WebSocket-Key
заголовок. Этот метод основан на хешировании SHA-1 и Base64-кодировании результата.
Как я могу реализовать этот метод в простом C, используя libtomcrypt для SHA-1 и Base64?
Примечание: этот вопрос намеренно не требует никаких усилий, потому что я сразу же ответил на него сам. Смотрите ниже мои усилия.
1 ответ
Решение
Вот полный компилируемый пример, который использует только libtomcrypt без какого-либо динамического выделения памяти и успешно вычисляет эталонный пример из RFC6455:
//This file is licensed under CC0 1.0 Universal (public domain)
//Compile like this: gcc -o wsencodetest wsencodetest.c -ltomcrypt
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <tomcrypt.h>
#define SHA1_HASHSIZE 20
//Magic GUID as defined in RFC6455 section 1.3
static const char magicGUID[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
/**
* Compute the value of the Sec-WebSocket-Accept response header
* from the value of the Sec-WebSocket-Key header.
* @param key The whitespace or NUL terminated Sec-WebSocket-Key value
* @param out Where to store the base64-encoded output. Must provide 29 bytes of memory.
* The 29 bytes starting at out contain the resulting value (plus a terminating NUL byte)
*/
void computeWebsocketSecAccept(const char* key, char* dst) {
/**
* Determine start & length of key minus leading/trailing whitespace
* See RFC6455 section 1.3
*/
//Skip leading whitespace
while(isspace(*key)) {
key++;
}
//Determine key size.
size_t keySize = 0;
while(!isspace(key[keySize]) && key[keySize] != 0) {
keySize++;
}
//Compute SHA1 hash. See RFC6455 section 1.3
char hashOut[SHA1_HASHSIZE];
hash_state md;
sha1_desc.init(&md);
sha1_desc.process(&md, key, keySize);
sha1_desc.process(&md, magicGUID, sizeof(magicGUID));
sha1_desc.done(&md, hashOut);
//Encode hash to output buffer
size_t outlen = 29; //We know the output is 28 in size
base64_encode(hashOut, SHA1_HASHSIZE, dst, &outlen);
}
/**
* Usage example
*/
int main(int argc, char** argv) {
//Whitespace needs to be removed according to RFC6455
//Example from RFC6455
const char* key = " dGhlIHNhbXBsZSBub25jZQ== ";
char buf[29];
//Perform computation
computeWebsocketSecAccept(key, buf);
//Should print s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
printf("%s\n", buf);
}