diff --git a/dependencies/tlibc b/dependencies/tlibc index 7e7bd19..14ffede 160000 --- a/dependencies/tlibc +++ b/dependencies/tlibc @@ -1 +1 @@ -Subproject commit 7e7bd195a9715abceb4131b21232aed7d990b75d +Subproject commit 14ffede476b786d9e31006f4bac52289ff656158 diff --git a/src/client/ClientCredential.c b/src/client/ClientCredential.c index 8cb7330..01e57fc 100644 --- a/src/client/ClientCredential.c +++ b/src/client/ClientCredential.c @@ -13,6 +13,7 @@ void ClientCredential_free(ClientCredential* cred){ } #define __passhash_lvl_iter 1e5 +#define __rsa_key_size 2048 Result(ClientCredential*) ClientCredential_create(str username, str password){ Deferral(32); @@ -56,7 +57,8 @@ Result(ClientCredential*) ClientCredential_create(str username, str password){ // generate client rsa keys from password hash br_hmac_drbg_context passhash_based_rng = { .vtable = &br_hmac_drbg_vtable }; br_hmac_drbg_init(&passhash_based_rng, &br_sha256_vtable, passhash_lvl1.data, password_hash_size); - try_void(RSA_generateKeyPair(4096, &cred->sk, &cred->pk, &passhash_based_rng.vtable)); + // TODO: does client really need it's own RSA private key? At least i should generate it once using seedFromTime and save in a file encrypted by user_data_aes_enc + try_void(RSA_generateKeyPair(__rsa_key_size, &cred->sk, &cred->pk, &passhash_based_rng.vtable)); Defer( if(!success){ RSA_destroyPrivateKey(&cred->sk); @@ -66,8 +68,8 @@ Result(ClientCredential*) ClientCredential_create(str username, str password){ DecryptorRSA_construct(&cred->rsa_dec, &cred->sk); EncryptorRSA_construct(&cred->rsa_enc, &cred->pk); - DecryptorAES_construct(&cred->aes_dec, cred->aes_key); - EncryptorAES_construct(&cred->aes_enc, cred->aes_key); + DecryptorAES_construct(&cred->user_data_aes_dec, cred->aes_key); + EncryptorAES_construct(&cred->user_data_aes_enc, cred->aes_key); success = true; Return RESULT_VALUE(p, cred); diff --git a/src/client/ServerConnection.c b/src/client/ServerConnection.c index c592671..db25934 100644 --- a/src/client/ServerConnection.c +++ b/src/client/ServerConnection.c @@ -5,18 +5,44 @@ void ServerConnection_close(ServerConnection* conn){ return; socket_close(conn->system_socket); socket_close(conn->content_socket); + RSA_destroyPublicKey(&conn->server_pk); free(conn); } -Result(ServerConnection*) ServerConnection_open(ClientCredential* client_credential, EndpointIPv4 server_end, str server_key){ +/// @brief +/// @param server_link_cstr address:port:public_key +/// @return +Result(void) ServerLink_parse(cstr server_link_cstr, EndpointIPv4* server_end_out, br_rsa_public_key* server_key_out){ + Deferral(16); + str server_link_str = str_from_cstr(server_link_cstr); + i32 sep_pos = 0; + + // parse address and port + sep_pos = str_seekChar(server_link_str, ':', sep_pos); + if(sep_pos == -1){ + Return RESULT_ERROR_FMT("server link is invalid: %s", server_link_cstr); + } + *server_end_out = EndpointIPv4_INVALID; + try_void(EndpointIPv4_parse(server_link_cstr, server_end_out)); + if(EndpointIPv4_is_invalid(*server_end_out)){ + Return RESULT_ERROR_FMT("server address or port is invalid: %s", server_link_cstr); + } + + // parse public key + sep_pos = str_seekChar(server_link_str, ':', sep_pos); + if(sep_pos == -1){ + Return RESULT_ERROR_FMT("server link is invalid: %s", server_link_cstr); + } + str server_key_str = server_link_str; + server_key_str.data += sep_pos + 1; + try_void(RSA_parsePublicKey_base64(server_key_str, server_key_out)); + + Return RESULT_VOID; +} + +Result(ServerConnection*) ServerConnection_open(ClientCredential* client_credential, cstr server_link_cstr){ Deferral(64); - str end_str = EndpointIPv4_toStr(server_end); - Defer(free(end_str.data)); - if(EndpointIPv4_is_invalid(server_end)){ - Return RESULT_ERROR_FMT("endpoint is invalid: %s", end_str.data); - } - ServerConnection* conn = (ServerConnection*)malloc(sizeof(ServerConnection)); memset(conn, 0, sizeof(ServerConnection)); bool success = false; @@ -25,12 +51,10 @@ Result(ServerConnection*) ServerConnection_open(ClientCredential* client_credent ServerConnection_close(conn); ); - printf("connecting to server %s\n", end_str.data); + printf("connecting to server %s\n", server_link_cstr); try(conn->system_socket, i, socket_open_TCP()); - try_void(socket_connect(conn->system_socket, server_end)); + try_void(socket_connect(conn->system_socket, conn->server_end)); - // ask user name and password - // calculate key pair from password hash // send client public key to server // request server info // show server info diff --git a/src/client/client.c b/src/client/client.c index 1c8edf3..4151c3a 100644 --- a/src/client/client.c +++ b/src/client/client.c @@ -26,10 +26,16 @@ static Result(void) commandExec(str command, bool* stop); static Result(void) askUserNameAndPassword(ClientCredential** cred){ Deferral(8); + + printf("username: "); char username[1024]; + fgets(username, sizeof(username), stdin); + + printf("password: "); char password[1024]; - scanf("username: %s", username); - scanf("password: %s", password); + // TODO: hide password + fgets(password, sizeof(password), stdin); + try(*cred, p, ClientCredential_create(str_from_cstr(username), str_from_cstr(password))); Return RESULT_VOID; } @@ -96,13 +102,10 @@ static Result(void) commandExec(str command, bool* stop){ else if (is_alias("j") || is_alias("join")){ puts("Enter server address (ip:port): "); fgets(answer_buf, answer_buf_size, stdin); - EndpointIPv4 new_server_end; - try_void(EndpointIPv4_parse(answer_buf, &new_server_end)); - puts("Enter server key (): "); - fgets(answer_buf, answer_buf_size, stdin); - str new_server_key = str_from_cstr(answer_buf); - try(ServerConnection* conn, p, ServerConnection_open(client_credential, new_server_end, new_server_key)); - // TODO: close server connection somewhere + str new_server_link = str_from_cstr(answer_buf); + str_trim(&new_server_link, true); + try(ServerConnection* conn, p, ServerConnection_open(client_credential, new_server_link.data)); + // TODO: store server connection somewhere } else if(is_alias("c") || is_alias("connect")){ // TODO: read saved servers from database diff --git a/src/client/client.h b/src/client/client.h index bd93a06..78c0bd8 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -12,8 +12,8 @@ typedef struct ClientCredential { br_rsa_public_key pk; EncryptorRSA rsa_enc; DecryptorRSA rsa_dec; - EncryptorAES aes_enc; - DecryptorAES aes_dec; + EncryptorAES user_data_aes_enc; + DecryptorAES user_data_aes_dec; } ClientCredential; Result(ClientCredential*) ClientCredential_create(str username, str password); @@ -23,10 +23,11 @@ typedef struct ServerConnection { EndpointIPv4 server_end; Socket system_socket; Socket content_socket; + br_rsa_public_key server_pk; EncryptorRSA rsa_enc; EncryptorAES session_aes_enc; DecryptorAES session_aes_dec; } ServerConnection; -Result(ServerConnection*) ServerConnection_open(ClientCredential* client_credential, EndpointIPv4 server_end, str server_key); -void ServerConnection_close(ServerConnection* conn); \ No newline at end of file +Result(ServerConnection*) ServerConnection_open(ClientCredential* client_credential, cstr server_link_cstr); +void ServerConnection_close(ServerConnection* conn); diff --git a/src/cryptography/RSA.c b/src/cryptography/RSA.c index 9ec72d7..e90abc8 100644 --- a/src/cryptography/RSA.c +++ b/src/cryptography/RSA.c @@ -2,6 +2,7 @@ #include #include "bearssl_x509.h" #include "bearssl_pem.h" +#include "tlibc/base64.h" // https://crypto.stackexchange.com/questions/3110/impacts-of-not-using-rsa-exponent-of-65537 #define DEFAULT_PUBLIC_EXPONENT 65537 @@ -71,110 +72,88 @@ Result(void) RSA_computePublicKey(const br_rsa_private_key* sk, br_rsa_public_ke Return RESULT_VOID; } -Result(void) RSA_serializePrivateKey_RawDER( - const br_rsa_private_key* sk, - NULLABLE(const br_rsa_public_key*) pk, - Array(u8)* out_der) -{ - Deferral(32); - br_rsa_compute_pubexp compute_pubexp = br_rsa_i31_compute_pubexp; - br_rsa_compute_privexp compute_privexp = br_rsa_i31_compute_privexp; - - br_rsa_public_key pk_computed; - if(pk == NULL){ - pk = &pk_computed; - try_void(RSA_computePublicKey(sk, &pk_computed)); - Defer(free(pk->n)); - } - - u32 pubexp_little_endian = compute_pubexp(sk); - if (pubexp_little_endian == 0) { - Return RESULT_ERROR("compute_pubexp", false); - } - size_t privexp_size = compute_privexp(NULL, sk, pubexp_little_endian); - if (privexp_size == 0) { - Return RESULT_ERROR("compute_privexp", false); - } - void* privexp = malloc(privexp_size); - Defer(free(privexp)); - if (compute_privexp(privexp, sk, pubexp_little_endian) != privexp_size) { - Return RESULT_ERROR("compute_privexp", false); - } - +str RSA_serializePrivateKey_base64(const br_rsa_private_key* sk){ + u32 key_buffer_size = BR_RSA_KBUF_PRIV_SIZE(sk->n_bitlen); + u32 key_base64_size = base64_encodedSize(key_buffer_size); + char* serialized_buf = malloc(32 + key_base64_size); + sprintf(serialized_buf, "RSA-Private-%u:", sk->n_bitlen); + u32 offset = strlen(serialized_buf); + offset += base64_encode(sk->p, key_buffer_size, serialized_buf + offset); + serialized_buf[offset] = '\0'; + return str_construct(serialized_buf, offset, true); +} - size_t der_size = br_encode_rsa_raw_der(NULL, sk, pk, privexp, privexp_size); - if (der_size == 0) { - Return RESULT_ERROR("br_encode_rsa_raw_der", false); - } - void* der = malloc(der_size); - bool success = false; - Defer( - if(!success) - free(der) - ); - if (br_encode_rsa_raw_der(der, sk, pk, privexp, privexp_size) != der_size) { - Return RESULT_ERROR("br_encode_rsa_raw_der", false); - } +str RSA_serializePublicKey_base64(const br_rsa_public_key* pk){ + u32 n_bitlen = pk->nlen * 8; + u32 key_buffer_size = BR_RSA_KBUF_PUB_SIZE(n_bitlen); + u32 key_base64_size = base64_encodedSize(key_buffer_size); + char* serialized_buf = malloc(32 + key_base64_size); + sprintf(serialized_buf, "RSA-Public-%u:", n_bitlen); + u32 offset = strlen(serialized_buf); + offset += base64_encode(pk->n, key_buffer_size, serialized_buf + offset); + serialized_buf[offset] = '\0'; + return str_construct(serialized_buf, offset, true); +} - success = true; - out_der->data = der; - out_der->size = der_size; +Result(void) RSA_parsePublicKey_base64(const str src, br_rsa_public_key* pk){ + Deferral(8); + u32 n_bitlen = 0; + if(sscanf(src.data, "RSA-Public-%u:", &n_bitlen) != 1){ + Return RESULT_ERROR("can't parse key size", false); + } + u32 key_buffer_size = BR_RSA_KBUF_PUB_SIZE(n_bitlen); + pk->n = malloc(key_buffer_size); + pk->elen = 4; + pk->nlen = key_buffer_size - 4; + pk->e = pk->n + pk->nlen; + u32 offset = str_seekChar(src, ':', 14) + 1; + if(offset == 0){ + Return RESULT_ERROR("missing ':' before key data", false); + } + str key_base64_str = src; + key_base64_str.data += offset; + key_base64_str.size -= offset; + u32 decoded_size = base64_decodedSize(key_base64_str.data, key_base64_str.size); + if(decoded_size != key_buffer_size){ + Return RESULT_ERROR_FMT("decoded key size is %u, must be %u", decoded_size, key_buffer_size); + } + decoded_size = base64_decode(key_base64_str.data, key_base64_str.size, pk->n); + if(decoded_size != key_buffer_size){ + Return RESULT_ERROR("key decoding failed", false); + } Return RESULT_VOID; } -void PEM_encode(Array(u8) src, Array(u8)* dst, cstr label){ - u64 encoded_size = br_pem_encode(NULL, src.data, src.size, label, 0); - // br_pem_encode doesn't count '\0' but writes it - *dst = Array_alloc_size(encoded_size + 1); - br_pem_encode(dst->data, src.data, src.size, label, 0); -} - - -Result(void) RSA_parsePrivateKey_DER(Array(u8) _src, br_rsa_private_key* sk){ - Deferral(16); - // private key data will be written in this buffer on success - Array(u8) buf = Array_copy(_src); - bool success = false; - Defer(free(buf.data)); - - br_skey_decoder_context decoder; - br_skey_decoder_init(&decoder); - br_skey_decoder_push(&decoder, buf.data, buf.size); - i32 errcode = br_skey_decoder_last_error(&decoder); - if (errcode != 0) { - Return RESULT_ERROR_FMT("br_skey_decoder error %i", errcode); - } - i32 parsed_type = br_skey_decoder_key_type(&decoder); - if(parsed_type != BR_KEYTYPE_RSA){ - Return RESULT_ERROR_FMT("parsed key has unsupported type %i", parsed_type); +Result(void) RSA_parsePrivateKey_base64(const str src, br_rsa_private_key* sk){ + Deferral(8); + u32 n_bitlen = 0; + if(sscanf(src.data, "RSA-Private-%u:", &n_bitlen) != 1){ + Return RESULT_ERROR("can't parse key size", false); } - const br_rsa_private_key* decoded_key = br_skey_decoder_get_rsa(&decoder); - if(decoded_key == NULL){ - Return RESULT_ERROR("decoder failed without errors", false); + sk->n_bitlen = n_bitlen; + u32 key_buffer_size = BR_RSA_KBUF_PRIV_SIZE(n_bitlen); + u32 field_len = key_buffer_size / 5; + sk->plen = sk->qlen = sk->dplen = sk->dqlen = sk->iqlen = field_len; + sk->p = malloc(key_buffer_size); + sk->q = sk->p + field_len; + sk->dp = sk->q + field_len; + sk->dq = sk->dp + field_len; + sk->iq = sk->dq + field_len; + u32 offset = str_seekChar(src, ':', 14) + 1; + if(offset == 0){ + Return RESULT_ERROR("missing ':' before key data", false); } - - success = true; - memcpy(sk, decoded_key, sizeof(*decoded_key)); - - // sk fields still point to stack array decoder.key_data - // This code copies the data and adjusts sk fields to point to the copied chunk - Array(u8) key_data_copy = Array_alloc_size(BR_RSA_KBUF_PRIV_SIZE(decoded_key->n_bitlen)); - Defer( - if(!success) - free(key_data_copy.data); - ); - memcpy(key_data_copy.data, decoder.key_data, key_data_copy.size); - u64 memory_distance = (u64)key_data_copy.data - (u64)(void*)decoder.key_data; - u8** sk_pointer_fields[] = { - &sk->p, &sk->q, &sk->dp, &sk->dq, &sk->iq - }; - for(u32 i = 0; i < ARRAY_LEN(sk_pointer_fields); i++){ - u8** field_place = sk_pointer_fields[i]; - u64 field_value = (u64)*field_place; - field_value += memory_distance; - *field_place = (void*)field_value; + str key_base64_str = src; + key_base64_str.data += offset; + key_base64_str.size -= offset; + u32 decoded_size = base64_decodedSize(key_base64_str.data, key_base64_str.size); + if(decoded_size != key_buffer_size){ + Return RESULT_ERROR_FMT("decoded key size is %u, must be %u", decoded_size, key_buffer_size); + } + decoded_size = base64_decode(key_base64_str.data, key_base64_str.size, sk->p); + if(decoded_size != key_buffer_size){ + Return RESULT_ERROR("key decoding failed", false); } - Return RESULT_VOID; } diff --git a/src/cryptography/cryptography.h b/src/cryptography/cryptography.h index 9e53fd1..f478b57 100755 --- a/src/cryptography/cryptography.h +++ b/src/cryptography/cryptography.h @@ -107,24 +107,24 @@ static inline void RSA_destroyPublicKey(br_rsa_public_key* sk){ /// @param pk out public key. WARNING: .n is allocated on heap Result(void) RSA_computePublicKey(const br_rsa_private_key* sk, br_rsa_public_key* pk); -/// @brief Serialize key in raw DER binary format -/// @param sk the private key -/// @param pk set to NULL to calculate automatically -/// @param out_der out array. WARNING: .data is allocated on heap -Result(void) RSA_serializePrivateKey_RawDER( - const br_rsa_private_key* sk, - NULLABLE(const br_rsa_public_key*) pk, - Array(u8)* out_der); +/// @brief Encode key data in human-readable format +/// @param src some data +/// @return heap-allocated string +str RSA_serializePrivateKey_base64(const br_rsa_private_key* sk); + +/// @param src serialized private key format "RSA-Private-%SIZE%:%DATA_BASE64%" +/// @param sk out private key. WARNING: .p is allocated on heap +Result(void) RSA_parsePrivateKey_base64(const str src, br_rsa_private_key* sk); /// @brief Encode key data in human-readable format /// @param src some data -/// @param dst out array. WARNING: .data is allocated on heap -/// @param label some string to write at the top of PEM file -void PEM_encode(Array(u8) src, Array(u8)* dst, cstr label); +/// @return heap-allocated string +str RSA_serializePublicKey_base64(const br_rsa_public_key* sk); + +/// @param src serialized public key format "RSA-Public-%SIZE%:%DATA_BASE64%" +/// @param sk out public key. WARNING: .p is allocated on heap +Result(void) RSA_parsePublicKey_base64(const str src, br_rsa_public_key* sk); -/// @param src serialized private key in DER format -/// @param sk out private key. WARNING: .p is allocated on heap -Result(void) RSA_parsePrivateKey_DER(Array(u8) src, br_rsa_private_key* sk); typedef struct EncryptorRSA { const br_rsa_public_key* pk; diff --git a/src/network/endpoint.h b/src/network/endpoint.h index 8f2d243..1bb3822 100755 --- a/src/network/endpoint.h +++ b/src/network/endpoint.h @@ -29,7 +29,7 @@ typedef struct EndpointIPv4 { } EndpointIPv4; #define EndpointIPv4_INVALID EndpointIPv4_create(AddressIPv4_INVALID, port_INVALID) -#define EndpointIPv4_is_invalid(ENDP) (AddressIPv4_is_invalid(ENDP.address) || port_is_invalid(ENDP.port)) +#define EndpointIPv4_is_invalid(ENDP) (AddressIPv4_is_invalid((ENDP).address) || port_is_invalid((ENDP).port)) #define EndpointIPv4_create(ADDR, PORT) ((EndpointIPv4){ADDR, PORT}) Result(void) EndpointIPv4_parse(cstr s, EndpointIPv4* end);