コード例 #1
0
ファイル: encrypt.c プロジェクト: 764664/shadowsocks-libev
char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, int method)
{
    if (method > TABLE)
    {
        cipher_ctx_t evp;
        cipher_context_init(&evp, method, 1);

        int c_len = *len + BLOCK_SIZE;
        int iv_len = 0;
        int err = 0;
        char *ciphertext = malloc(max(iv_len + c_len, buf_size));

        uint8_t iv[MAX_IV_LENGTH];
        iv_len = enc_iv_len;
        cipher_context_set_iv(&evp, iv, iv_len, 1);
        memcpy(ciphertext, iv, iv_len);

        err = cipher_context_update(&evp, (uint8_t*)(ciphertext+iv_len),
                                    &c_len, (const uint8_t *)plaintext, *len);

        if (!err)
        {
            free(ciphertext);
            free(plaintext);
            cipher_context_release(&evp);
            return NULL;
        }

#ifdef DEBUG
        dump("PLAIN", plaintext);
        dump("CIPHER", ciphertext);
#endif

        *len = iv_len + c_len;
        free(plaintext);
        cipher_context_release(&evp);

        return ciphertext;

    }
    else
    {
        char *begin = plaintext;
        while (plaintext < begin + *len)
        {
            *plaintext = (char)enc_table[(uint8_t)*plaintext];
            plaintext++;
        }
        return begin;
    }
}
コード例 #2
0
ファイル: encrypt.c プロジェクト: 764664/shadowsocks-libev
char* ss_decrypt(int buf_size, char *ciphertext, ssize_t *len, struct enc_ctx *ctx)
{
    if (ctx != NULL)
    {
        int p_len = *len + BLOCK_SIZE;
        int iv_len = 0;
        int err = 0;
        char *plaintext = malloc(max(p_len, buf_size));

        if (!ctx->init)
        {
            uint8_t iv[MAX_IV_LENGTH];
            iv_len = enc_iv_len;
            memcpy(iv, ciphertext, iv_len);
            cipher_context_set_iv(&ctx->evp, iv, iv_len, 0);
            ctx->init = 1;
        }

        err = cipher_context_update(&ctx->evp, (uint8_t*)plaintext, &p_len,
                                    (const uint8_t*)(ciphertext + iv_len), *len - iv_len);

        if (!err)
        {
            free(ciphertext);
            free(plaintext);
            return NULL;
        }

#ifdef DEBUG
        dump("PLAIN", plaintext);
        dump("CIPHER", ciphertext);
#endif

        *len = p_len;
        free(ciphertext);
        return plaintext;
    }
    else
    {
        char *begin = ciphertext;
        while (ciphertext < begin + *len)
        {
            *ciphertext = (char)dec_table[(uint8_t)*ciphertext];
            ciphertext++;
        }
        return begin;
    }
}
コード例 #3
0
ファイル: encrypt.c プロジェクト: 3gao/shadowsocks-libev
int ss_decrypt(buffer_t *cipher, enc_ctx_t *ctx, size_t capacity)
{
    if (ctx != NULL) {
        static buffer_t tmp = { 0, 0, 0, NULL };

        size_t iv_len = 0;
        int err       = 1;

        brealloc(&tmp, cipher->len, capacity);
        buffer_t *plain = &tmp;
        plain->len = cipher->len;

        if (!ctx->init) {
            uint8_t iv[MAX_IV_LENGTH];
            iv_len      = enc_iv_len;
            plain->len -= iv_len;

            memcpy(iv, cipher->array, iv_len);
            cipher_context_set_iv(&ctx->evp, iv, iv_len, 0);
            ctx->counter = 0;
            ctx->init    = 1;

            if (enc_method >= RC4_MD5) {
                if (cache_key_exist(iv_cache, (char *)iv, iv_len)) {
                    bfree(cipher);
                    return -1;
                } else {
                    cache_insert(iv_cache, (char *)iv, iv_len, NULL);
                }
            }
        }

        if (enc_method >= SALSA20) {
            int padding = ctx->counter % SODIUM_BLOCK_SIZE;
            brealloc(plain, (plain->len + padding) * 2, capacity);

            if (padding) {
                brealloc(cipher, cipher->len + padding, capacity);
                memmove(cipher->array + iv_len + padding, cipher->array + iv_len,
                        cipher->len - iv_len);
                memset(cipher->array + iv_len, 0, padding);
            }
            crypto_stream_xor_ic((uint8_t *)plain->array,
                                 (const uint8_t *)(cipher->array + iv_len),
                                 (uint64_t)(cipher->len - iv_len + padding),
                                 (const uint8_t *)ctx->evp.iv,
                                 ctx->counter / SODIUM_BLOCK_SIZE, enc_key,
                                 enc_method);
            ctx->counter += cipher->len - iv_len;
            if (padding) {
                memmove(plain->array, plain->array + padding, plain->len);
            }
        } else {
            err = cipher_context_update(&ctx->evp, (uint8_t *)plain->array, &plain->len,
                                        (const uint8_t *)(cipher->array + iv_len),
                                        cipher->len - iv_len);
        }

        if (!err) {
            bfree(cipher);
            return -1;
        }

#ifdef DEBUG
        dump("PLAIN", plain->array, plain->len);
        dump("CIPHER", cipher->array + iv_len, cipher->len - iv_len);
#endif

        brealloc(cipher, plain->len, capacity);
        memcpy(cipher->array, plain->array, plain->len);
        cipher->len = plain->len;

        return 0;
    } else {
        char *begin = cipher->array;
        char *ptr   = cipher->array;
        while (ptr < begin + cipher->len) {
            *ptr = (char)dec_table[(uint8_t)*ptr];
            ptr++;
        }
        return 0;
    }
}
コード例 #4
0
ファイル: encrypt.c プロジェクト: 3gao/shadowsocks-libev
int ss_decrypt_all(buffer_t *cipher, int method, int auth, size_t capacity)
{
    if (method > TABLE) {
        size_t iv_len = enc_iv_len;
        int ret       = 1;

        if (cipher->len <= iv_len) {
            return -1;
        }

        cipher_ctx_t evp;
        cipher_context_init(&evp, method, 0);

        static buffer_t tmp = { 0, 0, 0, NULL };
        brealloc(&tmp, cipher->len, capacity);
        buffer_t *plain = &tmp;
        plain->len = cipher->len - iv_len;

        uint8_t iv[MAX_IV_LENGTH];
        memcpy(iv, cipher->array, iv_len);
        cipher_context_set_iv(&evp, iv, iv_len, 0);

        if (method >= SALSA20) {
            crypto_stream_xor_ic((uint8_t *)plain->array,
                                 (const uint8_t *)(cipher->array + iv_len),
                                 (uint64_t)(cipher->len - iv_len),
                                 (const uint8_t *)iv, 0, enc_key, method);
        } else {
            ret = cipher_context_update(&evp, (uint8_t *)plain->array, &plain->len,
                                        (const uint8_t *)(cipher->array + iv_len),
                                        cipher->len - iv_len);
        }

        if (auth || (plain->array[0] & ONETIMEAUTH_FLAG)) {
            if (plain->len > ONETIMEAUTH_BYTES) {
                ret = !ss_onetimeauth_verify(plain, iv);
                if (ret) {
                    plain->len -= ONETIMEAUTH_BYTES;
                }
            } else {
                ret = 0;
            }
        }

        if (!ret) {
            bfree(cipher);
            cipher_context_release(&evp);
            return -1;
        }

#ifdef DEBUG
        dump("PLAIN", plain->array, plain->len);
        dump("CIPHER", cipher->array + iv_len, cipher->len - iv_len);
#endif

        cipher_context_release(&evp);

        brealloc(cipher, plain->len, capacity);
        memcpy(cipher->array, plain->array, plain->len);
        cipher->len = plain->len;

        return 0;
    } else {
        char *begin = cipher->array;
        char *ptr   = cipher->array;
        while (ptr < begin + cipher->len) {
            *ptr = (char)dec_table[(uint8_t)*ptr];
            ptr++;
        }
        return 0;
    }
}
コード例 #5
0
ファイル: encrypt.c プロジェクト: 3gao/shadowsocks-libev
int ss_encrypt(buffer_t *plain, enc_ctx_t *ctx, size_t capacity)
{
    if (ctx != NULL) {
        static buffer_t tmp = { 0, 0, 0, NULL };

        int err       = 1;
        size_t iv_len = 0;
        if (!ctx->init) {
            iv_len = enc_iv_len;
        }

        brealloc(&tmp, iv_len + plain->len, capacity);
        buffer_t *cipher = &tmp;
        cipher->len = plain->len;

        if (!ctx->init) {
            cipher_context_set_iv(&ctx->evp, ctx->evp.iv, iv_len, 1);
            memcpy(cipher->array, ctx->evp.iv, iv_len);
            ctx->counter = 0;
            ctx->init    = 1;
        }

        if (enc_method >= SALSA20) {
            int padding = ctx->counter % SODIUM_BLOCK_SIZE;
            brealloc(cipher, iv_len + (padding + cipher->len) * 2, capacity);
            if (padding) {
                brealloc(plain, plain->len + padding, capacity);
                memmove(plain->array + padding, plain->array, plain->len);
                memset(plain->array, 0, padding);
            }
            crypto_stream_xor_ic((uint8_t *)(cipher->array + iv_len),
                                 (const uint8_t *)plain->array,
                                 (uint64_t)(plain->len + padding),
                                 (const uint8_t *)ctx->evp.iv,
                                 ctx->counter / SODIUM_BLOCK_SIZE, enc_key,
                                 enc_method);
            ctx->counter += plain->len;
            if (padding) {
                memmove(cipher->array + iv_len,
                        cipher->array + iv_len + padding, cipher->len);
            }
        } else {
            err =
                cipher_context_update(&ctx->evp,
                                      (uint8_t *)(cipher->array + iv_len),
                                      &cipher->len, (const uint8_t *)plain->array,
                                      plain->len);
            if (!err) {
                return -1;
            }
        }

#ifdef DEBUG
        dump("PLAIN", plain->array, plain->len);
        dump("CIPHER", cipher->array + iv_len, cipher->len);
#endif

        brealloc(plain, iv_len + cipher->len, capacity);
        memcpy(plain->array, cipher->array, iv_len + cipher->len);
        plain->len = iv_len + cipher->len;

        return 0;
    } else {
        char *begin = plain->array;
        char *ptr   = plain->array;
        while (ptr < begin + plain->len) {
            *ptr = (char)enc_table[(uint8_t)*ptr];
            ptr++;
        }
        return 0;
    }
}
コード例 #6
0
ファイル: encrypt.c プロジェクト: 3gao/shadowsocks-libev
int ss_encrypt_all(buffer_t *plain, int method, int auth, size_t capacity)
{
    if (method > TABLE) {
        cipher_ctx_t evp;
        cipher_context_init(&evp, method, 1);

        size_t iv_len = enc_iv_len;
        int err       = 1;

        static buffer_t tmp = { 0, 0, 0, NULL };
        brealloc(&tmp, iv_len + plain->len, capacity);
        buffer_t *cipher = &tmp;
        cipher->len = plain->len;

        uint8_t iv[MAX_IV_LENGTH];

        rand_bytes(iv, iv_len);
        cipher_context_set_iv(&evp, iv, iv_len, 1);
        memcpy(cipher->array, iv, iv_len);

        if (auth) {
            ss_onetimeauth(plain, iv, capacity);
            cipher->len = plain->len;
        }

        if (method >= SALSA20) {
            crypto_stream_xor_ic((uint8_t *)(cipher->array + iv_len),
                                 (const uint8_t *)plain->array, (uint64_t)(plain->len),
                                 (const uint8_t *)iv,
                                 0, enc_key, method);
        } else {
            err = cipher_context_update(&evp, (uint8_t *)(cipher->array + iv_len),
                                        &cipher->len, (const uint8_t *)plain->array,
                                        plain->len);
        }

        if (!err) {
            bfree(plain);
            cipher_context_release(&evp);
            return -1;
        }

#ifdef DEBUG
        dump("PLAIN", plain->array, plain->len);
        dump("CIPHER", cipher->array + iv_len, cipher->len);
#endif

        cipher_context_release(&evp);

        brealloc(plain, iv_len + cipher->len, capacity);
        memcpy(plain->array, cipher->array, iv_len + cipher->len);
        plain->len = iv_len + cipher->len;

        return 0;
    } else {
        char *begin = plain->array;
        char *ptr   = plain->array;
        while (ptr < begin + plain->len) {
            *ptr = (char)enc_table[(uint8_t)*ptr];
            ptr++;
        }
        return 0;
    }
}
コード例 #7
0
ファイル: encrypt.c プロジェクト: Arathi/ShadowsocksRDroid
char * ss_decrypt(int buf_size, char *ciphertext, ssize_t *len, struct enc_ctx *ctx)
{
    if (ctx != NULL) {
        static int tmp_len = 0;
        static char *tmp_buf = NULL;

        size_t c_len = *len, p_len = *len;
        size_t iv_len = 0;
        int err = 1;
        int buf_len = max(p_len, buf_size);

        if (tmp_len < buf_len) {
            tmp_len = buf_len;
            tmp_buf = realloc(tmp_buf, buf_len);
        }
        char *plaintext = tmp_buf;

        if (!ctx->init) {
            uint8_t iv[MAX_IV_LENGTH];
            iv_len = enc_iv_len;
            p_len -= iv_len;
            memcpy(iv, ciphertext, iv_len);
            cipher_context_set_iv(&ctx->evp, iv, iv_len, 0);
            ctx->counter = 0;
            ctx->init = 1;

            if (enc_method >= RC4_MD5) {
                if (cache_key_exist(iv_cache, (char *)iv, iv_len)) {
                    free(ciphertext);
                    return NULL;
                } else {
                    cache_insert(iv_cache, (char *)iv, iv_len, NULL);
                }
            }
        }

        if (enc_method >= SALSA20) {
            int padding = ctx->counter % SODIUM_BLOCK_SIZE;
            if (buf_len < (p_len + padding) * 2) {
                buf_len = max((p_len + padding) * 2, buf_size);
                plaintext = realloc(plaintext, buf_len);
                tmp_len = buf_len;
                tmp_buf = plaintext;
            }
            if (padding) {
                ciphertext = realloc(ciphertext, max(c_len + padding, buf_size));
                memmove(ciphertext + iv_len + padding, ciphertext + iv_len,
                        c_len - iv_len);
                memset(ciphertext + iv_len, 0, padding);
            }
            crypto_stream_xor_ic((uint8_t *)plaintext,
                                 (const uint8_t *)(ciphertext + iv_len),
                                 (uint64_t)(c_len - iv_len + padding),
                                 (const uint8_t *)ctx->evp.iv,
                                 ctx->counter / SODIUM_BLOCK_SIZE, enc_key,
                                 enc_method);
            ctx->counter += c_len - iv_len;
            if (padding) {
                memmove(plaintext, plaintext + padding, p_len);
            }
        } else {
            err = cipher_context_update(&ctx->evp, (uint8_t *)plaintext, &p_len,
                                        (const uint8_t *)(ciphertext + iv_len),
                                        c_len - iv_len);
        }

        if (!err) {
            free(ciphertext);
            return NULL;
        }

#ifdef DEBUG
        dump("PLAIN", plaintext, p_len);
        dump("CIPHER", ciphertext + iv_len, c_len - iv_len);
#endif

        if (buf_size < p_len) {
            ciphertext = realloc(ciphertext, p_len);
        }
        *len = p_len;
        memcpy(ciphertext, plaintext, *len);

        return ciphertext;
    } else {
        char *begin = ciphertext;
        while (ciphertext < begin + *len) {
            *ciphertext = (char)dec_table[(uint8_t)*ciphertext];
            ciphertext++;
        }
        return begin;
    }
}
コード例 #8
0
ファイル: encrypt.c プロジェクト: Arathi/ShadowsocksRDroid
char * ss_decrypt_all(int buf_size, char *ciphertext, ssize_t *len, int method, int auth)
{
    if (method > TABLE) {
        size_t iv_len = enc_iv_len;
        size_t c_len = *len, p_len = *len - iv_len;
        int ret = 1;

        if (*len <= iv_len) {
            return NULL;
        }

        cipher_ctx_t evp;
        cipher_context_init(&evp, method, 0);

        static int tmp_len = 0;
        static char *tmp_buf = NULL;
        int buf_len = max(p_len, buf_size);
        if (tmp_len < buf_len) {
            tmp_len = buf_len;
            tmp_buf = realloc(tmp_buf, buf_len);
        }
        char *plaintext = tmp_buf;

        uint8_t iv[MAX_IV_LENGTH];
        memcpy(iv, ciphertext, iv_len);
        cipher_context_set_iv(&evp, iv, iv_len, 0);

        if (method >= SALSA20) {
            crypto_stream_xor_ic((uint8_t *)plaintext,
                                 (const uint8_t *)(ciphertext + iv_len),
                                 (uint64_t)(c_len - iv_len),
                                 (const uint8_t *)iv, 0, enc_key, method);
        } else {
            ret = cipher_context_update(&evp, (uint8_t *)plaintext, &p_len,
                                        (const uint8_t *)(ciphertext + iv_len),
                                        c_len - iv_len);
        }

        if (auth || (plaintext[0] & ONETIMEAUTH_FLAG)) {
            if (p_len > ONETIMEAUTH_BYTES) {
                char hash[ONETIMEAUTH_BYTES];
                memcpy(hash, plaintext + p_len - ONETIMEAUTH_BYTES, ONETIMEAUTH_BYTES);
                ret = !ss_onetimeauth_verify(hash, plaintext, p_len - ONETIMEAUTH_BYTES, iv);
                if (ret) {
                    p_len -= ONETIMEAUTH_BYTES;
                }
            } else {
                ret = 0;
            }
        }

        if (!ret) {
            free(ciphertext);
            cipher_context_release(&evp);
            return NULL;
        }

#ifdef DEBUG
        dump("PLAIN", plaintext, p_len);
        dump("CIPHER", ciphertext + iv_len, c_len - iv_len);
#endif

        cipher_context_release(&evp);

        if (buf_size < p_len) {
            ciphertext = realloc(ciphertext, p_len);
        }
        *len = p_len;
        memcpy(ciphertext, plaintext, *len);

        return ciphertext;
    } else {
        char *begin = ciphertext;
        while (ciphertext < begin + *len) {
            *ciphertext = (char)dec_table[(uint8_t)*ciphertext];
            ciphertext++;
        }
        return begin;
    }
}
コード例 #9
0
ファイル: encrypt.c プロジェクト: Arathi/ShadowsocksRDroid
char * ss_encrypt(int buf_size, char *plaintext, ssize_t *len,
                  struct enc_ctx *ctx)
{
    if (ctx != NULL) {
        static int tmp_len = 0;
        static char *tmp_buf = NULL;

        int err = 1;
        size_t iv_len = 0;
        size_t p_len = *len, c_len = *len;
        if (!ctx->init) {
            iv_len = enc_iv_len;
        }

        int buf_len = max(iv_len + c_len, buf_size);
        if (tmp_len < buf_len) {
            tmp_len = buf_len;
            tmp_buf = realloc(tmp_buf, buf_len);
        }
        char *ciphertext = tmp_buf;

        if (!ctx->init) {
            cipher_context_set_iv(&ctx->evp, ctx->evp.iv, iv_len, 1);
            memcpy(ciphertext, ctx->evp.iv, iv_len);
            ctx->counter = 0;
            ctx->init = 1;
        }

        if (enc_method >= SALSA20) {
            int padding = ctx->counter % SODIUM_BLOCK_SIZE;
            if (buf_len < iv_len + padding + c_len) {
                buf_len = max(iv_len + (padding + c_len) * 2, buf_size);
                ciphertext = realloc(ciphertext, buf_len);
                tmp_len = buf_len;
                tmp_buf = ciphertext;
            }
            if (padding) {
                plaintext = realloc(plaintext, max(p_len + padding, buf_size));
                memmove(plaintext + padding, plaintext, p_len);
                memset(plaintext, 0, padding);
            }
            crypto_stream_xor_ic((uint8_t *)(ciphertext + iv_len),
                                 (const uint8_t *)plaintext,
                                 (uint64_t)(p_len + padding),
                                 (const uint8_t *)ctx->evp.iv,
                                 ctx->counter / SODIUM_BLOCK_SIZE, enc_key,
                                 enc_method);
            ctx->counter += p_len;
            if (padding) {
                memmove(ciphertext + iv_len, ciphertext + iv_len + padding,
                        c_len);
            }
        } else {
            err =
                cipher_context_update(&ctx->evp,
                                      (uint8_t *)(ciphertext + iv_len),
                                      &c_len, (const uint8_t *)plaintext,
                                      p_len);
            if (!err) {
                free(plaintext);
                return NULL;
            }
        }

#ifdef DEBUG
        dump("PLAIN", plaintext, p_len);
        dump("CIPHER", ciphertext + iv_len, c_len);
#endif

        if (buf_size < iv_len + c_len) {
            plaintext = realloc(plaintext, iv_len + c_len);
        }
        *len = iv_len + c_len;
        memcpy(plaintext, ciphertext, *len);

        return plaintext;
    } else {
        char *begin = plaintext;
        while (plaintext < begin + *len) {
            *plaintext = (char)enc_table[(uint8_t)*plaintext];
            plaintext++;
        }
        return begin;
    }
}
コード例 #10
0
ファイル: encrypt.c プロジェクト: Arathi/ShadowsocksRDroid
char * ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, int method, int auth)
{
    if (method > TABLE) {
        cipher_ctx_t evp;
        cipher_context_init(&evp, method, 1);

        size_t p_len = *len, c_len = *len;
        size_t iv_len = enc_iv_len;
        int err = 1;

        static int tmp_len = 0;
        static char *tmp_buf = NULL;
        int buf_len = max(iv_len + c_len, buf_size);
        if (tmp_len < buf_len) {
            tmp_len = buf_len;
            tmp_buf = realloc(tmp_buf, buf_len);
        }
        char *ciphertext = tmp_buf;

        uint8_t iv[MAX_IV_LENGTH];

        rand_bytes(iv, iv_len);
        cipher_context_set_iv(&evp, iv, iv_len, 1);
        memcpy(ciphertext, iv, iv_len);

        if (auth) {
            char hash[ONETIMEAUTH_BYTES * 2];
            ss_onetimeauth(hash, plaintext, p_len, iv);
            if (buf_size < ONETIMEAUTH_BYTES + p_len) {
                plaintext = realloc(plaintext, ONETIMEAUTH_BYTES + p_len);
            }
            memcpy(plaintext + p_len, hash, ONETIMEAUTH_BYTES);
            p_len = c_len = p_len + ONETIMEAUTH_BYTES;
        }

        if (method >= SALSA20) {
            crypto_stream_xor_ic((uint8_t *)(ciphertext + iv_len),
                                 (const uint8_t *)plaintext, (uint64_t)(p_len),
                                 (const uint8_t *)iv,
                                 0, enc_key, method);
        } else {
            err = cipher_context_update(&evp, (uint8_t *)(ciphertext + iv_len),
                                        &c_len, (const uint8_t *)plaintext,
                                        p_len);
        }

        if (!err) {
            free(plaintext);
            cipher_context_release(&evp);
            return NULL;
        }

#ifdef DEBUG
        dump("PLAIN", plaintext, *len);
        dump("CIPHER", ciphertext + iv_len, c_len);
#endif

        cipher_context_release(&evp);

        if (buf_size < iv_len + c_len) {
            plaintext = realloc(plaintext, iv_len + c_len);
        }
        *len = iv_len + c_len;
        memcpy(plaintext, ciphertext, *len);

        return plaintext;
    } else {
        char *begin = plaintext;
        while (plaintext < begin + *len) {
            *plaintext = (char)enc_table[(uint8_t)*plaintext];
            plaintext++;
        }
        return begin;
    }
}
コード例 #11
0
ファイル: encrypt.c プロジェクト: nezharen/shadowsocks-libev
char * ss_decrypt_all(int buf_size, char *ciphertext, ssize_t *len, int method)
{
    if (method > TABLE) {
        cipher_ctx_t evp;
        cipher_context_init(&evp, method, 0);
        int iv_len = enc_iv_len;
        int c_len = *len, p_len = *len - iv_len;
        int err = 1;

        static int tmp_len = 0;
        static char *tmp_buf = NULL;
        int buf_len = max(p_len, buf_size);
        if (tmp_len < buf_len) {
            tmp_len = buf_len;
            tmp_buf = realloc(tmp_buf, buf_len);
        }
        char *plaintext = tmp_buf;

        uint8_t iv[MAX_IV_LENGTH];
        memcpy(iv, ciphertext, iv_len);
        cipher_context_set_iv(&evp, iv, iv_len, 0);

        if (method >= SALSA20) {
            crypto_stream_xor_ic((uint8_t *)plaintext,
                                 (const uint8_t *)(ciphertext + iv_len),
                                 (uint64_t)(c_len - iv_len),
                                 (const uint8_t *)iv, 0, enc_key, method);
        } else {
            err = cipher_context_update(&evp, (uint8_t *)plaintext, &p_len,
                                        (const uint8_t *)(ciphertext + iv_len),
                                        c_len - iv_len);
        }

        if (!err) {
            free(ciphertext);
            cipher_context_release(&evp);
            return NULL;
        }

#ifdef DEBUG
        dump("PLAIN", plaintext, p_len);
        dump("CIPHER", ciphertext + iv_len, c_len - iv_len);
#endif

        cipher_context_release(&evp);

        if (*len < p_len) {
            ciphertext = realloc(ciphertext, max(p_len, buf_size));
        }
        *len = p_len;
        memcpy(ciphertext, plaintext, *len);

        return ciphertext;
    } else {
        char *begin = ciphertext;
        while (ciphertext < begin + *len) {
            *ciphertext = (char)dec_table[(uint8_t)*ciphertext];
            ciphertext++;
        }
        return begin;
    }
}