int aead_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity) { int err = CRYPTO_OK; static buffer_t tmp = { 0, 0, 0, NULL }; cipher_t *cipher = cipher_ctx->cipher; size_t salt_len = cipher->key_len; 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, capacity); } brealloc(cipher_ctx->chunk, cipher_ctx->chunk->len + ciphertext->len, capacity); memcpy(cipher_ctx->chunk->data + cipher_ctx->chunk->len, ciphertext->data, ciphertext->len); cipher_ctx->chunk->len += ciphertext->len; brealloc(&tmp, cipher_ctx->chunk->len, capacity); buffer_t *plaintext = &tmp; if (!cipher_ctx->init) { if (cipher_ctx->chunk->len <= salt_len) return CRYPTO_NEED_MORE; memcpy(cipher_ctx->salt, cipher_ctx->chunk->data, salt_len); aead_cipher_ctx_set_key(cipher_ctx, 0); if (ppbloom_check((void *)cipher_ctx->salt, salt_len) == 1) { LOGE("crypto: AEAD: repeat salt detected"); return CRYPTO_ERROR; } memmove(cipher_ctx->chunk->data, cipher_ctx->chunk->data + salt_len, cipher_ctx->chunk->len - salt_len); cipher_ctx->chunk->len -= salt_len; cipher_ctx->init = 1; } size_t plen = 0; while (cipher_ctx->chunk->len > 0) { size_t chunk_clen = cipher_ctx->chunk->len; size_t chunk_plen = 0; err = aead_chunk_decrypt(cipher_ctx, (uint8_t *)plaintext->data + plen, (uint8_t *)cipher_ctx->chunk->data, cipher_ctx->nonce, &chunk_plen, &chunk_clen); if (err == CRYPTO_ERROR) { return err; } else if (err == CRYPTO_NEED_MORE) { if (plen == 0) return err; else break; } cipher_ctx->chunk->len = chunk_clen; plen += chunk_plen; } plaintext->len = plen; // Add the salt to bloom filter if (cipher_ctx->init == 1) { if (ppbloom_check((void *)cipher_ctx->salt, salt_len) == 1) { LOGE("crypto: AEAD: repeat salt detected"); return CRYPTO_ERROR; } ppbloom_add((void *)cipher_ctx->salt, salt_len); cipher_ctx->init = 2; } brealloc(ciphertext, plaintext->len, capacity); memcpy(ciphertext->data, plaintext->data, plaintext->len); ciphertext->len = plaintext->len; return CRYPTO_OK; }
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; }