char *ss_gen_hash(char *buf, ssize_t *buf_len, uint32_t *counter, struct enc_ctx *ctx, int buf_size) { ssize_t blen = *buf_len; int size = max(AUTH_BYTES + blen, buf_size); if (buf_size < size) { buf = realloc(buf, size); } uint16_t chunk_len = htons((uint16_t)blen); uint8_t hash[ONETIMEAUTH_BYTES * 2]; uint8_t key[MAX_IV_LENGTH + sizeof(uint32_t)]; uint32_t c = htonl(*counter); memcpy(key, ctx->evp.iv, enc_iv_len); memcpy(key + enc_iv_len, &c, sizeof(uint32_t)); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), key, enc_iv_len + sizeof(uint32_t), (uint8_t *)buf, blen, hash, NULL); #else ss_sha1_hmac(key, enc_iv_len + sizeof(uint32_t), (uint8_t *)buf, blen, hash); #endif memmove(buf + AUTH_BYTES, buf, blen); memcpy(buf + CLEN_BYTES, hash, ONETIMEAUTH_BYTES); memcpy(buf, &chunk_len, CLEN_BYTES); *counter = *counter + 1; *buf_len = blen + AUTH_BYTES; return buf; }
int ss_onetimeauth_verify(char *auth, char *msg, int msg_len, uint8_t *iv) { uint8_t hash[ONETIMEAUTH_BYTES * 2]; uint8_t auth_key[MAX_IV_LENGTH + MAX_KEY_LENGTH]; memcpy(auth_key, iv, enc_iv_len); memcpy(auth_key + enc_iv_len, enc_key, enc_key_len); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, hash, NULL); #else ss_sha1_hmac(auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, hash); #endif return memcmp(auth, hash, ONETIMEAUTH_BYTES); }
int ss_sha1_hmac(char *auth, char *msg, int msg_len, uint8_t *iv) { uint8_t hash[ONETIMEAUTH_BYTES * 2]; uint8_t auth_key[MAX_IV_LENGTH + MAX_KEY_LENGTH]; memcpy(auth_key, iv, enc_iv_len); memcpy(auth_key + enc_iv_len, enc_key, enc_key_len); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash); #else ss_sha1_hmac(auth_key, enc_iv_len + enc_key_len, (uint8_t *)msg, msg_len, (uint8_t *)hash); #endif memcpy(auth, hash, ONETIMEAUTH_BYTES); return 0; }
int auth_sha1_v4_pack_auth_data(auth_simple_global_data *global, server_info *server, char *data, int datalength, char *outdata) { unsigned int rand_len = (datalength > 1300 ? 0 : datalength > 400 ? (xorshift128plus() & 0x7F) : (xorshift128plus() & 0x3FF)) + 1; int data_offset = rand_len + 4 + 2; int out_size = data_offset + datalength + 12 + OBFS_HMAC_SHA1_LEN; const char* salt = "auth_sha1_v4"; int salt_len = strlen(salt); unsigned char *crc_salt = (unsigned char*)malloc(salt_len + server->key_len + 2); crc_salt[0] = outdata[0] = out_size >> 8; crc_salt[1] = outdata[1] = out_size; memcpy(crc_salt + 2, salt, salt_len); memcpy(crc_salt + salt_len + 2, server->key, server->key_len); fillcrc32to(crc_salt, salt_len + server->key_len + 2, (unsigned char *)outdata + 2); free(crc_salt); if (rand_len < 128) { outdata[6] = rand_len; } else { outdata[6] = 0xFF; outdata[7] = rand_len >> 8; outdata[8] = rand_len; } ++global->connection_id; if (global->connection_id > 0xFF000000) { rand_bytes(global->local_client_id, 8); rand_bytes((uint8_t*)&global->connection_id, 4); global->connection_id &= 0xFFFFFF; } time_t t = time(NULL); memintcopy_lt(outdata + data_offset, t); memmove(outdata + data_offset + 4, global->local_client_id, 4); memintcopy_lt(outdata + data_offset + 8, global->connection_id); memmove(outdata + data_offset + 12, data, datalength); char hash[ONETIMEAUTH_BYTES * 2]; ss_sha1_hmac(hash, outdata, out_size - OBFS_HMAC_SHA1_LEN, server->iv); memcpy(outdata + out_size - OBFS_HMAC_SHA1_LEN, hash, OBFS_HMAC_SHA1_LEN); return out_size; }
int auth_sha1_pack_auth_data(auth_simple_global_data *global, server_info *server, char *data, int datalength, char *outdata) { unsigned char rand_len = (xorshift128plus() & 0x7F) + 1; int data_offset = rand_len + 4 + 2; int out_size = data_offset + datalength + 12 + OBFS_HMAC_SHA1_LEN; fillcrc32to((unsigned char *)server->key, server->key_len, (unsigned char *)outdata); outdata[4] = out_size >> 8; outdata[5] = out_size; outdata[6] = rand_len; ++global->connection_id; if (global->connection_id > 0xFF000000) { rand_bytes(global->local_client_id, 8); rand_bytes((uint8_t*)&global->connection_id, 4); global->connection_id &= 0xFFFFFF; } time_t t = time(NULL); memintcopy_lt(outdata + data_offset, t); memmove(outdata + data_offset + 4, global->local_client_id, 4); memintcopy_lt(outdata + data_offset + 8, global->connection_id); memmove(outdata + data_offset + 12, data, datalength); char hash[ONETIMEAUTH_BYTES * 2]; ss_sha1_hmac(hash, outdata, out_size - OBFS_HMAC_SHA1_LEN, server->iv); memcpy(outdata + out_size - OBFS_HMAC_SHA1_LEN, hash, OBFS_HMAC_SHA1_LEN); return out_size; }
int ss_check_hash(char **buf_ptr, ssize_t *buf_len, struct chunk *chunk, struct enc_ctx *ctx, int buf_size) { int i, j, k; char *buf = *buf_ptr; ssize_t blen = *buf_len; uint32_t cidx = chunk->idx; if (chunk->buf == NULL) { chunk->buf = (char *)malloc(buf_size); chunk->len = buf_size - AUTH_BYTES; } int size = max(chunk->len + blen, buf_size); if (buf_size < size) { buf = realloc(buf, size); } for (i = 0, j = 0, k = 0; i < blen; i++) { chunk->buf[cidx++] = buf[k++]; if (cidx == CLEN_BYTES) { uint16_t clen = ntohs(*((uint16_t *)chunk->buf)); if (buf_size < clen + AUTH_BYTES) { chunk->buf = realloc(chunk->buf, clen + AUTH_BYTES); } chunk->len = clen; } if (cidx == chunk->len + AUTH_BYTES) { // Compare hash uint8_t hash[ONETIMEAUTH_BYTES * 2]; uint8_t key[MAX_IV_LENGTH + sizeof(uint32_t)]; uint32_t c = htonl(chunk->counter); memcpy(key, ctx->evp.iv, enc_iv_len); memcpy(key + enc_iv_len, &c, sizeof(uint32_t)); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), key, enc_iv_len + sizeof(uint32_t), (uint8_t *)chunk->buf + AUTH_BYTES, chunk->len, hash, NULL); #else ss_sha1_hmac(key, enc_iv_len + sizeof(uint32_t), (uint8_t *)chunk->buf + AUTH_BYTES, chunk->len, hash); #endif if (memcmp(hash, chunk->buf + CLEN_BYTES, ONETIMEAUTH_BYTES) != 0) { *buf_ptr = buf; return 0; } // Copy chunk back to buffer memmove(buf + j + chunk->len, buf + k, blen - i - 1); memcpy(buf + j, chunk->buf + AUTH_BYTES, chunk->len); // Reset the base offset j += chunk->len; k = j; cidx = 0; chunk->counter++; } } *buf_ptr = buf; *buf_len = j; chunk->idx = cidx; return 1; }