Nicolas Mora nicolas@babelouest.org writes:
It was designed to wrap key data, but not necessarily AES only. The kek must be an AES key though. The key data to wrap can be any data, as long as it's a set of 64 bits blocks.
If it doesn't add a lot of complexity, I think it would be nice to be able to substitute at least other 16-byte block ciphers (e.g., any other AES finalist, serpent and twofish being the once currently implemented in Nettle).
Good point, instead of passing the kek in the input params, it's better to pass a struct aes_ctx which is supposed to be already initialized.
I think it's better to represent the context as a const void* (in the main function), and let the caller allocate and pass in appropriate context, aes128_ctx or aes256_ctx etc). struct aes_ctx is deprecated, with the current api model being that the AES variants with different key sizes are separete algorithms, similarities just being implementation details.
We could still have convenience wrappers taking the key as a byte string, if that'ss the common usecase.
Good point too. Endianess is my kryptonite so my code would not be valid on all architectures...
If one goes this way, one needs some extra care and testing. It's worth it if there's a measurable performance improvement. Not sure about this case, but AES itself is pretty fast on some platforms.
(Also, for the best AES performance, one should call aes_encrypt with more than one block at a time. But as far as I understand, AES key wrap is inherently serial, so that's not possible here).
We can also replace the uint8_t with uint64_t as well in the input values?
It would be nice if we could have that alignment on input and output, but I think it's not a good idea to have uint64_t in this interface. We'd force alignment requirement on callers (who may be forced to make an extra copy to be able to call the function), and we'd also need to document endianness of the input. In short, since the specification defines the mechanism as operating on byte strings, the Nettle api should too.
I suspect that using byte strings in the interface and uint64_t internally makes it a bit difficult to allocate storage for internal state, since one can't just reuse the output buffer for working storage. Is the size needed for internal state same as the message size, or is if fixed size? I think it's doable but tricky to make it work without separate allocation for working storage.
It's up to the calling algorithm. The IV is used for key data integrity [5]. Concerning using different IVs, the paragraph 2.2.3.2 mentions that alternative IVs can be used as part of larger key management protocols if the key data is not just an AES key, it may not always be a multiple of 64 bits.
I was pointed to RFC 5649 (AES Key Wrap with Padding), is that relevant?
Perhaps if instead of using uint8_t[8] I use uint64_t, then the default IV can be a classic #define DEFAULT_IV A6A6A6A6A6A6A6A6
That would work for this particular value, since it is invariant under byte swapping. But in general an uint64_t iv would be endian dpendent.
Regards, /Niels