summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am5
-rw-r--r--include/ncrypto/ncrypto.h41
-rw-r--r--lib/ncrypto_local.c342
-rw-r--r--tests/symm_ciphers.c174
4 files changed, 561 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am
index 2d4a0ab..961d8b8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,7 +35,7 @@ AM_CPPFLAGS = -I $(top_srcdir)/include $(GLIB_CFLAGS) $(NSS_CFLAGS) \
## Targets
lib_LTLIBRARIES = lib/libncrypto.la
pkginclude_HEADERS = include/ncrypto/ncrypto.h
-TESTS = tests/digests
+TESTS = tests/digests tests/symm_ciphers
## Rules
noinst_PROGRAMS = $(TESTS)
@@ -45,3 +45,6 @@ lib_libncrypto_la_LDFLAGS = -version-info 0:0:0 $(OPENSSL_LIBS)
tests_digests_LDADD = lib/libncrypto.la $(GLIB_LIBS)
tests_digests_LDFLAGS = -no-install
+
+tests_symm_ciphers_LDADD = lib/libncrypto.la $(GLIB_LIBS)
+tests_symm_ciphers_LDFLAGS = -no-install
diff --git a/include/ncrypto/ncrypto.h b/include/ncrypto/ncrypto.h
index af4f518..8da49c0 100644
--- a/include/ncrypto/ncrypto.h
+++ b/include/ncrypto/ncrypto.h
@@ -53,4 +53,45 @@ CK_RV ncr_digest_standalone (CK_MECHANISM_TYPE mech, void *dest,
size_t *dest_size_ptr, const void *data,
size_t data_size);
+struct ncr_symm_cipher_session;
+
+struct ncr_symm_key;
+
+CK_RV ncr_symm_key_create (struct ncr_symm_key **key, CK_KEY_TYPE type,
+ const void *value, size_t value_size);
+CK_RV ncr_symm_key_destroy (struct ncr_symm_key *key);
+
+/* Session lifetime management. */
+CK_RV ncr_symm_cipher_alloc (struct ncr_symm_cipher_session **sess,
+ CK_MECHANISM_TYPE mech);
+CK_RV ncr_symm_cipher_free (struct ncr_symm_cipher_session *sess);
+/* Use either ncr_symm_cipher_encrypt_{init,update,final} (), or
+ ncr_symm_cipher_{encrypt_init,encrypt} (). After finishing such a call
+ sequence, a new sequence can be started within the same session. Same for
+ decryption sequences. */
+CK_RV ncr_symm_cipher_encrypt_init (struct ncr_symm_cipher_session *sess,
+ struct ncr_symm_key *key,
+ const void *param, size_t param_size);
+CK_RV ncr_symm_cipher_encrypt_update (struct ncr_symm_cipher_session *sess,
+ void *dest, size_t *dest_size_ptr,
+ const void *src, size_t src_size);
+CK_RV ncr_symm_cipher_encrypt_final (struct ncr_symm_cipher_session *sess,
+ void *dest, size_t *dest_size_ptr,
+ const void *src, size_t src_size);
+CK_RV ncr_symm_cipher_encrypt (struct ncr_symm_cipher_session *sess, void *dest,
+ size_t *dest_size_ptr, const void *src,
+ size_t src_size);
+CK_RV ncr_symm_cipher_decrypt_init (struct ncr_symm_cipher_session *sess,
+ struct ncr_symm_key *key,
+ const void *param, size_t param_size);
+CK_RV ncr_symm_cipher_decrypt_update (struct ncr_symm_cipher_session *sess,
+ void *dest, size_t *dest_size_ptr,
+ const void *src, size_t src_size);
+CK_RV ncr_symm_cipher_decrypt_final (struct ncr_symm_cipher_session *sess,
+ void *dest, size_t *dest_size_ptr,
+ const void *src, size_t src_size);
+CK_RV ncr_symm_cipher_decrypt (struct ncr_symm_cipher_session *sess, void *dest,
+ size_t *dest_size_ptr, const void *src,
+ size_t src_size);
+
#endif
diff --git a/lib/ncrypto_local.c b/lib/ncrypto_local.c
index 8c686b7..7080c68 100644
--- a/lib/ncrypto_local.c
+++ b/lib/ncrypto_local.c
@@ -26,6 +26,10 @@ POSSIBILITY OF SUCH DAMAGE.
Red Hat author: Miloslav Trmač <mitr@redhat.com> */
#include <config.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
#include <glib.h>
#include <openssl/evp.h>
@@ -40,6 +44,47 @@ ckr_openssl (void)
return CKR_GENERAL_ERROR;
}
+ /* Symmetric keys */
+
+struct ncr_symm_key
+{
+ CK_KEY_TYPE type;
+ size_t size;
+ uint8_t value[];
+};
+
+CK_RV
+ncr_symm_key_create (struct ncr_symm_key **key, CK_KEY_TYPE type,
+ const void *value, size_t value_size)
+{
+ struct ncr_symm_key *k;
+
+ g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (value != NULL || value_size == 0, CKR_ARGUMENTS_BAD);
+ /* FIXME? validate "type" */
+ /* FIXME: PKCS#11 modules should refuse keys with incorrect parity here */
+
+ k = malloc (sizeof (*k) + value_size);
+ if (k == NULL)
+ return CKR_HOST_MEMORY;
+
+ k->type = type;
+ k->size = value_size;
+ memcpy (k->value, value, value_size);
+ *key = k;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_symm_key_destroy (struct ncr_symm_key *key)
+{
+ g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD);
+
+ memset (key->value, 0, key->size); /* FIXME: is this safe WRT optimization? */
+ free (key);
+ return CKR_OK;
+}
+
/* Digest handling */
static const EVP_MD *
@@ -230,3 +275,300 @@ ncr_digest_standalone (CK_MECHANISM_TYPE mech, void *dest,
return EVP_Digest(data, data_size, dest, NULL, md, NULL) != 0
? CKR_OK : ckr_openssl ();
}
+
+ /* Symmetric encryption */
+
+struct ncr_symm_cipher_session
+{
+ EVP_CIPHER_CTX ctx;
+ CK_MECHANISM_TYPE mech;
+ size_t padding_size; /* Additional space to reserve for padding */
+ _Bool encrypting;
+ /* Debugging only */
+ enum { NSCS_NEW, NSCS_INITIALIZED, NSCS_UPDATED, NSCS_FINISHED } state;
+};
+
+CK_RV
+ncr_symm_cipher_alloc (struct ncr_symm_cipher_session **sess,
+ CK_MECHANISM_TYPE mech)
+{
+ struct ncr_symm_cipher_session *s;
+
+ g_return_val_if_fail (sess != NULL, CKR_ARGUMENTS_BAD);
+ /* FIXME? Validate "mech" */
+
+ s = malloc (sizeof (*s));
+ if (s == NULL)
+ return CKR_HOST_MEMORY;
+
+ EVP_CIPHER_CTX_init (&s->ctx);
+ s->mech = mech;
+ s->state = NSCS_NEW;
+ *sess = s;
+ return CKR_OK;
+}
+
+CK_RV
+ncr_symm_cipher_free (struct ncr_symm_cipher_session *sess)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+
+ EVP_CIPHER_CTX_cleanup (&sess->ctx);
+ free (sess);
+ return CKR_OK;
+}
+
+static CK_RV
+symm_cipher_init (struct ncr_symm_cipher_session *sess, _Bool encrypt,
+ struct ncr_symm_key *key, const void *param,
+ size_t param_size)
+{
+ const EVP_CIPHER *type;
+ _Bool padding;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSCS_NEW || sess->state == NSCS_FINISHED,
+ CKR_OPERATION_ACTIVE);
+ g_return_val_if_fail (key != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (param != NULL || param_size == 0, CKR_ARGUMENTS_BAD);
+
+ switch (sess->mech)
+ {
+#define AES_SWITCH(MODE) \
+ switch (key->size) \
+ { \
+ AES_ENTRY (MODE, 128); \
+ AES_ENTRY (MODE, 192); \
+ AES_ENTRY (MODE, 256); \
+ default: \
+ g_return_val_if_reached (CKR_KEY_SIZE_RANGE); \
+ }
+#define AES_ENTRY(MODE, SIZE) \
+ case (SIZE) / 8: \
+ type = EVP_aes_##SIZE##_##MODE (); \
+ break;
+
+ case CKM_AES_ECB:
+ g_return_val_if_fail (key->type == CKK_AES, CKR_KEY_TYPE_INCONSISTENT);
+ g_return_val_if_fail (param_size == 0, CKR_MECHANISM_PARAM_INVALID);
+ AES_SWITCH (ecb);
+ padding = false;
+ break;
+
+ case CKM_AES_CBC:
+ case CKM_AES_CBC_PAD:
+ g_return_val_if_fail (key->type == CKK_AES, CKR_KEY_TYPE_INCONSISTENT);
+ g_return_val_if_fail (param_size == 16, CKR_MECHANISM_PARAM_INVALID);
+ AES_SWITCH (cbc);
+ padding = sess->mech == CKM_AES_CBC_PAD;
+ break;
+#undef AES_ENTRY
+
+ case CKM_DES3_ECB:
+ g_return_val_if_fail (key->type == CKK_DES3, CKR_KEY_TYPE_INCONSISTENT);
+ g_return_val_if_fail (key->size == 24, CKR_KEY_SIZE_RANGE);
+ g_return_val_if_fail (param_size == 0, CKR_MECHANISM_PARAM_INVALID);
+ type = EVP_des_ede3();
+ padding = false;
+ break;
+
+ case CKM_DES3_CBC:
+ case CKM_DES3_CBC_PAD:
+ g_return_val_if_fail (key->type == CKK_DES3, CKR_KEY_TYPE_INCONSISTENT);
+ g_return_val_if_fail (key->size == 24, CKR_KEY_SIZE_RANGE);
+ g_return_val_if_fail (param_size == 8, CKR_MECHANISM_PARAM_INVALID);
+ type = EVP_des_ede3_cbc();
+ padding = sess->mech == CKM_DES3_CBC_PAD;
+ break;
+
+ default:
+ g_return_val_if_reached (CKR_MECHANISM_INVALID);
+ }
+
+ if (EVP_CipherInit_ex (&sess->ctx, type, NULL, key->value,
+ param_size != 0 ? param : NULL, encrypt ? 1 : 0) == 0)
+ return ckr_openssl ();
+ if (!padding && EVP_CIPHER_CTX_set_padding (&sess->ctx, 0) == 0)
+ return ckr_openssl ();
+
+ sess->padding_size = padding ? EVP_CIPHER_block_size (type) : 0;
+ sess->encrypting = encrypt;
+ sess->state = NSCS_INITIALIZED;
+ return CKR_OK;
+}
+
+static CK_RV
+symm_cipher_update (struct ncr_symm_cipher_session *sess, _Bool encrypt,
+ void *dest, size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ int outl;
+
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess->state == NSCS_INITIALIZED
+ || sess->state == NSCS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+ g_return_val_if_fail (sess->encrypting == encrypt,
+ CKR_OPERATION_NOT_INITIALIZED);
+
+ if (dest == NULL)
+ {
+ *dest_size_ptr = src_size + sess->padding_size;
+ return CKR_OK;
+ }
+ if (*dest_size_ptr < src_size) /* FIXME? this does not handle partial data */
+ {
+ *dest_size_ptr = src_size;
+ g_return_val_if_reached (CKR_BUFFER_TOO_SMALL);
+ }
+
+ g_return_val_if_fail (dest != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (src != NULL || src_size == 0, CKR_ARGUMENTS_BAD);
+
+ if (EVP_CipherUpdate (&sess->ctx, dest, &outl, src, src_size) == 0)
+ return ckr_openssl ();
+
+ *dest_size_ptr = outl;
+ sess->state = NSCS_UPDATED;
+ return CKR_OK;
+}
+
+/* EVP_CipherUpdate + EVP_CipherFinal_ex */
+static CK_RV
+do_symm_cipher_update_final (struct ncr_symm_cipher_session *sess,
+ _Bool encrypt, void *dest, size_t *dest_size_ptr,
+ const void *src, size_t src_size)
+{
+ int outl;
+ size_t dest_size;
+
+ /* The caller has verified session and its state. */
+ g_return_val_if_fail (dest_size_ptr != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (sess->encrypting == encrypt,
+ CKR_OPERATION_NOT_INITIALIZED);
+
+ if (dest == NULL)
+ {
+ *dest_size_ptr = src_size + sess->padding_size;
+ return CKR_OK;
+ }
+ /* FIXME? this does not handle partial data or padding. */
+ if (*dest_size_ptr < src_size)
+ {
+ *dest_size_ptr = src_size;
+ g_return_val_if_reached (CKR_BUFFER_TOO_SMALL);
+ }
+
+ g_return_val_if_fail (dest != NULL, CKR_ARGUMENTS_BAD);
+ g_return_val_if_fail (src != NULL || src_size == 0, CKR_ARGUMENTS_BAD);
+
+ if (EVP_CipherUpdate (&sess->ctx, dest, &outl, src, src_size) == 0)
+ {
+ sess->state = NSCS_FINISHED;
+ return ckr_openssl ();
+ }
+
+ dest_size = outl;
+
+ if (EVP_CipherFinal_ex (&sess->ctx, (uint8_t *)dest + outl, &outl) == 0)
+ {
+ sess->state = NSCS_FINISHED;
+ return ckr_openssl ();
+ }
+
+ *dest_size_ptr = dest_size + outl;
+
+ sess->state = NSCS_FINISHED;
+ return CKR_OK;
+}
+
+static CK_RV
+symm_cipher_final (struct ncr_symm_cipher_session *sess, _Bool encrypt,
+ void *dest, size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSCS_INITIALIZED
+ || sess->state == NSCS_UPDATED,
+ CKR_OPERATION_NOT_INITIALIZED);
+
+ return do_symm_cipher_update_final (sess, encrypt, dest, dest_size_ptr, src,
+ src_size);
+}
+
+static CK_RV
+symm_cipher (struct ncr_symm_cipher_session *sess, _Bool encrypt, void *dest,
+ size_t *dest_size_ptr, const void *src, size_t src_size)
+{
+ g_return_val_if_fail (sess != NULL, CKR_SESSION_HANDLE_INVALID);
+ g_return_val_if_fail (sess->state == NSCS_INITIALIZED,
+ CKR_OPERATION_NOT_INITIALIZED);
+
+ return do_symm_cipher_update_final (sess, encrypt, dest, dest_size_ptr, src,
+ src_size);
+}
+
+CK_RV
+ncr_symm_cipher_encrypt_init (struct ncr_symm_cipher_session *sess,
+ struct ncr_symm_key *key, const void *param,
+ size_t param_size)
+{
+ return symm_cipher_init (sess, true, key, param, param_size);
+}
+
+CK_RV
+ncr_symm_cipher_encrypt_update (struct ncr_symm_cipher_session *sess,
+ void *dest, size_t *dest_size_ptr,
+ const void *src, size_t src_size)
+{
+ return symm_cipher_update (sess, true, dest, dest_size_ptr, src, src_size);
+}
+
+CK_RV
+ncr_symm_cipher_encrypt_final (struct ncr_symm_cipher_session *sess, void *dest,
+ size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ return symm_cipher_final (sess, true, dest, dest_size_ptr, src, src_size);
+}
+
+CK_RV
+ncr_symm_cipher_encrypt (struct ncr_symm_cipher_session *sess, void *dest,
+ size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ return symm_cipher (sess, true, dest, dest_size_ptr, src, src_size);
+}
+
+CK_RV
+ncr_symm_cipher_decrypt_init (struct ncr_symm_cipher_session *sess,
+ struct ncr_symm_key *key, const void *param,
+ size_t param_size)
+{
+ return symm_cipher_init (sess, false, key, param, param_size);
+}
+
+CK_RV
+ncr_symm_cipher_decrypt_update (struct ncr_symm_cipher_session *sess,
+ void *dest, size_t *dest_size_ptr,
+ const void *src, size_t src_size)
+{
+ return symm_cipher_update (sess, false, dest, dest_size_ptr, src, src_size);
+}
+
+CK_RV
+ncr_symm_cipher_decrypt_final (struct ncr_symm_cipher_session *sess, void *dest,
+ size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ return symm_cipher_final (sess, false, dest, dest_size_ptr, src, src_size);
+}
+
+CK_RV
+ncr_symm_cipher_decrypt (struct ncr_symm_cipher_session *sess, void *dest,
+ size_t *dest_size_ptr, const void *src,
+ size_t src_size)
+{
+ return symm_cipher (sess, false, dest, dest_size_ptr, src, src_size);
+}
diff --git a/tests/symm_ciphers.c b/tests/symm_ciphers.c
new file mode 100644
index 0000000..ccf6fe5
--- /dev/null
+++ b/tests/symm_ciphers.c
@@ -0,0 +1,174 @@
+/* ncr_symm_cipher_* tests.
+
+Copyright 2010 Red Hat, Inc.
+
+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 CONTRIBUTORS ``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 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.
+
+Red Hat author: Miloslav Trmač <mitr@redhat.com> */
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+#include <ncrypto/ncrypto.h>
+
+struct tv
+{
+ CK_MECHANISM_TYPE mech;
+ CK_KEY_TYPE key_type;
+ const uint8_t *key;
+ size_t key_size;
+ const uint8_t *input;
+ size_t input_size;
+ const uint8_t *output;
+ size_t output_size;
+};
+
+/* FIXME: Test non-ECB modes as well. */
+static const struct tv tvs[] =
+ {
+#define TV(M, K, KEY, IN, OUT) \
+ { \
+ (M), (K), (const uint8_t *)(KEY), sizeof (KEY) - 1, \
+ (const uint8_t *)(IN), sizeof (IN) - 1, (const uint8_t *)(OUT), \
+ sizeof (OUT) - 1 \
+ }
+ TV (CKM_AES_ECB, CKK_AES,
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+ "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF",
+ "\x69\xC4\xE0\xD8\x6A\x7B\x04\x30\xD8\xCD\xB7\x80\x70\xB4\xC5\x5A"),
+ TV (CKM_AES_ECB, CKK_AES,
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17",
+ "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF",
+ "\xDD\xA9\x7C\xA4\x86\x4C\xDF\xE0\x6E\xAF\x70\xA0\xEC\x0D\x71\x91"),
+ TV (CKM_AES_ECB, CKK_AES,
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
+ "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF",
+ "\x8E\xA2\xB7\xCA\x51\x67\x45\xBF\xEA\xFC\x49\x90\x4B\x49\x60\x89"),
+#undef TV
+ };
+
+int
+main (void)
+{
+ struct ncr_symm_cipher_session *sess;
+ struct ncr_symm_key *key;
+ uint8_t dest[256];
+ size_t i, j, dest_size;
+ CK_RV res;
+
+ for (i = 0; i < G_N_ELEMENTS (tvs); i++)
+ {
+ res = ncr_symm_cipher_alloc (&sess, tvs[i].mech);
+ assert (res == CKR_OK);
+
+ res = ncr_symm_key_create (&key, tvs[i].key_type, tvs[i].key,
+ tvs[i].key_size);
+ assert (res == CKR_OK);
+
+ for (j = 0; j < 2; j++)
+ {
+ res = ncr_symm_cipher_encrypt_init (sess, key, NULL, 0);
+ assert (res == CKR_OK);
+
+ dest_size = sizeof (dest);
+ res = ncr_symm_cipher_encrypt_update (sess, dest, &dest_size,
+ tvs[i].input,
+ tvs[i].input_size);
+ assert (res == CKR_OK);
+ assert (dest_size == tvs[i].output_size);
+ assert (memcmp (dest, tvs[i].output, dest_size) == 0);
+
+ dest_size = sizeof (dest);
+ res = ncr_symm_cipher_encrypt_final (sess, dest, &dest_size,
+ NULL, 0);
+ assert (res == CKR_OK);
+ assert (dest_size == 0);
+
+ res = ncr_symm_cipher_decrypt_init (sess, key, NULL, 0);
+ assert (res == CKR_OK);
+
+ dest_size = sizeof (dest);
+ res = ncr_symm_cipher_decrypt_update (sess, dest, &dest_size,
+ tvs[i].output,
+ tvs[i].output_size);
+ assert (res == CKR_OK);
+ assert (dest_size == tvs[i].input_size);
+ assert (memcmp (dest, tvs[i].input, dest_size) == 0);
+
+ dest_size = sizeof (dest);
+ res = ncr_symm_cipher_decrypt_final (sess, dest, &dest_size,
+ NULL, 0);
+ assert (res == CKR_OK);
+ assert (dest_size == 0);
+ }
+
+ res = ncr_symm_key_destroy (key);
+ assert (res == CKR_OK);
+
+ res = ncr_symm_cipher_free (sess);
+ assert (res == CKR_OK);
+ }
+
+ for (i = 0; i < G_N_ELEMENTS (tvs); i++)
+ {
+ res = ncr_symm_cipher_alloc (&sess, tvs[i].mech);
+ assert (res == CKR_OK);
+
+ res = ncr_symm_key_create (&key, tvs[i].key_type, tvs[i].key,
+ tvs[i].key_size);
+ assert (res == CKR_OK);
+
+ for (j = 0; j < 2; j++)
+ {
+ res = ncr_symm_cipher_encrypt_init (sess, key, NULL, 0);
+ assert (res == CKR_OK);
+
+ dest_size = sizeof (dest);
+ res = ncr_symm_cipher_encrypt (sess, dest, &dest_size, tvs[i].input,
+ tvs[i].input_size);
+ assert (res == CKR_OK);
+ assert (dest_size == tvs[i].output_size);
+ assert (memcmp (dest, tvs[i].output, dest_size) == 0);
+
+ res = ncr_symm_cipher_decrypt_init (sess, key, NULL, 0);
+ assert (res == CKR_OK);
+
+ dest_size = sizeof (dest);
+ res = ncr_symm_cipher_decrypt (sess, dest, &dest_size, tvs[i].output,
+ tvs[i].output_size);
+ assert (res == CKR_OK);
+ assert (dest_size == tvs[i].input_size);
+ assert (memcmp (dest, tvs[i].input, dest_size) == 0);
+ }
+
+ res = ncr_symm_key_destroy (key);
+ assert (res == CKR_OK);
+
+ res = ncr_symm_cipher_free (sess);
+ assert (res == CKR_OK);
+ }
+
+ return EXIT_SUCCESS;
+}