Nikos Mavrogiannopoulos nmav@gnutls.org writes:
The disadvantage here is that I need to define encrypt and decrypt functions for each possible cipher and mode. That was the reason for the usage of cbc_encrypt() and decrypt.
Maybe it's possible with some trickery.
For cbc modes, you could allocate a context which is a pointer to the nettle_cipher struct followed by a CBC_CTX with cipher context and iv. Then you could do
nettle_crypt_func gnutls_cbc_encrypt;
struct gnutls_cbc_ctx { const struct nettle_cipher *cipher;
/* A cipher specific context, followed by iv. Use unsigned long as an alignment hack (or use pointers and additional memory blocks). Total allocation size:
offsetof (struct gnutls_cbc_ctx, buf) + cipher->context_size + cipher->block_size. */ unsigned long buf[1]; };
void gnutls_cbc_encrypt (void *p, ...) { struct gnutls_cbc_ctx *ctx = (struct gnutls_cbc_ctx *) p; void *cipher_ctx = ctx->buf; uint8_t *iv = (uint8_t *) cipher_ctx + ctx->cipher->context_size; cbc_encrypt (cipher_ctx, ctx->cipher->encrypt, ctx->cipher->block_size, iv, ...); }
and use the same encrypt function for all ciphers in cbc mode. Not sure what's best, to go this route, or generate boilerplate code for each algorithm.
And note that the only casting above is for packing everything into the same memory block, otherwise the cbc_encrypt call needs no casts at all. (The essential casts are hidden in the initialization of the various nettle_cipher instances).
btw. I realized that nettle-meta.h lacks definitions for 3des, des and salsa20.
des and des3 (and blowfish) are missing, because their set_key functions have a return value indicating weak keys. Maybe they should be added anyway? Either relying on casting betwen function pointers being safe with and without return value, or using a wrapper function to explicitly remove it.
Unfortunately, I don't think a C compiler can optimize
int bar (int x); void foo(int x) { (void) bar(x); /* Ignore return value */ }
to make foo simply an alias of bar (assuming the ABI calling ocnventions allow that). As far as I understand, the C standard requires that &bar != &foo, so at best foo wil be compiled into a single jmp instruction.
And salsa20 is missing because there is no nettle-meta abstraction for stream ciphers. Internally, I use nettle_aead with NULL ->update and ->digest methods to represent stream ciphers, but I'm not sure if that's suitable for a public interface. BTW, it's of course possible to represent CBC and CTR mode in the same way, as nettle_aead without authentication.
Regards, /Niels