From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 07E432A8BD for ; Mon, 29 Apr 2019 08:24:50 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id nfk7xeEr1iRC for ; Mon, 29 Apr 2019 08:24:49 -0400 (EDT) Received: from smtp61.i.mail.ru (smtp61.i.mail.ru [217.69.128.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 9317B2A886 for ; Mon, 29 Apr 2019 08:24:49 -0400 (EDT) Date: Mon, 29 Apr 2019 15:24:47 +0300 From: Konstantin Osipov Subject: [tarantool-patches] Re: [PATCH v2 3/3] crypto: implement crypto codec API and AES 128 encryption Message-ID: <20190429122447.GB25624@atlas> References: <8491f1b7c3bc2c0297153c2e033b62f1a13461ac.1556535949.git.v.shpilevoy@tarantool.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <8491f1b7c3bc2c0297153c2e033b62f1a13461ac.1556535949.git.v.shpilevoy@tarantool.org> Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-Help: List-Unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-Subscribe: List-Owner: List-post: List-Archive: To: Vladislav Shpilevoy Cc: tarantool-patches@freelists.org * Vladislav Shpilevoy [19/04/29 14:09]: LGTM, please ask Georgy for a second opinion. > OpenSSL API is quite complex and hard to follow, additionally it > is very unstable. Encoding/decoding via OpenSSL methods usually > consists of multiple calls of a lot of functions. This patch > wraps OpenSSL API with one more easy to use and conforming > Tarantool code style in scope of crypto library. > > The API provides struct crypto_codec which encapsulates all the > encryption logic and exposes quite simple API like this: > > crypto_codec_encode/decode(in, in_size, out, out_size) > > A caller can create a needed codec via crypto_codec_new, which > now supports only AES 128 algorithm. The reason behind such a > choice is simple - it is needed in SWIM now. > > The API is flexible in terms of extending and adding new > algorithms in future. > > Needed for #3234 > --- > src/lib/core/diag.h | 2 + > src/lib/core/exception.cc | 25 +++++ > src/lib/core/exception.h | 7 ++ > src/lib/crypto/CMakeLists.txt | 2 +- > src/lib/crypto/crypto.c | 144 +++++++++++++++++++++++++ > src/lib/crypto/crypto.h | 94 +++++++++++++++++ > test/unit/CMakeLists.txt | 3 + > test/unit/crypto.c | 191 ++++++++++++++++++++++++++++++++++ > test/unit/crypto.result | 40 +++++++ > 9 files changed, 507 insertions(+), 1 deletion(-) > create mode 100644 test/unit/crypto.c > create mode 100644 test/unit/crypto.result > > diff --git a/src/lib/core/diag.h b/src/lib/core/diag.h > index 78f0cdbdf..fd3831e66 100644 > --- a/src/lib/core/diag.h > +++ b/src/lib/core/diag.h > @@ -251,6 +251,8 @@ struct error * > BuildCollationError(const char *file, unsigned line, const char *format, ...); > struct error * > BuildSwimError(const char *file, unsigned line, const char *format, ...); > +struct error * > +BuildCryptoError(const char *file, unsigned line, const char *format, ...); > > struct index_def; > > diff --git a/src/lib/core/exception.cc b/src/lib/core/exception.cc > index 6124c70d0..a6999af43 100644 > --- a/src/lib/core/exception.cc > +++ b/src/lib/core/exception.cc > @@ -280,6 +280,19 @@ SwimError::SwimError(const char *file, unsigned line, const char *format, ...) > va_end(ap); > } > > +const struct type_info type_CryptoError = > + make_type("CryptoError", &type_Exception); > + > +CryptoError::CryptoError(const char *file, unsigned line, > + const char *format, ...) > + : Exception(&type_CryptoError, file, line) > +{ > + va_list ap; > + va_start(ap, format); > + error_vformat_msg(this, format, ap); > + va_end(ap); > +} > + > #define BuildAlloc(type) \ > void *p = malloc(sizeof(type)); \ > if (p == NULL) \ > @@ -371,6 +384,18 @@ BuildSwimError(const char *file, unsigned line, const char *format, ...) > return e; > } > > +struct error * > +BuildCryptoError(const char *file, unsigned line, const char *format, ...) > +{ > + BuildAlloc(CryptoError); > + CryptoError *e = new (p) CryptoError(file, line, ""); > + va_list ap; > + va_start(ap, format); > + error_vformat_msg(e, format, ap); > + va_end(ap); > + return e; > +} > + > struct error * > BuildSocketError(const char *file, unsigned line, const char *socketname, > const char *format, ...) > diff --git a/src/lib/core/exception.h b/src/lib/core/exception.h > index 4f5b66f2e..a29281427 100644 > --- a/src/lib/core/exception.h > +++ b/src/lib/core/exception.h > @@ -51,6 +51,7 @@ extern const struct type_info type_IllegalParams; > extern const struct type_info type_SystemError; > extern const struct type_info type_CollationError; > extern const struct type_info type_SwimError; > +extern const struct type_info type_CryptoError; > > const char * > exception_get_string(struct error *e, const struct method_info *method); > @@ -166,6 +167,12 @@ public: > virtual void raise() { throw this; } > }; > > +class CryptoError: public Exception { > +public: > + CryptoError(const char *file, unsigned line, const char *format, ...); > + virtual void raise() { throw this; } > +}; > + > /** > * Initialize the exception subsystem. > */ > diff --git a/src/lib/crypto/CMakeLists.txt b/src/lib/crypto/CMakeLists.txt > index 7e2c6e1d3..4e2e5e403 100644 > --- a/src/lib/crypto/CMakeLists.txt > +++ b/src/lib/crypto/CMakeLists.txt > @@ -2,4 +2,4 @@ set(lib_sources crypto.c) > > set_source_files_compile_flags(${lib_sources}) > add_library(crypto STATIC ${lib_sources}) > -target_link_libraries(crypto ${OPENSSL_LIBRARIES}) > +target_link_libraries(crypto ${OPENSSL_LIBRARIES} core) > diff --git a/src/lib/crypto/crypto.c b/src/lib/crypto/crypto.c > index 4b192ba2d..a96963d6f 100644 > --- a/src/lib/crypto/crypto.c > +++ b/src/lib/crypto/crypto.c > @@ -29,12 +29,156 @@ > * SUCH DAMAGE. > */ > #include "crypto.h" > +#include "diag.h" > +#include "exception.h" > +#include "core/random.h" > #include > #include > #include > #include > #include > > +/** Set a diag error with the latest OpenSSL error message. */ > +static inline void > +diag_set_OpenSSL(void) > +{ > + diag_set(CryptoError, "OpenSSL error: %s", > + ERR_error_string(ERR_get_error(), NULL)); > +} > + > +/** > + * OpenSSL codec. It contains only key, initial vector, and a > + * constant cipher type, because OpenSSL does not allow > + * long-living EVP_CIPHER_CTX contexts. > + */ > +struct crypto_codec { > + /** > + * Secret key, usually is unchanged among multiple data > + * packets. Only AES 128 is supported now, so the buffer > + * is of 16 byte size. > + */ > + unsigned char key[CRYPTO_AES128_KEY_SIZE]; > + /** > + * Initial vector, and in fact a public key. It should be > + * regenerated randomly for each data packet. > + */ > + unsigned char iv[CRYPTO_AES_IV_SIZE]; > + /** Size of block by which the algorithm operates. */ > + uint8_t block_size; > + /** Cipher type. Depends on algorithm and key size. */ > + const EVP_CIPHER *type; > +}; > + > +struct crypto_codec * > +crypto_codec_new(enum crypto_algo algo, const char *key) > +{ > + struct crypto_codec *c = (struct crypto_codec *) malloc(sizeof(*c)); > + if (c == NULL) { > + diag_set(OutOfMemory, sizeof(*c), "malloc", "c"); > + return NULL; > + } > + switch (algo) { > + case CRYPTO_AES128: > + memcpy(c->key, key, sizeof(c->key)); > + memset(c->iv, 0, sizeof(c->iv)); > + c->type = EVP_aes_128_cbc(); > + break; > + case CRYPTO_NONE: > + c->type = EVP_enc_null(); > + break; > + default: > + free(c); > + diag_set(CryptoError, "only 'none' and AES 128 are supported"); > + return NULL; > + } > + c->block_size = EVP_CIPHER_block_size(c->type); > + return c; > +} > + > +const char * > +crypto_codec_gen_iv(struct crypto_codec *c) > +{ > + random_bytes((char *) c->iv, sizeof(c->iv)); > + return (char *) c->iv; > +} > + > +int > +crypto_codec_encrypt(struct crypto_codec *c, const char *in, int in_size, > + char *out, int out_size) > +{ > + const unsigned char *uin = (const unsigned char *) in; > + unsigned char *uout = (unsigned char *) out; > + /* > + * Note, that even if in_size is already multiple of block > + * size, additional block is still needed. Result is > + * almost always bigger than input. OpenSSL API advises to > + * provide buffer of one block bigger than the data to > + * encode. > + */ > + int len, result, need = in_size + c->block_size; > + if (need > out_size) > + return need; > + > + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); > + if (ctx == NULL) > + goto error; > + if (EVP_EncryptInit_ex(ctx, c->type, NULL, c->key, c->iv) != 1) > + goto error; > + if (EVP_EncryptUpdate(ctx, uout, &len, uin, in_size) != 1) > + goto error; > + result = len; > + assert(result <= need); > + if (EVP_EncryptFinal_ex(ctx, uout + result, &len) != 1) > + goto error; > + result += len; > + assert(result <= need); > + EVP_CIPHER_CTX_free(ctx); > + return result; > + > +error: > + diag_set_OpenSSL(); > + if (ctx != NULL) > + EVP_CIPHER_CTX_free(ctx); > + return -1; > +} > + > +int > +crypto_codec_decrypt(struct crypto_codec *c, const char *iv, > + const char *in, int in_size, char *out, int out_size) > +{ > + if (in_size > out_size) > + return in_size; > + const unsigned char *uin = (const unsigned char *) in; > + const unsigned char *uiv = (const unsigned char *) iv; > + unsigned char *uout = (unsigned char *) out; > + int len, result; > + > + EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); > + if (ctx == NULL) > + goto error; > + if (EVP_DecryptInit_ex(ctx, c->type, NULL, c->key, uiv) != 1) > + goto error; > + if (EVP_DecryptUpdate(ctx, uout, &len, uin, in_size) != 1) > + goto error; > + result = len; > + if (EVP_DecryptFinal_ex(ctx, uout + result, &len) != 1) > + goto error; > + EVP_CIPHER_CTX_free(ctx); > + return result + len; > + > +error: > + diag_set_OpenSSL(); > + if (ctx != NULL) > + EVP_CIPHER_CTX_free(ctx); > + return -1; > +} > + > +void > +crypto_codec_delete(struct crypto_codec *c) > +{ > + free(c); > +} > + > void > crypto_init(void) > { > diff --git a/src/lib/crypto/crypto.h b/src/lib/crypto/crypto.h > index bc807e1a2..c679c39f7 100644 > --- a/src/lib/crypto/crypto.h > +++ b/src/lib/crypto/crypto.h > @@ -35,6 +35,100 @@ > extern "C" { > #endif > > +enum crypto_algo { > + /** None to disable encryption. */ > + CRYPTO_NONE, > + /** > + * AES - Advanced Encryption Standard. It is a symmetric > + * key block cipher algorithm. AES encodes data in blocks > + * of 128 bits, for what it uses a key and an initial > + * vector. The key is a secret information which needs to > + * be shared among communicating nodes. Key size can be > + * 128, 192 and 256 bits. Initial vector is an additional > + * entropy factor to prevent an attack when an attacker > + * somehow learns a purpose or content of one data packet > + * and immediately learns purpose of all the same looking > + * packets. Initial vector should be generated randomly > + * for each data packet, nonetheless it is not private and > + * can be sent without encryption. > + */ > + CRYPTO_AES128, > +}; > + > +/** > + * Values obtained from EVP_CIPHER_*() API, but the constants are > + * needed in some places at compilation time. For example, for > + * statically sized buffers. > + */ > +enum { > + /** > + * Block size of AES operation. Encrypted data size is > + * always divisible by this value. > + */ > + CRYPTO_AES_BLOCK_SIZE = 16, > + /** > + * Size of AES initial vector. It does not depend on key > + * size. > + */ > + CRYPTO_AES_IV_SIZE = 16, > + /** > + * Obviously, 128 bits = 16 bytes always. It is just > + * syntax sugar so as not to hardcode 16 everywhere. > + */ > + CRYPTO_AES128_KEY_SIZE = 16, > +}; > + > +struct crypto_codec; > + > +/** > + * Create a new codec working with a specified @a algo algorithm > + * and a secret @a key. Size of @a key depends on the chosen > + * algorithm. > + */ > +struct crypto_codec * > +crypto_codec_new(enum crypto_algo algo, const char *key); > + > +/** Generate a new initial vector and return it. */ > +const char * > +crypto_codec_gen_iv(struct crypto_codec *c); > + > +/** > + * Encrypt plain data by codec @a c. > + * @param c Codec. > + * @param in Plain input data. > + * @param in_size Byte size of @a in. > + * @param out Output buffer. > + * @param out_size Byte size of @a out. > + * > + * @retval -1 Error. Diag is set. > + * @return Number of written bytes. If > @a out_size then nothing > + * is written, needed number of bytes is returned. > + */ > +int > +crypto_codec_encrypt(struct crypto_codec *c, const char *in, int in_size, > + char *out, int out_size); > + > +/** > + * Decrypt cipher by codec @a c. > + * @param c Codec. > + * @param iv Initial vector used to encode @a in. > + * @param in Cipher to decode. > + * @param in_size Byte size of @a in. > + * @param out Output buffer. > + * @param out_size Byte size of @a out. > + * > + * @retval -1 Error. Diag is set. > + * @return Number of written bytes. If > @a out_size then nothing > + * is written, needed number of bytes is returned. > + */ > +int > +crypto_codec_decrypt(struct crypto_codec *c, const char *iv, > + const char *in, int in_size, char *out, int out_size); > + > +/** Delete codec. */ > +void > +crypto_codec_delete(struct crypto_codec *c); > + > void > crypto_init(void); > > diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt > index bb88b9c9b..368ceb649 100644 > --- a/test/unit/CMakeLists.txt > +++ b/test/unit/CMakeLists.txt > @@ -213,6 +213,9 @@ target_link_libraries(checkpoint_schedule.test m unit) > add_executable(sio.test sio.c) > target_link_libraries(sio.test unit core) > > +add_executable(crypto.test crypto.c) > +target_link_libraries(crypto.test crypto unit) > + > add_executable(swim.test swim.c swim_test_transport.c swim_test_ev.c > swim_test_utils.c ${PROJECT_SOURCE_DIR}/src/version.c) > target_link_libraries(swim.test unit swim) > diff --git a/test/unit/crypto.c b/test/unit/crypto.c > new file mode 100644 > index 000000000..092650543 > --- /dev/null > +++ b/test/unit/crypto.c > @@ -0,0 +1,191 @@ > +/* > + * Copyright 2010-2019, Tarantool AUTHORS, please see AUTHORS file. > + * > + * Redistribution and use in source and binary forms, with or > + * without modification, are permitted provided that the following > + * conditions are met: > + * > + * 1. Redistributions of source code must retain the above > + * copyright notice, this list of conditions and the > + * following disclaimer. > + * > + * 2. Redistributions in binary form must reproduce the above > + * copyright notice, this list of conditions and the following > + * disclaimer in the documentation and/or other materials > + * provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED > + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL > + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, > + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF > + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR > + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF > + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF > + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > +#include "crypto/crypto.h" > +#include "core/random.h" > +#include "unit.h" > +#include "trivia/util.h" > +#include "memory.h" > +#include "fiber.h" > + > +static void > +test_aes128_codec(void) > +{ > + header(); > + plan(19); > + > + char key[CRYPTO_AES128_KEY_SIZE]; > + random_bytes(key, sizeof(key)); > + struct crypto_codec *c = crypto_codec_new(CRYPTO_AES128, key); > + > + int rc = crypto_codec_encrypt(c, NULL, 10, NULL, 0); > + is(rc, 26, "encrypt returns needed number of bytes"); > + rc = crypto_codec_encrypt(c, NULL, 10, NULL, 15); > + is(rc, 26, "encrypt does not write anything when too small "\ > + "buffer"); > + rc = crypto_codec_encrypt(c, NULL, 0, NULL, 0); > + is(rc, 16, "encrypt does not allow 0 sized buffer"); > + rc = crypto_codec_encrypt(c, NULL, 32, NULL, 0); > + is(rc, 48, "encrypt requires additional block when buffer "\ > + "size is multiple of block size"); > + > + const char *plain = "plain text"; > + int plain_size = strlen(plain) + 1; > + char buffer1[128], buffer2[128]; > + memset(buffer1, 0, sizeof(buffer1)); > + memset(buffer2, 0, sizeof(buffer2)); > + int buffer_size = sizeof(buffer1); > + const char *iv = crypto_codec_gen_iv(c); > + > + rc = crypto_codec_encrypt(c, plain, plain_size, buffer1, buffer_size); > + is(rc, 16, "encrypt works when buffer is big enough"); > + rc = crypto_codec_encrypt(c, plain, plain_size, buffer2, buffer_size); > + is(rc, 16, "encrypt returns the same on second call"); > + is(memcmp(buffer1, buffer2, rc), 0, "encrypted data is the same"); > + isnt(memcmp(buffer1, plain, plain_size), 0, > + "and it is not just copied from the plain text"); > + > + rc = crypto_codec_decrypt(c, iv, NULL, 16, NULL, 0); > + is(rc, 16, "decrypt also checks length and returns needed number "\ > + "of bytes"); > + rc = crypto_codec_decrypt(c, iv, buffer1, 16, buffer2, buffer_size); > + is(rc, plain_size, "decrypt returns correct number of bytes"); > + is(memcmp(buffer2, plain, plain_size), 0, > + "and correctly decrypts data"); > + > + rc = crypto_codec_decrypt(c, "false iv not meaning anything", > + buffer1, 16, buffer2, buffer_size); > + is(rc, -1, "decrypt can fail with wrong IV"); > + ok(! diag_is_empty(diag_get()), "diag error is set"); > + > + const char *iv2 = crypto_codec_gen_iv(c); > + rc = crypto_codec_encrypt(c, plain, plain_size, buffer2, buffer_size); > + is(rc, 16, "encrypt with different IV and the same number of written "\ > + "bytes returned") > + isnt(memcmp(buffer2, buffer1, rc), 0, > + "the encrypted data looks different"); > + rc = crypto_codec_decrypt(c, iv2, buffer2, 16, buffer1, buffer_size); > + is(rc, plain_size, "decrypt works with correct but another IV"); > + is(memcmp(buffer1, plain, plain_size), 0, "data is the same"); > + > + struct crypto_codec *c2 = crypto_codec_new(CRYPTO_AES128, key); > + rc = crypto_codec_encrypt(c, plain, plain_size, buffer1, buffer_size); > + memset(buffer2, 0, rc); > + rc = crypto_codec_decrypt(c2, iv2, buffer1, rc, buffer2, buffer_size); > + is(rc, plain_size, "encrypt with one codec, but decrypt with another "\ > + "codec and the same key"); > + is(memcmp(plain, buffer2, plain_size), 0, "data is the same"); > + > + crypto_codec_delete(c2); > + crypto_codec_delete(c); > + > + check_plan(); > + footer(); > +} > + > +static void > +test_aes128_stress(void) > +{ > + header(); > + plan(1); > + char key[CRYPTO_AES128_KEY_SIZE]; > + random_bytes(key, sizeof(key)); > + struct crypto_codec *c = crypto_codec_new(CRYPTO_AES128, key); > + > + char plain[515], cipher[1024], result[1024]; > + int rc, size = 10; > + for (int size = 10; size < (int) sizeof(plain); size += 10) { > + random_bytes(plain, size); > + const char *iv = crypto_codec_gen_iv(c); > + rc = crypto_codec_encrypt(c, plain, size, > + cipher, sizeof(cipher)); > + rc = crypto_codec_decrypt(c, iv, cipher, rc, > + result, sizeof(result)); > + fail_if(memcmp(result, plain, rc) != 0); > + } > + ok(true, "try encrypt/decrypt on a variety of sizes, keys, and ivs"); > + > + check_plan(); > + crypto_codec_delete(c); > + footer(); > +} > + > +static void > +test_none_codec(void) > +{ > + header(); > + plan(4); > + > + struct crypto_codec *c = crypto_codec_new(CRYPTO_NONE, NULL); > + const char *plain = "plain text"; > + int plain_size = strlen(plain) + 1; > + char buffer1[128], buffer2[128]; > + const char *iv = crypto_codec_gen_iv(c); > + int rc = crypto_codec_encrypt(c, plain, plain_size, > + buffer1, sizeof(buffer1)); > + is(rc, plain_size, "'none' codec does not require more space "\ > + "than the data"); > + is(memcmp(buffer1, plain, plain_size), 0, "data is just copied"); > + rc = crypto_codec_decrypt(c, iv, buffer1, rc, buffer2, sizeof(buffer2)); > + is(rc, plain_size, "'decrypt' does the same"); > + is(memcmp(buffer2, plain, plain_size), 0, "data is copied back"); > + > + crypto_codec_delete(c); > + > + check_plan(); > + footer(); > +} > + > +int > +main(void) > +{ > + header(); > + plan(4); > + random_init(); > + crypto_init(); > + memory_init(); > + fiber_init(fiber_c_invoke); > + > + struct crypto_codec *c = crypto_codec_new(-1, "1234"); > + is(c, NULL, "crypto checks that algo argument is correct"); > + crypto_codec_delete(c); > + > + test_aes128_codec(); > + test_aes128_stress(); > + test_none_codec(); > + > + fiber_free(); > + memory_free(); > + crypto_free(); > + random_free(); > + int rc = check_plan(); > + footer(); > + return rc; > +} > diff --git a/test/unit/crypto.result b/test/unit/crypto.result > new file mode 100644 > index 000000000..de55fd2e4 > --- /dev/null > +++ b/test/unit/crypto.result > @@ -0,0 +1,40 @@ > + *** main *** > +1..4 > +ok 1 - crypto checks that algo argument is correct > + *** test_aes128_codec *** > + 1..19 > + ok 1 - encrypt returns needed number of bytes > + ok 2 - encrypt does not write anything when too small buffer > + ok 3 - encrypt does not allow 0 sized buffer > + ok 4 - encrypt requires additional block when buffer size is multiple of block size > + ok 5 - encrypt works when buffer is big enough > + ok 6 - encrypt returns the same on second call > + ok 7 - encrypted data is the same > + ok 8 - and it is not just copied from the plain text > + ok 9 - decrypt also checks length and returns needed number of bytes > + ok 10 - decrypt returns correct number of bytes > + ok 11 - and correctly decrypts data > + ok 12 - decrypt can fail with wrong IV > + ok 13 - diag error is set > + ok 14 - encrypt with different IV and the same number of written bytes returned > + ok 15 - the encrypted data looks different > + ok 16 - decrypt works with correct but another IV > + ok 17 - data is the same > + ok 18 - encrypt with one codec, but decrypt with another codec and the same key > + ok 19 - data is the same > +ok 2 - subtests > + *** test_aes128_codec: done *** > + *** test_aes128_stress *** > + 1..1 > + ok 1 - try encrypt/decrypt on a variety of sizes, keys, and ivs > +ok 3 - subtests > + *** test_aes128_stress: done *** > + *** test_none_codec *** > + 1..4 > + ok 1 - 'none' codec does not require more space than the data > + ok 2 - data is just copied > + ok 3 - 'decrypt' does the same > + ok 4 - data is copied back > +ok 4 - subtests > + *** test_none_codec: done *** > + *** main: done *** > -- > 2.20.1 (Apple Git-117) > -- Konstantin Osipov, Moscow, Russia, +7 903 626 22 32