Browse Source

add CRC8 for payload authentication

pull/399/head
Max Lv 9 years ago
parent
commit
9e021aa919
10 changed files with 131 additions and 0 deletions
  1. 67
      src/encrypt.c
  2. 5
      src/encrypt.h
  3. 9
      src/local.c
  4. 3
      src/local.h
  5. 9
      src/redir.c
  6. 3
      src/redir.h
  7. 20
      src/server.c
  8. 5
      src/server.h
  9. 7
      src/tunnel.c
  10. 3
      src/tunnel.h

67
src/encrypt.c

@ -1462,3 +1462,70 @@ int enc_init(const char *pass, const char *method)
return m;
}
/*
* Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A table-based
* algorithm would be faster, but for only a few bytes it isn't worth the code
* size.
*/
uint8_t crc8(const void *vptr, int len)
{
const uint8_t *data = vptr;
unsigned crc = 0;
int i, j;
for (j = len; j; j--, data++) {
crc ^= (*data << 8);
for(i = 8; i; i--) {
if (crc & 0x8000)
crc ^= (0x1070 << 3);
crc <<= 1;
}
}
return (uint8_t)(crc >> 8);
}
int ss_check_crc(char *buf, ssize_t *buf_len, char *crc_buf, ssize_t *crc_idx)
{
int i, j;
ssize_t blen = *buf_len;
ssize_t cidx = *crc_idx;
for (i = 0, j = 0; i < blen; i++) {
if (cidx == CRC_BUF_LEN) {
uint8_t c = crc8((const void*)crc_buf, CRC_BUF_LEN);
if (memcmp(&c, buf + i, 1) != 0) return 0;
cidx = 0;
} else {
crc_buf[cidx] = buf[j] = buf[i];
cidx++; j++;
}
}
*buf_len = j;
*crc_idx = cidx;
return 1;
}
void ss_gen_crc(char *buf, ssize_t *buf_len, char *crc_buf, ssize_t *crc_idx, int buf_size)
{
int i, j;
ssize_t blen = *buf_len;
ssize_t cidx = *crc_idx;
int size = max(blen / CRC_BUF_LEN + blen, buf_size);
if (buf_size < size) {
buf = realloc(buf, size);
}
for (i = 0, j = 0; i < blen; i++, j++) {
if (cidx == CRC_BUF_LEN) {
uint8_t c = crc8((const void*)crc_buf, CRC_BUF_LEN);
memmove(buf + j + 1, buf + j, blen - i);
memcpy(buf + j, &c, 1);
j++; cidx = 0;
}
crc_buf[cidx] = buf[j];
cidx++;
}
*buf_len = j;
*crc_idx = cidx;
}

5
src/encrypt.h

@ -147,6 +147,8 @@ typedef struct {
#define ONETIMEAUTH_MASK 0xF0
#define ADDRTYPE_MASK 0xF
#define CRC_BUF_LEN 128
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define max(a, b) (((a) > (b)) ? (a) : (b))
@ -171,4 +173,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);
int ss_onetimeauth_verify(char *auth, char *msg, int msg_len);
int ss_check_crc(char *buf, ssize_t *buf_len, char *crc_buf, ssize_t *crc_idx);
void ss_gen_crc(char *buf, ssize_t *buf_len, char *crc_buf, ssize_t *crc_idx, int buf_size);
#endif // _ENCRYPT_H

9
src/local.c

@ -244,6 +244,10 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
return;
}
if (remote->send_ctx->connected && auth) {
ss_gen_crc(remote->buf, &r, remote->crc_buf, &remote->crc_idx, BUF_SIZE);
}
// insert shadowsocks header
if (!remote->direct) {
remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r,
@ -478,6 +482,11 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
}
memcpy(remote->buf, ss_addr_to_send, addr_len);
if (auth) {
ss_gen_crc(buf, &r, remote->crc_buf, &remote->crc_idx, BUF_SIZE);
}
if (r > 0) {
memcpy(remote->buf + addr_len, buf, r);
}

3
src/local.h

@ -81,6 +81,9 @@ struct remote {
struct server *server;
struct sockaddr_storage addr;
int addr_len;
ssize_t crc_idx;
char crc_buf[CRC_BUF_LEN];
};
#endif // _LOCAL_H

9
src/redir.c

@ -184,7 +184,12 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
}
}
if (auth) {
ss_gen_crc(remote->buf, &r, remote->crc_buf, &remote->crc_idx, BUF_SIZE);
}
remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx);
if (remote->buf == NULL) {
LOGE("invalid password or cipher");
close_and_free_remote(EV_A_ remote);
@ -193,6 +198,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
}
int s = send(remote->fd, remote->buf, r, 0);
if (s == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
// no data, wait for send
@ -444,6 +450,9 @@ static struct remote * new_remote(int fd, int timeout)
{
struct remote *remote;
remote = malloc(sizeof(struct remote));
memset(remote, 0, sizeof(struct remote));
remote->buf = malloc(BUF_SIZE);
remote->recv_ctx = malloc(sizeof(struct remote_ctx));
remote->send_ctx = malloc(sizeof(struct remote_ctx));

3
src/redir.h

@ -70,6 +70,9 @@ struct remote {
struct remote_ctx *recv_ctx;
struct remote_ctx *send_ctx;
struct server *server;
ssize_t crc_idx;
char crc_buf[CRC_BUF_LEN];
};
#endif // _LOCAL_H

20
src/server.c

@ -495,6 +495,14 @@ 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_crc(remote->buf, &r, server->crc_buf, &server->crc_idx)) {
LOGE("crc error");
report_addr(server->fd);
close_and_free_server(EV_A_ server);
close_and_free_remote(EV_A_ remote);
return;
}
int s = send(remote->fd, remote->buf, r, 0);
if (s == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
@ -648,6 +656,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
return;
};
offset += ONETIMEAUTH_BYTES;
server->auth = 1;
}
if (verbose) {
@ -660,6 +669,14 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
server->buf_idx = offset;
}
if (server->auth
&& !ss_check_crc(server->buf + server->buf_idx, &server->buf_len, server->crc_buf, &server->crc_idx)) {
LOGE("crc error");
report_addr(server->fd);
close_and_free_server(EV_A_ server);
return;
}
if (!need_query) {
struct remote *remote = connect_to_remote(&info, server);
@ -1061,6 +1078,9 @@ static struct server * new_server(int fd, struct listen_ctx *listener)
struct server *server;
server = malloc(sizeof(struct server));
memset(server, 0, sizeof(struct server));
server->buf = malloc(BUF_SIZE);
server->recv_ctx = malloc(sizeof(struct server_ctx));
server->send_ctx = malloc(sizeof(struct server_ctx));

5
src/server.h

@ -55,6 +55,11 @@ struct server {
ssize_t buf_len;
ssize_t buf_idx;
char *buf; // server send from, remote recv into
int auth;
ssize_t crc_idx;
char crc_buf[CRC_BUF_LEN];
struct enc_ctx *e_ctx;
struct enc_ctx *d_ctx;
struct server_ctx *recv_ctx;

7
src/tunnel.c

@ -196,6 +196,10 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents)
}
}
if (auth) {
ss_gen_crc(remote->buf, &r, remote->crc_buf, &remote->crc_idx, BUF_SIZE);
}
remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx);
if (remote->buf == NULL) {
@ -485,6 +489,9 @@ static struct remote * new_remote(int fd, int timeout)
{
struct remote *remote;
remote = malloc(sizeof(struct remote));
memset(remote, 0, sizeof(struct remote));
remote->buf = malloc(BUF_SIZE);
remote->recv_ctx = malloc(sizeof(struct remote_ctx));
remote->send_ctx = malloc(sizeof(struct remote_ctx));

3
src/tunnel.h

@ -74,6 +74,9 @@ struct remote {
struct remote_ctx *recv_ctx;
struct remote_ctx *send_ctx;
struct server *server;
ssize_t crc_idx;
char crc_buf[CRC_BUF_LEN];
};
#endif // _TUNNEL_H
Loading…
Cancel
Save