int ss_check_hash(buffer_t *buf, chunk_t *chunk, enc_ctx_t *ctx) { int i, j, k; ssize_t blen = buf->len; uint32_t cidx = chunk->idx; brealloc(chunk->buf, chunk->len + blen, buf->capacity); brealloc(buf, chunk->len + blen, buf->capacity); for (i = 0, j = 0, k = 0; i < blen; i++) { chunk->buf->array[cidx++] = buf->array[k++]; if (cidx == CLEN_BYTES) { uint16_t clen = ntohs(*((uint16_t *)chunk->buf->array)); brealloc(chunk->buf, clen + AUTH_BYTES, buf->capacity); 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->array + AUTH_BYTES, chunk->len, hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), key, enc_iv_len + sizeof(uint32_t), (uint8_t *)chunk->buf->array + AUTH_BYTES, chunk->len, hash); #else sha1_hmac(key, enc_iv_len + sizeof(uint32_t), (uint8_t *)chunk->buf->array + AUTH_BYTES, chunk->len, hash); #endif if (safe_memcmp(hash, chunk->buf->array + CLEN_BYTES, ONETIMEAUTH_BYTES) != 0) { return 0; } // Copy chunk back to buffer memmove(buf->array + j + chunk->len, buf->array + k, blen - i - 1); memcpy(buf->array + j, chunk->buf->array + AUTH_BYTES, chunk->len); // Reset the base offset j += chunk->len; k = j; cidx = 0; chunk->counter++; } } buf->len = j; chunk->idx = cidx; return 1; }
static int obfs_tls_response(buffer_t *buf, size_t cap, obfs_t *obfs) { if (obfs == NULL || obfs->obfs_stage < 0) return 0; static buffer_t tmp = { 0, 0, 0, NULL }; if (obfs->obfs_stage == 0) { size_t buf_len = buf->len; size_t hello_len = sizeof(struct tls_server_hello); size_t change_cipher_spec_len = sizeof(struct tls_change_cipher_spec); size_t encrypted_handshake_len = sizeof(struct tls_encrypted_handshake); size_t tls_len = hello_len + change_cipher_spec_len + encrypted_handshake_len + buf_len; brealloc(&tmp, buf_len, cap); brealloc(buf, tls_len, cap); memcpy(tmp.data, buf->data, buf_len); /* Server Hello */ memcpy(buf->data, &tls_server_hello_template, hello_len); struct tls_server_hello *hello = (struct tls_server_hello *)buf->data; hello->random_unix_time = CT_HTONL((uint32_t)time(NULL)); rand_bytes(hello->random_bytes, 28); if (obfs->buf != NULL) { memcpy(hello->session_id, obfs->buf->data, 32); } else { rand_bytes(hello->session_id, 32); } /* Change Cipher Spec */ memcpy(buf->data + hello_len, &tls_change_cipher_spec_template, change_cipher_spec_len); /* Encrypted Handshake */ memcpy(buf->data + hello_len + change_cipher_spec_len, &tls_encrypted_handshake_template, encrypted_handshake_len); memcpy(buf->data + hello_len + change_cipher_spec_len + encrypted_handshake_len, tmp.data, buf_len); struct tls_encrypted_handshake *encrypted_handshake = (struct tls_encrypted_handshake *)(buf->data + hello_len + change_cipher_spec_len); encrypted_handshake->len = CT_HTONS(buf_len); buf->len = tls_len; obfs->obfs_stage++; } else if (obfs->obfs_stage == 1) { obfs_app_data(buf, cap, obfs); } return buf->len; }
static bool grow_del_list(struct del_ctx *del) { if (del->num_ids == MAX_DEL_LIST_LEN) { return false; } if (del->num_ids == del->max_ids) { del->max_ids = (del->max_ids * 3) / 2; del->JobId = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) * del->max_ids); del->PurgedFiles = (char *)brealloc(del->PurgedFiles, del->max_ids); } return true; }
int aead_decrypt_all(buffer_t *ciphertext, cipher_t *cipher, size_t capacity) { size_t salt_len = cipher->key_len; size_t tag_len = cipher->tag_len; int err = CRYPTO_OK; if (ciphertext->len <= salt_len + tag_len) { return CRYPTO_ERROR; } cipher_ctx_t cipher_ctx; aead_ctx_init(cipher, &cipher_ctx, 0); static buffer_t tmp = { 0, 0, 0, NULL }; brealloc(&tmp, ciphertext->len, capacity); buffer_t *plaintext = &tmp; plaintext->len = ciphertext->len - salt_len - tag_len; /* get salt */ uint8_t *salt = cipher_ctx.salt; memcpy(salt, ciphertext->data, salt_len); if (ppbloom_check((void *)salt, salt_len) == 1) { LOGE("crypto: AEAD: repeat salt detected"); return CRYPTO_ERROR; } aead_cipher_ctx_set_key(&cipher_ctx, 0); size_t plen = plaintext->len; err = aead_cipher_decrypt(&cipher_ctx, (uint8_t *)plaintext->data, &plen, (uint8_t *)ciphertext->data + salt_len, ciphertext->len - salt_len, NULL, 0, cipher_ctx.nonce, cipher_ctx.skey); aead_ctx_release(&cipher_ctx); if (err) return CRYPTO_ERROR; ppbloom_add((void *)salt, salt_len); brealloc(ciphertext, plaintext->len, capacity); memcpy(ciphertext->data, plaintext->data, plaintext->len); ciphertext->len = plaintext->len; return CRYPTO_OK; }
/* TCP */ int aead_encrypt(buffer_t *plaintext, cipher_ctx_t *cipher_ctx, size_t capacity) { if (cipher_ctx == NULL) return CRYPTO_ERROR; if (plaintext->len == 0) { return CRYPTO_OK; } static buffer_t tmp = { 0, 0, 0, NULL }; buffer_t *ciphertext; cipher_t *cipher = cipher_ctx->cipher; int err = CRYPTO_ERROR; size_t salt_ofst = 0; size_t salt_len = cipher->key_len; size_t tag_len = cipher->tag_len; if (!cipher_ctx->init) { salt_ofst = salt_len; } size_t out_len = salt_ofst + 2 * tag_len + plaintext->len + CHUNK_SIZE_LEN; brealloc(&tmp, out_len, capacity); ciphertext = &tmp; ciphertext->len = out_len; if (!cipher_ctx->init) { memcpy(ciphertext->data, cipher_ctx->salt, salt_len); aead_cipher_ctx_set_key(cipher_ctx, 1); cipher_ctx->init = 1; ppbloom_add((void *)cipher_ctx->salt, salt_len); } err = aead_chunk_encrypt(cipher_ctx, (uint8_t *)plaintext->data, (uint8_t *)ciphertext->data + salt_ofst, cipher_ctx->nonce, plaintext->len); if (err) return err; brealloc(plaintext, ciphertext->len, capacity); memcpy(plaintext->data, ciphertext->data, ciphertext->len); plaintext->len = ciphertext->len; return 0; }
static inline bool cd_ensure_capacity(calldata_t *data, uint8_t **pos, size_t new_size) { size_t offset; size_t new_capacity; if (new_size < data->capacity) return true; if (data->fixed) { blog(LOG_ERROR, "Tried to go above fixed calldata stack size!"); return false; } offset = *pos - data->stack; new_capacity = data->capacity * 2; if (new_capacity < new_size) new_capacity = new_size; data->stack = brealloc(data->stack, new_capacity); data->capacity = new_capacity; *pos = data->stack + offset; return true; }
int ss_onetimeauth(buffer_t *buf, uint8_t *iv, size_t capacity) { 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); brealloc(buf, ONETIMEAUTH_BYTES + buf->len, capacity); #if defined(USE_CRYPTO_OPENSSL) HMAC(EVP_sha1(), auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, buf->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 *)buf->array, buf->len, (uint8_t *)hash); #else sha1_hmac(auth_key, enc_iv_len + enc_key_len, (uint8_t *)buf->array, buf->len, (uint8_t *)hash); #endif memcpy(buf->array + buf->len, hash, ONETIMEAUTH_BYTES); buf->len += ONETIMEAUTH_BYTES; return 0; }
/* external function definitions */ void buffroom(struct buff * p, int add) { int def; /* space deficiency */ if ((p != (struct buff *) (0)) && ((def = add - (p->max - p->put)) > 0)) { int len = p->put - p->get; int off = p->get - p->min; if (def > off) { /* deficiency is more than the offset */ int siz = p->max - p->min; int req = siz + def; siz += siz / 2; if (siz < req) siz = req; if (siz < sizeof(*p)) siz = sizeof(*p); p->min = (char *) brealloc(p->min, siz); p->get = p->min + off; p->put = p->get + len; p->max = p->min + siz; } else { bcopy(p->get, p->min, len); p->get -= off; p->put -= off; } } return; }
char *read_line(HANDLE hin) { char *buf; int bufsize = 32, strind = 0; DWORD bytes_read; buf = bmalloc(bufsize); while (1) { if (!ReadFile(hin, &buf[strind], 1, &bytes_read, NULL)) { printf("Read error\n"); break; } if (bytes_read == 0) { buf[strind] = '\0'; break; } else if (buf[strind] == '\r') continue; else if (buf[strind] == '\n') { buf[strind++] = '\0'; break; } else { strind++; if (strind >= bufsize) { bufsize *= 2; buf = brealloc(buf, bufsize); } } } if (strind == 0) { bfree(buf); return NULL; } else return buf; }
static int inputGetc(ej_t* ep) { ejinput_t *ip; int c, len; a_assert(ep); ip = ep->input; if ((len = ringqLen(&ip->script)) == 0) { return -1; } c = ringqGetc(&ip->script); if (c == '\n') { ip->lineNumber++; ip->lineColumn = 0; } else { if ((ip->lineColumn + 2) >= ip->lineLength) { ip->lineLength += EJ_INC; ip->line = brealloc(B_L, ip->line, ip->lineLength * sizeof(char_t)); } ip->line[ip->lineColumn++] = c; ip->line[ip->lineColumn] = '\0'; } return c; }
int ss_gen_hash(buffer_t *buf, uint32_t *counter, enc_ctx_t *ctx, size_t capacity) { ssize_t blen = buf->len; 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); brealloc(buf, AUTH_BYTES + blen, capacity); 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->array, blen, hash, NULL); #elif defined(USE_CRYPTO_MBEDTLS) mbedtls_md_hmac(mbedtls_md_info_from_type( MBEDTLS_MD_SHA1), key, enc_iv_len + sizeof(uint32_t), (uint8_t *)buf->array, blen, hash); #else sha1_hmac(key, enc_iv_len + sizeof(uint32_t), (uint8_t *)buf->array, blen, hash); #endif memmove(buf->array + AUTH_BYTES, buf->array, blen); memcpy(buf->array + CLEN_BYTES, hash, ONETIMEAUTH_BYTES); memcpy(buf->array, &chunk_len, CLEN_BYTES); *counter = *counter + 1; buf->len = blen + AUTH_BYTES; return 0; }
int stream_encrypt_all(buffer_t *plaintext, cipher_t *cipher, size_t capacity) { cipher_ctx_t cipher_ctx; stream_ctx_init(cipher, &cipher_ctx, 1); size_t nonce_len = cipher->nonce_len; int err = CRYPTO_OK; static buffer_t tmp = { 0, 0, 0, NULL }; brealloc(&tmp, nonce_len + plaintext->len, capacity); buffer_t *ciphertext = &tmp; ciphertext->len = plaintext->len; uint8_t *nonce = cipher_ctx.nonce; cipher_ctx_set_nonce(&cipher_ctx, nonce, nonce_len, 1); memcpy(ciphertext->data, nonce, nonce_len); if (cipher->method >= SALSA20) { crypto_stream_xor_ic((uint8_t *)(ciphertext->data + nonce_len), (const uint8_t *)plaintext->data, (uint64_t)(plaintext->len), (const uint8_t *)nonce, 0, cipher->key, cipher->method); } else { err = cipher_ctx_update(&cipher_ctx, (uint8_t *)(ciphertext->data + nonce_len), &ciphertext->len, (const uint8_t *)plaintext->data, plaintext->len); } stream_ctx_release(&cipher_ctx); if (err) return CRYPTO_ERROR; #ifdef SS_DEBUG dump("PLAIN", plaintext->data, plaintext->len); dump("CIPHER", ciphertext->data + nonce_len, ciphertext->len); dump("NONCE", ciphertext->data, nonce_len); #endif brealloc(plaintext, nonce_len + ciphertext->len, capacity); memcpy(plaintext->data, ciphertext->data, nonce_len + ciphertext->len); plaintext->len = nonce_len + ciphertext->len; return CRYPTO_OK; }
/* internal function definitions */ static void acpt(struct lstn * p) { static char fnc[] = "acpt"; int r_namelen = p->r_namelen; struct sockaddr *r_name; int fd; int l_namelen = p->l_namelen; struct sockaddr *l_name; r_name = (struct sockaddr *) balloc(r_namelen); if ((fd = accept(p->fd, r_name, &r_namelen)) < 0) { if ((errno == EWOULDBLOCK) || (errno == EINTR)) { /* nothing to report */ } else if ((errno == EMFILE) || (errno == ENFILE) || (errno == ENXIO) || (errno == EIO)) { Warn("%t %s(%s): warn: accept(%d): %m\n", fnc, p->name, p->fd); } else { Warn("%t %s(%s): error: accept(%d): %m\n", fnc, p->name, p->fd); lstnclose(p); } bfree((char *) r_name); return; } l_name = (struct sockaddr *) balloc(l_namelen); if (getsockname(fd, l_name, &l_namelen) < 0) { Warn("%t %s(%s): error: getsockname(%d): %m\n", fnc, p->name, fd); doclose(fd); bfree((char *) l_name); bfree((char *) r_name); return; } p->acpttod = todsec(); (p->acptcount)++; r_name = (struct sockaddr *) brealloc((char *) r_name, r_namelen); l_name = (struct sockaddr *) brealloc((char *) l_name, l_namelen); (*(p->acptfunc)) (p, fd, r_name, r_namelen, l_name, l_namelen); return; }
/* * Called here to make in memory list of JobIds to be * deleted and the associated PurgedFiles flag. * The in memory list will then be transversed * to issue the SQL DELETE commands. Note, the list * is allowed to get to MAX_DEL_LIST_LEN to limit the * maximum malloc'ed memory. */ int job_delete_handler(void *ctx, int num_fields, char **row) { struct del_ctx *del = (struct del_ctx *)ctx; if (del->num_ids == MAX_DEL_LIST_LEN) { return 1; } if (del->num_ids == del->max_ids) { del->max_ids = (del->max_ids * 3) / 2; del->JobId = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) * del->max_ids); del->PurgedFiles = (char *)brealloc(del->PurgedFiles, del->max_ids); } del->JobId[del->num_ids] = (JobId_t)str_to_int64(row[0]); // Dmsg2(60, "row=%d val=%d\n", del->num_ids, del->JobId[del->num_ids]); del->PurgedFiles[del->num_ids++] = (char)str_to_int64(row[1]); return 0; }
int bprepend(buffer_t *dst, buffer_t *src, size_t capacity) { brealloc(dst, dst->len + src->len, capacity); memmove(dst->data + src->len, dst->data, dst->len); memcpy(dst->data, src->data, src->len); dst->len = dst->len + src->len; return dst->len; }
void bstr_expandby(bstr *str, unsigned extralength) { if (str->bufsiz >= str->length + 1 + extralength) return; while (str->bufsiz < str->length + 1 + extralength) str->bufsiz *= 2; str->text = brealloc(str->text, str->bufsiz); }
static __inline void array_grow(struct array *array, size_t newsize) { size_t i; array->data = brealloc(array->data, newsize * sizeof(*array->data)); for (i = array->size; i < newsize; i++) array->data[i].array = NULL; array->size = newsize; }
int main() { binit(); char* a = bmalloc(20); printf("%d\n", (int)a); a = brealloc(a, 40); printf("%d\n", (int)a); bfree(a); blame(); return 0; }
int aead_encrypt_all(buffer_t *plaintext, cipher_t *cipher, size_t capacity) { cipher_ctx_t cipher_ctx; aead_ctx_init(cipher, &cipher_ctx, 1); size_t salt_len = cipher->key_len; size_t tag_len = cipher->tag_len; int err = CRYPTO_OK; static buffer_t tmp = { 0, 0, 0, NULL }; brealloc(&tmp, salt_len + tag_len + plaintext->len, capacity); buffer_t *ciphertext = &tmp; ciphertext->len = tag_len + plaintext->len; /* copy salt to first pos */ memcpy(ciphertext->data, cipher_ctx.salt, salt_len); ppbloom_add((void *)cipher_ctx.salt, salt_len); aead_cipher_ctx_set_key(&cipher_ctx, 1); size_t clen = ciphertext->len; err = aead_cipher_encrypt(&cipher_ctx, (uint8_t *)ciphertext->data + salt_len, &clen, (uint8_t *)plaintext->data, plaintext->len, NULL, 0, cipher_ctx.nonce, cipher_ctx.skey); aead_ctx_release(&cipher_ctx); if (err) return CRYPTO_ERROR; assert(ciphertext->len == clen); brealloc(plaintext, salt_len + ciphertext->len, capacity); memcpy(plaintext->data, ciphertext->data, salt_len + ciphertext->len); plaintext->len = salt_len + ciphertext->len; return CRYPTO_OK; }
static inline void copy_data(struct ffmpeg_decode *decode, uint8_t *data, size_t size) { size_t new_size = size + FF_INPUT_BUFFER_PADDING_SIZE; if (decode->packet_size < new_size) { decode->packet_buffer = brealloc(decode->packet_buffer, new_size); } memset(decode->packet_buffer + size, 0, FF_INPUT_BUFFER_PADDING_SIZE); memcpy(decode->packet_buffer, data, size); }
static void stack_grow(struct stack *stack) { int new_size, i; if (++stack->sp == stack->size) { new_size = stack->size * 2 + 1; stack->stack = brealloc(stack->stack, new_size * sizeof(*stack->stack)); for (i = stack->size; i < new_size; i++) stack->stack[i].array = NULL; stack->size = new_size; } }
/* * Add a new string to the output struct, resizing the string array as * necessary. Calls bail if memory allocation fails. */ void output_add(struct output *output, const char *string) { size_t next = output->count; size_t size; if (output->count == output->allocated) { size = output->allocated + 1; output->strings = brealloc(output->strings, size * sizeof(char *)); output->allocated = size; } output->strings[next] = bstrdup(string); output->count++; }
static int obfs_app_data(buffer_t *buf, size_t cap, obfs_t *obfs) { size_t buf_len = buf->len; brealloc(buf, buf_len + 5, cap); memmove(buf->data + 5, buf->data, buf_len); memcpy(buf->data, tls_data_header, 3); *(uint16_t*)(buf->data + 3) = CT_HTONS(buf_len); buf->len = buf_len + 5; return 0; }
/* * Called here to make in memory list of JobIds to be * deleted. The in memory list will then be transversed * to issue the SQL DELETE commands. Note, the list * is allowed to get to MAX_DEL_LIST_LEN to limit the * maximum malloc'ed memory. */ static int delete_handler(void *ctx, int num_fields, char **row) { struct s_del_ctx *del = (struct s_del_ctx *)ctx; if (del->num_ids == MAX_DEL_LIST_LEN) { return 1; } if (del->num_ids == del->max_ids) { del->max_ids = (del->max_ids * 3) / 2; del->JobId = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) * del->max_ids); } del->JobId[del->num_ids++] = (JobId_t)str_to_int64(row[0]); return 0; }
static inline void cd_ensure_capacity(calldata_t data, uint8_t **pos, size_t new_size) { size_t offset; size_t new_capacity; if (new_size < data->capacity) return; offset = *pos - data->stack; new_capacity = data->capacity * 2; if (new_capacity < new_size) new_capacity = new_size; data->stack = brealloc(data->stack, new_capacity); data->capacity = new_capacity; *pos = data->stack + offset; }
int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir, int arg, int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webdir, int arg, char_t *url, char_t *path, char_t *query), int flags) { websUrlHandlerType *sp; int len; a_assert(urlPrefix); a_assert(handler); /* * Grow the URL handler array to create a new slot */ len = (websUrlHandlerMax + 1) * sizeof(websUrlHandlerType); if ((websUrlHandler = brealloc(B_L, websUrlHandler, len)) == NULL) { return -1; } sp = &websUrlHandler[websUrlHandlerMax++]; memset(sp, 0, sizeof(websUrlHandlerType)); sp->urlPrefix = bstrdup(B_L, urlPrefix); sp->len = gstrlen(sp->urlPrefix); if (webDir) { sp->webDir = bstrdup(B_L, webDir); } else { sp->webDir = bstrdup(B_L, T("")); } sp->handler = handler; sp->arg = arg; sp->flags = flags; /* * Sort in decreasing URL length order observing the flags for first and last */ qsort(websUrlHandler, websUrlHandlerMax, sizeof(websUrlHandlerType), websUrlHandlerSort); return 0; }
char * read_string(struct source *src) { int count, i, sz, new_sz, ch; char *p; bool escape; escape = false; count = 1; i = 0; sz = 15; p = bmalloc(sz + 1); while ((ch = (*src->vtable->readchar)(src)) != EOF) { if (!escape) { if (ch == '[') count++; else if (ch == ']') count--; if (count == 0) break; } if (ch == '\\' && !escape) escape = true; else { escape = false; if (i == sz) { new_sz = sz * 2; p = brealloc(p, new_sz + 1); sz = new_sz; } p[i++] = ch; } } p[i] = '\0'; return p; }
static void remote_send_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w; remote_t *remote = remote_send_ctx->remote; server_t *server = remote->server; if (!remote_send_ctx->connected) { struct sockaddr_storage addr; socklen_t len = sizeof addr; int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); if (r == 0) { remote_send_ctx->connected = 1; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_stop(EV_A_ & server->recv_ctx->io); ev_timer_stop(EV_A_ & remote_send_ctx->watcher); ev_timer_start(EV_A_ & remote->recv_ctx->watcher); // send destaddr buffer_t ss_addr_to_send; buffer_t *abuf = &ss_addr_to_send; balloc(abuf, BUF_SIZE); if (server->hostname_len > 0) { // HTTP/SNI uint16_t port; if (AF_INET6 == server->destaddr.ss_family) { // IPv6 port = (((struct sockaddr_in6 *)&(server->destaddr))->sin6_port); } else { // IPv4 port = (((struct sockaddr_in *)&(server->destaddr))->sin_port); } abuf->array[abuf->len++] = 3; // Type 3 is hostname abuf->array[abuf->len++] = server->hostname_len; memcpy(abuf->array + abuf->len, server->hostname, server->hostname_len); abuf->len += server->hostname_len; memcpy(abuf->array + abuf->len, &port, 2); } else if (AF_INET6 == server->destaddr.ss_family) { // IPv6 abuf->array[abuf->len++] = 4; // Type 4 is IPv6 address size_t in6_addr_len = sizeof(struct in6_addr); memcpy(abuf->array + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_addr), in6_addr_len); abuf->len += in6_addr_len; memcpy(abuf->array + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port), 2); } else { // IPv4 abuf->array[abuf->len++] = 1; // Type 1 is IPv4 address size_t in_addr_len = sizeof(struct in_addr); memcpy(abuf->array + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_addr, in_addr_len); abuf->len += in_addr_len; memcpy(abuf->array + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_port, 2); } abuf->len += 2; if (auth) { abuf->array[0] |= ONETIMEAUTH_FLAG; ss_onetimeauth(abuf, server->e_ctx->evp.iv, BUF_SIZE); } brealloc(remote->buf, remote->buf->len + abuf->len, BUF_SIZE); memmove(remote->buf->array + abuf->len, remote->buf->array, remote->buf->len); memcpy(remote->buf->array, abuf->array, abuf->len); remote->buf->len += abuf->len; bfree(abuf); int err = ss_encrypt(remote->buf, server->e_ctx, BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } ev_io_start(EV_A_ & remote->recv_ctx->io); } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } if (remote->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(remote->fd, remote->buf->array + remote->buf->idx, remote->buf->len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf->len) { // partly sent, move memory, wait for the next time to send remote->buf->len -= s; remote->buf->idx += s; return; } else { // all sent out, wait for reading remote->buf->len = 0; remote->buf->idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); } } }
int stream_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity) { if (cipher_ctx == NULL) return CRYPTO_ERROR; cipher_t *cipher = cipher_ctx->cipher; static buffer_t tmp = { 0, 0, 0, NULL }; int err = CRYPTO_OK; brealloc(&tmp, ciphertext->len, capacity); buffer_t *plaintext = &tmp; plaintext->len = ciphertext->len; if (!cipher_ctx->init) { if (cipher_ctx->chunk == NULL) { cipher_ctx->chunk = (buffer_t *)ss_malloc(sizeof(buffer_t)); memset(cipher_ctx->chunk, 0, sizeof(buffer_t)); balloc(cipher_ctx->chunk, cipher->nonce_len); } size_t left_len = min(cipher->nonce_len - cipher_ctx->chunk->len, ciphertext->len); if (left_len > 0) { memcpy(cipher_ctx->chunk->data + cipher_ctx->chunk->len, ciphertext->data, left_len); memmove(ciphertext->data, ciphertext->data + left_len, ciphertext->len - left_len); cipher_ctx->chunk->len += left_len; ciphertext->len -= left_len; } if (cipher_ctx->chunk->len < cipher->nonce_len) return CRYPTO_NEED_MORE; uint8_t *nonce = cipher_ctx->nonce; size_t nonce_len = cipher->nonce_len; plaintext->len -= left_len; memcpy(nonce, cipher_ctx->chunk->data, nonce_len); cipher_ctx_set_nonce(cipher_ctx, nonce, nonce_len, 0); cipher_ctx->counter = 0; cipher_ctx->init = 1; if (cipher->method >= RC4_MD5) { if (ppbloom_check((void *)nonce, nonce_len) == 1) { LOGE("crypto: stream: repeat IV detected"); return CRYPTO_ERROR; } } } if (ciphertext->len <= 0) return CRYPTO_NEED_MORE; if (cipher->method >= SALSA20) { int padding = cipher_ctx->counter % SODIUM_BLOCK_SIZE; brealloc(plaintext, (plaintext->len + padding) * 2, capacity); if (padding) { brealloc(ciphertext, ciphertext->len + padding, capacity); memmove(ciphertext->data + padding, ciphertext->data, ciphertext->len); sodium_memzero(ciphertext->data, padding); } crypto_stream_xor_ic((uint8_t *)plaintext->data, (const uint8_t *)(ciphertext->data), (uint64_t)(ciphertext->len + padding), (const uint8_t *)cipher_ctx->nonce, cipher_ctx->counter / SODIUM_BLOCK_SIZE, cipher->key, cipher->method); cipher_ctx->counter += ciphertext->len; if (padding) { memmove(plaintext->data, plaintext->data + padding, plaintext->len); } } else { err = cipher_ctx_update(cipher_ctx, (uint8_t *)plaintext->data, &plaintext->len, (const uint8_t *)(ciphertext->data), ciphertext->len); } if (err) return CRYPTO_ERROR; #ifdef SS_DEBUG dump("PLAIN", plaintext->data, plaintext->len); dump("CIPHER", ciphertext->data, ciphertext->len); #endif brealloc(ciphertext, plaintext->len, capacity); memcpy(ciphertext->data, plaintext->data, plaintext->len); ciphertext->len = plaintext->len; // Add to bloom filter if (cipher_ctx->init == 1) { if (cipher->method >= RC4_MD5) { ppbloom_add((void *)cipher_ctx->nonce, cipher->nonce_len); cipher_ctx->init = 2; } } return CRYPTO_OK; }
int stream_encrypt(buffer_t *plaintext, cipher_ctx_t *cipher_ctx, size_t capacity) { if (cipher_ctx == NULL) return CRYPTO_ERROR; cipher_t *cipher = cipher_ctx->cipher; static buffer_t tmp = { 0, 0, 0, NULL }; int err = CRYPTO_OK; size_t nonce_len = 0; if (!cipher_ctx->init) { nonce_len = cipher_ctx->cipher->nonce_len; } brealloc(&tmp, nonce_len + plaintext->len, capacity); buffer_t *ciphertext = &tmp; ciphertext->len = plaintext->len; if (!cipher_ctx->init) { cipher_ctx_set_nonce(cipher_ctx, cipher_ctx->nonce, nonce_len, 1); memcpy(ciphertext->data, cipher_ctx->nonce, nonce_len); cipher_ctx->counter = 0; cipher_ctx->init = 1; } if (cipher->method >= SALSA20) { int padding = cipher_ctx->counter % SODIUM_BLOCK_SIZE; brealloc(ciphertext, nonce_len + (padding + ciphertext->len) * 2, capacity); if (padding) { brealloc(plaintext, plaintext->len + padding, capacity); memmove(plaintext->data + padding, plaintext->data, plaintext->len); sodium_memzero(plaintext->data, padding); } crypto_stream_xor_ic((uint8_t *)(ciphertext->data + nonce_len), (const uint8_t *)plaintext->data, (uint64_t)(plaintext->len + padding), (const uint8_t *)cipher_ctx->nonce, cipher_ctx->counter / SODIUM_BLOCK_SIZE, cipher->key, cipher->method); cipher_ctx->counter += plaintext->len; if (padding) { memmove(ciphertext->data + nonce_len, ciphertext->data + nonce_len + padding, ciphertext->len); } } else { err = cipher_ctx_update(cipher_ctx, (uint8_t *)(ciphertext->data + nonce_len), &ciphertext->len, (const uint8_t *)plaintext->data, plaintext->len); if (err) { return CRYPTO_ERROR; } } #ifdef SS_DEBUG dump("PLAIN", plaintext->data, plaintext->len); dump("CIPHER", ciphertext->data + nonce_len, ciphertext->len); #endif brealloc(plaintext, nonce_len + ciphertext->len, capacity); memcpy(plaintext->data, ciphertext->data, nonce_len + ciphertext->len); plaintext->len = nonce_len + ciphertext->len; return CRYPTO_OK; }