Browse Source

Refine the authentication for true CCA

pull/405/head
Max Lv 9 years ago
parent
commit
1e10661a51
10 changed files with 92 additions and 65 deletions
  1. 86
      src/encrypt.c
  2. 13
      src/encrypt.h
  3. 9
      src/local.c
  4. 3
      src/local.h
  5. 2
      src/redir.c
  6. 3
      src/redir.h
  7. 33
      src/server.c
  8. 3
      src/server.h
  9. 2
      src/tunnel.c
  10. 3
      src/tunnel.h

86
src/encrypt.c

@ -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;
}

13
src/encrypt.h

@ -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

9
src/local.c

@ -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;

3
src/local.h

@ -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

2
src/redir.c

@ -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);

3
src/redir.h

@ -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

33
src/server.c

@ -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;
}

3
src/server.h

@ -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;

2
src/tunnel.c

@ -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);

3
src/tunnel.h

@ -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
Loading…
Cancel
Save