mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-29 12:36:53 +00:00
Refine the authentication for true CCA
This commit is contained in:
+55
-31
@@ -1478,53 +1478,77 @@ int enc_init(const char *pass, const char *method)
|
||||
return m;
|
||||
}
|
||||
|
||||
int ss_check_hash(char *buf, ssize_t *buf_len, char *hash_buf, ssize_t *hash_idx)
|
||||
int ss_check_hash(char **buf_ptr, ssize_t *buf_len, struct chunk *chunk, int buf_size)
|
||||
{
|
||||
int i, j;
|
||||
int i, j, k;
|
||||
char *buf = *buf_ptr;
|
||||
ssize_t blen = *buf_len;
|
||||
ssize_t cidx = *hash_idx;
|
||||
uint32_t cidx = chunk->idx;
|
||||
|
||||
for (i = 0, j = 0; i < blen; i++) {
|
||||
if (cidx < HASH_BUF_LEN) {
|
||||
buf[j] = buf[i];
|
||||
j++;
|
||||
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 (chunk->len < clen) {
|
||||
chunk->buf = realloc(chunk->buf, clen + AUTH_BYTES);
|
||||
}
|
||||
chunk->len = clen;
|
||||
}
|
||||
hash_buf[cidx] = buf[i];
|
||||
cidx++;
|
||||
if (cidx == HASH_BUF_LEN + HASH_BYTES) {
|
||||
uint8_t hash[HASH_BYTES];
|
||||
crypto_generichash(hash, HASH_BYTES, (uint8_t *)hash_buf, HASH_BUF_LEN, NULL, 0);
|
||||
if (memcmp(hash, hash_buf + HASH_BUF_LEN, HASH_BYTES) != 0) return 0;
|
||||
|
||||
if (cidx == chunk->len + AUTH_BYTES) {
|
||||
// Compare hash
|
||||
uint8_t *hash = (uint8_t *)malloc(chunk->len);
|
||||
crypto_generichash(hash, HASH_BYTES, (uint8_t *)chunk->buf + AUTH_BYTES, chunk->len, NULL, 0);
|
||||
|
||||
if (memcmp(hash, chunk->buf + CLEN_BYTES, HASH_BYTES) != 0) 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;
|
||||
}
|
||||
}
|
||||
|
||||
*buf_ptr = buf;
|
||||
*buf_len = j;
|
||||
*hash_idx = cidx;
|
||||
chunk->idx = cidx;
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *ss_gen_hash(char *buf, ssize_t *buf_len, char *hash_buf, ssize_t *hash_idx, int buf_size)
|
||||
char *ss_gen_hash(char *buf, ssize_t *buf_len, int buf_size)
|
||||
{
|
||||
int i, j;
|
||||
ssize_t blen = *buf_len;
|
||||
ssize_t cidx = *hash_idx;
|
||||
int size = max((blen / HASH_BUF_LEN + 1) * HASH_BYTES + blen, buf_size);
|
||||
int size = max(AUTH_BYTES + blen, buf_size);
|
||||
|
||||
if (buf_size < size) {
|
||||
buf = realloc(buf, size);
|
||||
}
|
||||
for (i = 0, j = 0; i < blen; i++, j++) {
|
||||
if (cidx == HASH_BUF_LEN) {
|
||||
uint8_t hash[HASH_BYTES];
|
||||
crypto_generichash(hash, HASH_BYTES, (uint8_t *)hash_buf, HASH_BUF_LEN, NULL, 0);
|
||||
memmove(buf + j + HASH_BYTES, buf + j, blen - i);
|
||||
memcpy(buf + j, hash, HASH_BYTES);
|
||||
j += HASH_BYTES; cidx = 0;
|
||||
}
|
||||
hash_buf[cidx] = buf[j];
|
||||
cidx++;
|
||||
}
|
||||
*buf_len = j;
|
||||
*hash_idx = cidx;
|
||||
|
||||
uint16_t chunk_len = htons((uint16_t)blen);
|
||||
uint8_t hash[HASH_BYTES];
|
||||
crypto_generichash(hash, HASH_BYTES, (uint8_t *)buf, blen, NULL, 0);
|
||||
|
||||
memmove(buf + AUTH_BYTES, buf, blen);
|
||||
memcpy(buf + CLEN_BYTES, hash, HASH_BYTES);
|
||||
memcpy(buf, &chunk_len, CLEN_BYTES);
|
||||
|
||||
*buf_len = blen + AUTH_BYTES;
|
||||
return buf;
|
||||
}
|
||||
|
||||
+10
-3
@@ -146,12 +146,19 @@ typedef struct {
|
||||
#define ONETIMEAUTH_FLAG 0x10
|
||||
#define ADDRTYPE_MASK 0xF
|
||||
|
||||
#define HASH_BUF_LEN 128
|
||||
#define HASH_BYTES 4
|
||||
#define CLEN_BYTES 2
|
||||
#define AUTH_BYTES (HASH_BYTES + CLEN_BYTES)
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
struct chunk {
|
||||
uint32_t idx;
|
||||
uint32_t len;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
struct enc_ctx {
|
||||
uint8_t init;
|
||||
uint64_t counter;
|
||||
@@ -173,7 +180,7 @@ unsigned char *enc_md5(const unsigned char *d, size_t n, unsigned char *md);
|
||||
int ss_onetimeauth(char *auth, char *msg, int msg_len, struct enc_ctx *ctx);
|
||||
int ss_onetimeauth_verify(char *auth, char *msg, int msg_len, struct enc_ctx *ctx);
|
||||
|
||||
int ss_check_hash(char *buf, ssize_t *buf_len, char *hash_buf, ssize_t *hash_idx);
|
||||
char * ss_gen_hash(char *buf, ssize_t *buf_len, char *hash_buf, ssize_t *hash_idx, int buf_size);
|
||||
int ss_check_hash(char **buf_ptr, ssize_t *buf_len, struct chunk *chunk, int buf_size);
|
||||
char *ss_gen_hash(char *buf, ssize_t *buf_len, int buf_size);
|
||||
|
||||
#endif // _ENCRYPT_H
|
||||
|
||||
+4
-5
@@ -245,7 +245,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
|
||||
if (!remote->direct && remote->send_ctx->connected && auth) {
|
||||
remote->buf = ss_gen_hash(remote->buf, &r, remote->hash_buf, &remote->hash_idx, BUF_SIZE);
|
||||
remote->buf = ss_gen_hash(remote->buf, &r, BUF_SIZE);
|
||||
}
|
||||
|
||||
// insert shadowsocks header
|
||||
@@ -483,11 +483,10 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
memcpy(remote->buf, ss_addr_to_send, addr_len);
|
||||
|
||||
if (auth) {
|
||||
buf = ss_gen_hash(buf, &r, remote->hash_buf, &remote->hash_idx, BUF_SIZE);
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
if (auth) {
|
||||
buf = ss_gen_hash(buf, &r, BUF_SIZE);
|
||||
}
|
||||
memcpy(remote->buf + addr_len, buf, r);
|
||||
}
|
||||
r += addr_len;
|
||||
|
||||
@@ -81,9 +81,6 @@ struct remote {
|
||||
struct server *server;
|
||||
struct sockaddr_storage addr;
|
||||
int addr_len;
|
||||
|
||||
ssize_t hash_idx;
|
||||
char hash_buf[HASH_BUF_LEN];
|
||||
};
|
||||
|
||||
#endif // _LOCAL_H
|
||||
|
||||
+1
-1
@@ -185,7 +185,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
remote->buf = ss_gen_hash(remote->buf, &r, remote->hash_buf, &remote->hash_idx, BUF_SIZE);
|
||||
remote->buf = ss_gen_hash(remote->buf, &r, BUF_SIZE);
|
||||
}
|
||||
|
||||
remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx);
|
||||
|
||||
@@ -70,9 +70,6 @@ struct remote {
|
||||
struct remote_ctx *recv_ctx;
|
||||
struct remote_ctx *send_ctx;
|
||||
struct server *server;
|
||||
|
||||
ssize_t hash_idx;
|
||||
char hash_buf[HASH_BUF_LEN];
|
||||
};
|
||||
|
||||
#endif // _LOCAL_H
|
||||
|
||||
+20
-13
@@ -495,8 +495,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
// handshake and transmit data
|
||||
if (server->stage == 5) {
|
||||
if (server->auth
|
||||
&& !ss_check_hash(remote->buf, &r, server->hash_buf, &server->hash_idx)) {
|
||||
if (server->auth && !ss_check_hash(&remote->buf, &r, server->chunk, BUF_SIZE)) {
|
||||
LOGE("hash error");
|
||||
report_addr(server->fd);
|
||||
close_and_free_server(EV_A_ server);
|
||||
@@ -541,13 +540,13 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
*/
|
||||
|
||||
/*
|
||||
* Shadowsocks TCP Request Payload CRC (Optional, no hash check for response's payload):
|
||||
* Shadowsocks TCP Request Chunk (Optional, no hash check for response's payload):
|
||||
*
|
||||
* +------+---------+------+---------+------+
|
||||
* | DATA | BLAKE2b | DATA | BLAKE2b | ...
|
||||
* +------+---------+------+---------+------+
|
||||
* | 128 | 4 | 128 | 4 | ...
|
||||
* +------+---------+------+---------+------+
|
||||
* +------+---------+-------------+------+
|
||||
* | LEN | BLAKE2b | DATA | ...
|
||||
* +------+---------+-------------+------+
|
||||
* | 2 | 4 | Variable | ...
|
||||
* +------+---------+-------------+------+
|
||||
*/
|
||||
|
||||
int offset = 0;
|
||||
@@ -680,11 +679,10 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
// XXX: should handle buffer carefully
|
||||
if (r > offset) {
|
||||
server->buf_len = r - offset;
|
||||
server->buf_idx = offset;
|
||||
memmove(server->buf, server->buf + offset, server->buf_len);
|
||||
}
|
||||
|
||||
if (server->auth
|
||||
&& !ss_check_hash(server->buf + server->buf_idx, &server->buf_len, server->hash_buf, &server->hash_idx)) {
|
||||
if (server->auth && !ss_check_hash(&server->buf, &server->buf_len, server->chunk, BUF_SIZE)) {
|
||||
LOGE("hash error");
|
||||
report_addr(server->fd);
|
||||
close_and_free_server(EV_A_ server);
|
||||
@@ -704,8 +702,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
|
||||
// XXX: should handle buffer carefully
|
||||
if (server->buf_len > 0) {
|
||||
memcpy(remote->buf, server->buf + server->buf_idx,
|
||||
server->buf_len);
|
||||
memcpy(remote->buf, server->buf + server->buf_idx, server->buf_len);
|
||||
remote->buf_len = server->buf_len;
|
||||
remote->buf_idx = 0;
|
||||
server->buf_len = 0;
|
||||
@@ -1123,6 +1120,9 @@ static struct server * new_server(int fd, struct listen_ctx *listener)
|
||||
server->buf_idx = 0;
|
||||
server->remote = NULL;
|
||||
|
||||
server->chunk = (struct chunk *)malloc(sizeof(struct chunk));
|
||||
memset(server->chunk, 0, sizeof(struct chunk));
|
||||
|
||||
cork_dllist_add(&connections, &server->entries);
|
||||
|
||||
return server;
|
||||
@@ -1132,6 +1132,13 @@ static void free_server(struct server *server)
|
||||
{
|
||||
cork_dllist_remove(&server->entries);
|
||||
|
||||
if (server->chunk != NULL) {
|
||||
if (server->chunk->buf != NULL) {
|
||||
free(server->chunk->buf);
|
||||
}
|
||||
free(server->chunk);
|
||||
server->chunk = NULL;
|
||||
}
|
||||
if (server->remote != NULL) {
|
||||
server->remote->server = NULL;
|
||||
}
|
||||
|
||||
+1
-2
@@ -57,8 +57,7 @@ struct server {
|
||||
char *buf; // server send from, remote recv into
|
||||
|
||||
int auth;
|
||||
ssize_t hash_idx;
|
||||
char hash_buf[HASH_BUF_LEN + HASH_BYTES]; // 2 bytes for HASH16
|
||||
struct chunk *chunk;
|
||||
|
||||
struct enc_ctx *e_ctx;
|
||||
struct enc_ctx *d_ctx;
|
||||
|
||||
+1
-1
@@ -197,7 +197,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
|
||||
}
|
||||
|
||||
if (auth) {
|
||||
remote->buf = ss_gen_hash(remote->buf, &r, remote->hash_buf, &remote->hash_idx, BUF_SIZE);
|
||||
remote->buf = ss_gen_hash(remote->buf, &r, BUF_SIZE);
|
||||
}
|
||||
|
||||
remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx);
|
||||
|
||||
@@ -74,9 +74,6 @@ struct remote {
|
||||
struct remote_ctx *recv_ctx;
|
||||
struct remote_ctx *send_ctx;
|
||||
struct server *server;
|
||||
|
||||
ssize_t hash_idx;
|
||||
char hash_buf[HASH_BUF_LEN];
|
||||
};
|
||||
|
||||
#endif // _TUNNEL_H
|
||||
|
||||
Reference in New Issue
Block a user