2

I have a piece of code where I wrap my symmetric key(AES) with AES key:

  1. swkKey: this is the AES key used for wrapping.
  2. key: the key to be wrapped.

Code:

SecretKey swkKeySpec = new SecretKeySpec(swkKey, 0, swkKey.length, "AES");
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
final int ivLength = 12;
final IvParameterSpec iv = createIV(ivLength);///Creates a new array.
cipher.init(Cipher.WRAP_MODE, swkKeySpec, iv);
SecretKey sKeySpec = new SecretKeySpec(key, 0, key.length, "AES");
byte[] wrappedAppKey = cipher.wrap(sKeySpec);`

What would be length of wrappedAppKey if key is 256 bits and swkkey is 256 bits. Can wrapped key be more than 32 bytes? Please note in this case I am getting following logs:

key length: 32(key to be wrapped)
swkKey length: 32(key used to wrap)
wrappedAppKey size: 48(final wrapped key output).
Vikas Rai
  • 87
  • 12
  • Welcome to StackOverflow! Your question seems to have its own answer (48 bytes; though that confuses me a bit, I expected this to implement RFC 3394 which should have an output of 40 bytes; key-length + 1 semi-block). When you say "more than 32 bits" did you mean "more than 32 bytes?" Is your question "why is the wrapped key longer than the original key?" As an unrelated note, what you're calling swkKey is usually called a KEK (key-encrypting key) in any documentation you read. – Rob Napier Mar 11 '19 at 14:12
  • or just "wrapping key" of course. – Maarten Bodewes Mar 11 '19 at 15:17

1 Answers1

7

A wrapped key using a standard mode of operation is simply encryption of the encoded data of the key. As the encoded data of an AES key is identical to the raw data, the data of a 256 bit key is simply 32 bytes.

The main difference for these non-specialized modes such as GCM/CBC/ECB is how the key bytes are handled: they are directly used in a SecretKey instance instead of being returned as bytes. This is of strong importance especially if the operation is performed in hardware (smart card, HSM, TPM) rather than software; the bytes of the wrapped keys can then be kept/protected within the specialized device.

GCM uses CTR mode underneath, which is a stream mode of operation. Stream mode of operation do not require padding of the plaintext, so the ciphertext will simply be 32 bytes as well. Java also includes the authentication tag (t) into the calculation. By default GCM uses the maximum authentication tag size, which is 16 bytes, so this is added to the ciphertext of the key itself, leaving you with 48 bytes. The tag size can be configured using the more specialized GCMParameterSpec class rather than ivParameterSpec; note that smaller tag sizes may introduce vulnerabilities for GCM mode.

However, remember that it is required to also be able to re-generate the IV/nonce for GCM mode encryption. So you need to store that as well if it cannot be regenerated from context. Note as well that GCM mode breaks in a horrible way if the nonce is ever reused for the same wrapping key. Most of the time using a fully random nonce and therefore storing it with the ciphertext is of high importance. For GCM it is strongly advisable to use a 12 byte nonce, expanding the ciphertext to 60 bytes.

Alternatively SIV mode or GCM-SIV mode could be used. These modes use the authentication tag as "synthetic" IV. This makes the encryption deterministic (identical plaintext leads to same ciphertext). As a key is supposed to be random by itself, they are very useful for these kind of modes, as they don't require usage of an RNG or storage of the IV. Unfortunately general purpose crypto libraries do often not contain implementations of these modes.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263