diff options
| author | Miloslav Trmač <mitr@redhat.com> | 2010-10-05 17:25:37 +0200 |
|---|---|---|
| committer | Miloslav Trmač <mitr@redhat.com> | 2010-10-05 17:25:37 +0200 |
| commit | 8a0e6e168da0c9efed8810725af5c593a8edf7cf (patch) | |
| tree | 557c812a0e195894a9a5f2bde4d2aac1456d5efd /lib | |
| parent | 1aab511f2b436ceee221233ba36c0e5a38311b82 (diff) | |
| download | ncrypto-8a0e6e168da0c9efed8810725af5c593a8edf7cf.tar.gz ncrypto-8a0e6e168da0c9efed8810725af5c593a8edf7cf.tar.xz ncrypto-8a0e6e168da0c9efed8810725af5c593a8edf7cf.zip | |
Add symmetric ciphers
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/ncrypto_local.c | 342 |
1 files changed, 342 insertions, 0 deletions
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); +} |
