Subject: [TLS] Consensus for AEAD IV

From: Joseph Salowey <[email-masked]>
Date: Fri, 24 Apr 2015 10:10:28 -0700

The general consensus on the list seems to prefer to derive "IV" and use it
to make the AEAD nonce less predictable. Most folks seemed to be OK with
this approach.    In Dallas, there was significant support for using the
derived "IV" as a per session XOR mask for the counter.  If you have
objections to this approach please respond on the list by May 1, 2015 .

Cheers,

Joe

---

From: Martin Thomson <[email-masked]>
Date: Fri, 24 Apr 2015 13:00:50 -0700

> objections to this approach please respond on the list by May 1, 2015 .

You aren't being particularly precise about the process here.

I believe that these were the two options that were most debated:

a)  nonce = zeroes(N_MIN) XOR counter
b)  nonce = HKDF(...., N_MIN) XOR counter

Did you mean the latter option?

---

From: Joseph Salowey <[email-masked]>
Date: Fri, 24 Apr 2015 13:44:54 -0700

> Did you mean the latter option?

[Joe] Yes, the later where the quantity XORed with the counter is derived
during the handshake.

---

From: Martin Thomson <[email-masked]>
Date: Fri, 24 Apr 2015 13:52:38 -0700

> [Joe] Yes, the later where the quantity XORed with the counter is derived

Sounds good.  We'll be guided by the concurrent HSM-friendly
discussion on what to do precisely.

---

From: Russ Housley <[email-masked]>
Date: Fri, 24 Apr 2015 17:00:26 -0400

Joe:

> On Fri, Apr 24, 2015 at 1:00 PM, Martin Thomson <[email-masked]> wrote:
> [Joe] Yes, the later where the quantity XORed with the counter is derived during the handshake.  

If the computation is done in an HSM-friendly fashion, I am supportive.

Russ

---

From: Michael StJohns <[email-masked]>
Date: Sat, 25 Apr 2015 23:21:22 -0400

On 4/24/2015 4:44 PM, Joseph Salowey wrote:
>
>
> On Fri, Apr 24, 2015 at 1:00 PM, Martin Thomson 
> <[email-masked] <mailto:[email-masked]>> wrote:
>
>     On 24 April 2015 at 10:10, Joseph Salowey <[email-masked]
>     <mailto:[email-masked]>> wrote:

In general, APIs for hardware (and software) encryption are set up as 
init, multiple updates and finalize.  The arguments to init are 
generally a handle pointing to the key, a selection of the encryption 
mode and the initialization parameters specific to that mode.  The 
initialization parameters generally include material for the IV 
(obviously not used in ECB), and other mode specific items. For CCM, 
most implementations use the block formatting function described in 
appendix A of the NIST spec and that function uses as input to the 
initialization a "nonce" as well as information about the length of the AAD.

All of the Init data is non-secret information (note that I said handle 
to key, and not key above - the handle is non-secret, the key material 
is secret) and must be shared implicitly or explicitly between sender 
and receiver.

All of that is a long way of saying that making the nonce be some sort 
of output of the HKDF is probably a bad idea as the general use for a 
KDF is to produce secret key material.

A zero session nonce combined with the message sequence number to form 
unique per-key value is acceptable cryptographically - at least for GCM 
and CCM.    (and that's really the same thing as 0 XOR counter as far as 
I can tell).

A randomly generated session nonce concatenated with the message 
sequence number to produce a message nonce is acceptable 
cryptographically and provides no less protection than generating a long 
session nonce and xor'ing the sequence number in to produce the message 
nonce.

AFAICT b) provides no additional security over a).   The security of CCM 
and GCM is NOT dependent on the secrecy of the IV/Nonce/sequence number, 
only in its uniqueness for a given key, and (b) appears to be trying to 
make the IV secret.

Doing (b) will make it difficult to implement TLS using generic HSM 
functions as there will probably need to be some way of piping the 
secret output of HKDF to be the per message IV.

So I'd prefer (a) - zero session nonce.  If a random session nonce is 
required (why?), then instead use the impedance matching function (e.g. 
the HKDF-Extract or the equivalent) against the client and server randoms:

    session_nonce = LTRUNCATE (HMAC-HASH ("0", client_random | server_ 
random));

    message_nonce = session_nonce | sequence_number

Mike

>
>
> _______________________________________________
> TLS mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/tls

---

From: Yoav Nir <[email-masked]>
Date: Sun, 26 Apr 2015 06:47:09 +0300

> On Apr 26, 2015, at 6:21 AM, Michael StJohns <[email-masked]> wrote:
> 
>> On Fri, Apr 24, 2015 at 1:00 PM, Martin Thomson <[email-masked] <mailto:[email-masked]>> wrote:
>> On 24 April 2015 at 10:10, Joseph Salowey <[email-masked] <mailto:[email-masked]>> wrote:
> In general, APIs for hardware (and software) encryption are set up as init, multiple updates and finalize.  The arguments to init are generally a handle pointing to the key, a selection of the encryption mode and the initialization parameters specific to that mode.  The initialization parameters generally include material for the IV (obviously not used in ECB), and other mode specific items.  For CCM, most implementations use the block formatting function described in appendix A of the NIST spec and that function uses as input to the initialization a "nonce" as well as information about the length of the AAD.
> 
> All of the Init data is non-secret information (note that I said handle to key, and not key above - the handle is non-secret, the key material is secret) and must be shared implicitly or explicitly between sender and receiver.
> 
> All of that is a long way of saying that making the nonce be some sort of output of the HKDF is probably a bad idea as the general use for a KDF is to produce secret key material.
> 
> 
> A zero session nonce combined with the message sequence number to form unique per-key value is acceptable cryptographically - at least for GCM and CCM.    (and that's really the same thing as 0 XOR counter as far as I can tell).
> 
> 
> A randomly generated session nonce concatenated with the message sequence number to produce a message nonce is acceptable cryptographically and provides no less protection than generating a long session nonce and xor'ing the sequence number in to produce the message nonce. 
> 
> AFAICT b) provides no additional security over a).   The security of CCM and GCM is NOT dependent on the secrecy of the IV/Nonce/sequence number, only in its uniqueness for a given key, and (b) appears to be trying to make the IV secret.
> 
> Doing (b) will make it difficult to implement TLS using generic HSM functions as there will probably need to be some way of piping the secret output of HKDF to be the per message IV.

I don’t see why. Make the 128- or 256-bit key one part of the keying material, and the 96-bit quantity another part of the keying material. A single handle references a structure containing both.

Now you pass the encryption function the handle, the data to be encrypted (and protected) and a message counter. The function (hardware or software) converts the counter into a nonce by XOR-ing with the quantity, and proceeds from there. There is no reason not to treat the 96-bit quantity as anything but secret.

Doesn’t this solve you API issue?

Yoav

---

From: Michael StJohns <[email-masked]>
Date: Sun, 26 Apr 2015 14:00:48 -0400

On 4/25/2015 11:47 PM, Yoav Nir wrote:
>
>> On Apr 26, 2015, at 6:21 AM, Michael StJohns <[email-masked] 
>> <mailto:[email-masked]>> wrote:
>>
>> All of the Init data is non-secret information (note that I said 
>> handle to key, and not key above - the handle is non-secret, the key 
>> material is secret) and must be shared implicitly or explicitly 
>> between sender and receiver.
>>
>> All of that is a long way of saying that making the nonce be some 
>> sort of output of the HKDF is probably a bad idea as the general use 
>> for a KDF is to produce secret key material.
>>
>>
>> A zero session nonce combined with the message sequence number to 
>> form unique per-key value is acceptable cryptographically - at least 
>> for GCM and CCM.    (and that's really the same thing as 0 XOR 
>> counter as far as I can tell).
>>
>>
>> cryptographically and provides no less protection than generating a 
>> long session nonce and xor'ing the sequence number in to produce the 
>> message nonce.
>>
>> AFAICT b) provides no additional security over a).   The security of 
>> CCM and GCM is NOT dependent on the secrecy of the IV/Nonce/sequence 
>> number, only in its uniqueness for a given key, and (b) appears to be 
>> trying to make the IV secret.
>>
> I don’t see why. Make the 128- or 256-bit key one part of the keying 
> material, and the 96-bit quantity another part of the keying material. 
> A single handle references a structure containing both.

So what you're suggesting is requiring each cipher mode that uses TLS 
have both the generic - pass in the IV etc - and the TLS specific - pass 
in a handle to material that has to be retained within the HSM and 
managed in some way to make sure that you delete when your done?

Seriously - no.

You're actually going to make it impossible to use TLS1.3 with generic 
hardware modules.

>
> Now you pass the encryption function the handle, the data to be 
> encrypted (and protected) and a message counter. The function 
> (hardware or software) converts the counter into a nonce by XOR-ing 
> with the quantity, and proceeds from there. There is no reason not to 
> treat the 96-bit quantity as anything but secret.

There is no reason to treat the 96 bit quantity as secret and no one 
else does.

TLS should use generic interfaces rather than inventing stuff that can't.

> Doesn’t this solve you API issue?

No.

---

From: Ilari Liusvaara <[email-masked]>
Date: Sun, 26 Apr 2015 21:20:25 +0300

> You're actually going to make it impossible to use TLS1.3 with generic

Define "generic hardware module".
 
What key derivation operations it supports? Both secret->secret and
secret->public (and yes, the latter _will_ be needed).

> >Now you pass the encryption function the handle, the data to be encrypted
> >(and protected) and a message counter. The function (hardware or software)
> >converts the counter into a nonce by XOR-ing with the quantity, and
> >proceeds from there. There is no reason not to treat the 96-bit quantity
> >as anything but secret.
> 
> There is no reason to treat the 96 bit quantity as secret and no one else
> does.

Oh, except SSH. The session nonce is 96 bits and secret.

(To lesser extent, IPSEC, there the session nonce is 32 bits and secret).

> TLS should use generic interfaces rather than inventing stuff that can't.

Well, given that one needs to derive public data out of secret keys, that
sure can also derive per-connection IVs out of secrets.

-Ilari

---

From: Brian Smith <[email-masked]>
Date: Sun, 26 Apr 2015 08:44:44 -1000

Michael StJohns <[email-masked]> wrote:

> So what you're suggesting is requiring each cipher mode that uses TLS have
> both the generic - pass in the IV etc - and the TLS specific - pass in a
> handle to material that has to be retained within the HSM and managed in
> some way to make sure that you delete when your done?
>

No, it isn't TLS-specific. As others noted, SSH can use it too. And, future
protocols can use it as well. Regardless of the particulars if the TLS
discussion, the pass-in-the-IV approach is terrible because the module
cannot guarantee the uniqueness of the IVs. So, actually, everybody should
be using the
pass-in-the-handle-to-material-that-can-be-*PROPERLY*-maintained-by-the-module
approach. The FIPS 140 implementation guidance agrees, as far as I
understand it.

> You're actually going to make it impossible to use TLS1.3 with generic

No, one can still create a generic module that doesn't know anything about
TLS, that can provide this type of interface. And, one should do so.

> There is no reason to treat the 96 bit quantity as secret and no one else

Others already refuted the "no one else does." As for there being "no
reason to treat the 96 bit quantity as secret," there's also no reason to
make it public. The working group already decided when there is no
compelling reason to make a handshake value public, then it should be made
private. (The charter says "Develop a mode that encrypts as much of the
handshake as is possible to reduce the amount of observable data to both
passive and active attackers.")

Further, I believe you actually mean "there is no *known* reason" to treat
the IV as secret. That doesn't mean there aren't *unknown* reasons for
doing so.

> TLS should use generic interfaces rather than inventing stuff that can't.

Again, this can use a generic interface. It can't use the generic
interfaces that are currently exposed by certain crypto modules, but that's
a problem with those crypto modules' interfaces, not with what is being
proposed here.

Cheers,
Brian

---

From: Michael StJohns <[email-masked]>
Date: Sun, 26 Apr 2015 16:26:32 -0400

> Oh, except SSH. The session nonce is 96 bits and secret.

(I'll get back to the rest of your message later,  but let me dispose of 
the above first).

Not exactly.  It turns out that the IV of each SSH message is the Cipher 
text of the last block of the previous message.  Which - since it's 
cipher text - is transmitted and known to everyone who can intercept the 
message stream.

SSH uses CBC exclusively as far as I can tell.   The fact that the 
mixin  of the first block of the first message (AKA the initial IV) is 
generated via keyed material from the negotiated shared secret is 
actually a problem (similar to the problems in TLS 1.2 and before) and 
doesn't actually provide any security.

Let me be blunt:  IVs are NOT secrets and you should not impute 
additional security by encrypting them or otherwise deriving them in a 
non-public manner.

Mike

---

From: Ilari Liusvaara <[email-masked]>
Date: Sun, 26 Apr 2015 23:34:23 +0300

On Sun, Apr 26, 2015 at 04:26:32PM -0400, Michael StJohns wrote:
> SSH uses CBC exclusively as far as I can tell.   The fact that the mixin  of
> the first block of the first message (AKA the initial IV) is generated via
> keyed material from the negotiated shared secret is actually a problem
> (similar to the problems in TLS 1.2 and before) and doesn't actually provide
> any security.

SSH can also use:
- CTR (start from 128-bit secret initial IV, no packet boundaries)
- AES-GCM (96 bit secret initial IV, increments per packet)
- Chacha20-Poly1305 (uses message sequence as nonce)

(In fact, I think the semi-offical recommendation is "don't use CBC in SSH").

-Ilari

---

From: Michael StJohns <[email-masked]>
Date: Sun, 26 Apr 2015 17:18:39 -0400

On 4/26/2015 4:34 PM, Ilari Liusvaara wrote:
>> SSH uses CBC exclusively as far as I can tell.

*sigh* I looked at the original SSH rfc and for some reason none of the 
new modes were added to that RFC as "Updates".

>>   The fact that the mixin  of

The fact that SSH was designed with CBC and that you got no security 
from CBC by doing it this way is the key point.  The fact that new modes 
have come along and just used what they were handed doesn't really add 
to the "the IV must be secret" argument.

In other words, it wasn't done this way originally to increase security 
so using it as an example for good practice is probably somewhat bogus.

---

From: Michael StJohns <[email-masked]>
Date: Sun, 26 Apr 2015 17:28:56 -0400

> (To lesser extent, IPSEC, there the session nonce is 32 bits and secret).

This is directly from section 2.3 of the IPSec ESP RFC 4303

> With regard to ensuring the alignment of the (real) ciphertext in the
>     presence of an IV, note the following:
>
>           o For some IV-based modes of operation, the receiver treats
>             the IV as the start of the ciphertext, feeding it into the
>             algorithm directly.  In these modes, alignment of the start
>             of the (real) ciphertext is not an issue at the receiver.
>
>
>           o In some cases, the receiver reads the IV in separately from
>             the ciphertext.  In these cases, the algorithm specification
>             MUST address how alignment of the (real) ciphertext is to be
>             achieved.

And RFC4309 - CCM mode has this:

>  ESP Payload
>
>    The ESP payload is composed of the IV followed by the ciphertext.
>    The payload field, as defined in [ESP], is structured as shown in
>    Figure 1.
>
>        0                   1                   2 3
>        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
>       |                     Initialization Vector                     |
>       |                            (8 octets)                         |
> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> |                                                               |
>       ~                  Encrypted Payload (variable)                 ~
> |                                                               |
> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
> |                                                               |
>       ~                 Authentication Data (variable)                ~
> |                                                               |
> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Again, newer modes may have done something else, but the above is strong 
indication that IVs were not generated as secrets as a general matter.

Later, Mike

---

From: Yoav Nir <[email-masked]>
Date: Mon, 27 Apr 2015 01:26:06 +0300

Both CCM and GCM use a concatenation of the explicit IV (which is obviously not secret and allowed to be predictable) with a salt that is derived from the keying material. This concatenation forms the nonce which is input to the AEAD.

RFC 4309 (CCM) says "The salt value need not be secret, but it MUST NOT be predictable prior to the beginning of the security association.”
RFC 4106 (GCM) says "The salt SHOULD be unpredictable (i.e., chosen at random) before it is selected, but need not be secret.”

The ChaCha20-Poly1305 for IPsec draft does the same thing, and in fact so does RFC 5288 (AES-GCM for TLS 1.2)

So no, that salt (and by extension, the proposed 96-bit value) need not be secret, but it’s never transmitted. This also shows that there is good precedent for generating such a doesn’t-really-need-to-be-secret value from the key_block or KEYMAT.

Yoav

> On Apr 27, 2015, at 12:28 AM, Michael StJohns <[email-masked]> wrote:
> 
> Again, newer modes may have done something else, but the above is strong indication that IVs were not generated as secrets as a general matter.
> 
> Later, Mike
>

---

From: Michael StJohns <[email-masked]>
Date: Sun, 26 Apr 2015 19:24:07 -0400

> Both CCM and GCM use a concatenation of the explicit IV (which is obviously not secret and allowed to be predictable) with a salt that is derived from the keying material. This concatenation forms…

Which protocol are we talking about?

CCM and GCM - as generic functions - use a per message Nonce.  CCM 
defines a block formatting function (Appendix A of the Nist Document)  
that takes a nonce of 1-15 octets.  David Mc Grew's RFC on AEAD 
functions APIs fixes the length of that nonce to 12 bytes because that's 
the most common length for GCM.  That per message nonce (back to the 
generic again) can be created from the combination of a per-session 
nonce and a sequence number, randomly generated or derived from key 
material.

HSMs generally implement the generic interfaces described in the base 
CCM and GCM documents, and David Mc Grew's RFC on AEAD is a subset of 
those possibilities and is therefor usable with the generic interfaces.

> RFC 4106 (GCM) says "The salt SHOULD be unpredictable (i.e., chosen at random) before it is selected, but need not be secret.”

In IPSEC GCM, the IV is explicitly included in each packet  (see section 
3.1 of RFC4106) and hence is not secret in any way shape or form.

In IPSEC CCM, the IV is also explicitly included in each packet - see 
section 3 and 3.1 of RFC 4309.  Hence, also never secret in any way 
shape or form.

> The ChaCha20-Poly1305 for IPsec draft does the same thing, and in fact so does RFC 5288 (AES-GCM for TLS 1.2)

Citing your own draft as proof of your own argument is a bit.... well...

In any event, I note that your IPSEC draft doesn't actually describe the 
ESP payload format, so without that, I'd make the assumption that the IV 
is included before the payload as is described in the IPSEC ESP document.

>
> So no, that salt (and by extension, the proposed 96-bit value) need not be secret, but it’s never transmitted.
In which of the above?  Maybe in the chacha20 draft... but not in the 
other two.

And RFC5288 does it the wrong way - getting IV (session nonce) material 
from the same key stream as key material.  That hopefully will be fixed 
with TLS1.3.  It would have been much more preferable to use a zero 
session nonce than extract it from the key stream.

>   This also shows that there is good precedent for generating such a doesn’t-really-need-to-be-secret value from the key_block or KEYMAT.

I'm pretty sure it doesn't.  It just shows a continuous misunderstanding 
of the problems with doing it this way.  There are ways to mitigate this 
a bit - but they require ensuring complete cryptographic isolation from 
key generation and a method of non-secret but not disclosed information 
that can still be used with the generic interfaces.

There was a good precedence for using RC4 and MD5 because they were fast 
and in wide use, but we've learned.

Later, Mike

---

From: Yoav Nir <[email-masked]>
Date: Mon, 27 Apr 2015 10:51:12 +0300

> On Apr 27, 2015, at 2:24 AM, Michael StJohns <[email-masked]> wrote:
> 

I thought it was clear from context that we were talking about how IPsec does it.

> CCM and GCM - as generic functions - use a per message Nonce.  CCM defines a block formatting function (Appendix A of the Nist Document)  that takes a nonce of 1-15 octets.  David Mc Grew's RFC on AEAD functions APIs fixes the length of that nonce to 12 bytes because that's the most common length for GCM.  That per message nonce (back to the generic again) can be created from the combination of a per-session nonce and a sequence number, randomly generated or derived from key material.
> 
> HSMs generally implement the generic interfaces described in the base CCM and GCM documents, and David Mc Grew's RFC on AEAD is a subset of those possibilities and is therefor usable with the generic interfaces.
> 
> 
>> 
> In IPSEC GCM, the IV is explicitly included in each packet  (see section 3.1 of RFC4106) and hence is not secret in any way shape or form.
> 
> In IPSEC CCM, the IV is also explicitly included in each packet - see section 3 and 3.1 of RFC 4309.  Hence, also never secret in any way shape or form.

The IV is explicit. The nonce is not. In both cases the 96-bit nonce is composed of 32 implicit salt bits and 64 explicit IV bits.

> Citing your own draft as proof of your own argument is a bit.... well…

That WG draft is in WGLC now, so it it’s doing something that is wrong, now would be a good time to say why. It’s also doing the exact same thing that IPsec has been doing with AEADs since 4106 and TLS since 5288. All of these combined a 64-bit explicit IV with a 32-bit salt that is derived as part of the keying materials (KEYMAT for IPsec, key_block for TLS) and never ever transmitted.

> In any event, I note that your IPSEC draft doesn't actually describe the ESP payload format, so without that, I'd make the assumption that the IV is included before the payload as is described in the IPSEC ESP document.
> 
>> 
> In which of the above?  Maybe in the chacha20 draft... but not in the other two.
> 
> And RFC5288 does it the wrong way - getting IV (session nonce) material from the same key stream as key material.  That hopefully will be fixed with TLS1.3.  It would have been much more preferable to use a zero session nonce than extract it from the key stream.

You are saying that this is wrong. Why?

> I'm pretty sure it doesn't.  It just shows a continuous misunderstanding of the problems with doing it this way.  

And those problems are…?

> There are ways to mitigate this a bit - but they require ensuring complete cryptographic isolation from key generation and a method of non-secret but not disclosed information that can still be used with the generic interfaces.
> 
> There was a good precedence for using RC4 and MD5 because they were fast and in wide use, but we've learned.
> 
> Later, Mike

---

From: Michael StJohns <[email-masked]>
Date: Mon, 27 Apr 2015 14:48:08 -0400

> That WG draft is in WGLC now, so it it’s doing something that is wrong, now would be a good time to say why. It’s also doing the exact same thing that IPsec has been doing with AEADs since 4106 and…

See below:  Basically getting your nonce/IV material from the same key 
stream production of your keys is problematic.  You'd be better off 
specifying a different mechanism for producing such material, even if it 
differs from what is done throughout IPSEC.

But that's a side show and rat hole we need not go down for TLS.

> You are saying that this is wrong. Why?

Because TLS1.2 had eliminated the IV production as part of the key 
expansion from the master secret phase.  The AEAD suites added it back 
in.  Without the IV production, it would have been somewhat easier to 
secure some of the TLS HSM functionality.   And given that zero session 
nonces are completely acceptable and secure, that would have been a fine 
fixed choice  instead of the one that was made.
>> >I'm pretty sure it doesn't.  It just shows a continuous misunderstanding of the problems with doing it this way.

Let me try this one last time.  I must just not be speaking the same 
language as the rest of you.

The generic definition of a KDF both in TLS and IPSEC looks something like:

Key_Stream = KDF (MasterSecret, Mixins, Length Of KeyStream)

The above is deterministic - if you call the same KDF repeatedly with 
the same master secret, mixins and length, you will get the exact same 
key stream.  The details of how you get that key stream differ between 
the two, but you still end up get a block of pseudo-random bytes of a 
certain length.

E.g. pretend I've derived a keystream of 20 octets for IPSEC: 
0x112233445566778899aabbccddeeff0011223344

In both TLS and IPSEC, the key stream is then broken down into parts 
that are assigned to secret keys, and unfortunately to values that are 
not secret (e.g. IV's nonces, etc).   For example, a new KEYMAT is 
generated for each GCM key and broken down into the key and salt (per 
RFC4106 section 8.1).

However, the split in the key stream is under user control.   For both 
TLS and the IPSEC, I can call the appropriate function and assign any 
part of the key stream to secret or public status. While the IPSEC spec 
says to generate 20 octets for a 128 bit GCM key, and to assign 4 octets 
of that to the salt, if I instead assign 0 octets to a key and 20 octets 
to a salt, I've managed to move what I thought was secret into a public 
part.

E.g. the first call gets me an AES key of 
0x112233445566778899aabbccddeeff00 with a salt of 0x11223344; the second 
call by the attacker gets him only a salt of 
0x112233445566778899aabbccddeeff0011223344 which coincidentally has the 
exact same value as the generated key stream.

This is important because calling sequences for HSM versions of these 
KDFs have no way of knowing - FOR A SPECIFIC CALL - the *real* purpose 
of a desired key.   The user may make a call to do the split along the 
16/4 lines, but an attacker can use the same exact call with different 
key targets to get the 0/20 split and extract the derived AES key.

Mixing the production of secret and not-secret data in the same call to 
a KDF without a way of cryptographically isolating the result means that 
you can never be sure of the secrecy of the derived keys in an HSM.

There are ways to mitigate this:  mandatory mixins of the length and 
types of material to be produced to the key stream production phase.  
That way, changes to the keystream to key assignments result in 
completely different keystream material and avoid this problem. An HSM 
can enforce the keystream to key assignments and even allow non-key 
material to be produced IF that is appropriately mixed in.

All of this is generally not a big issue for software only 
implementations because all memory is outside of any assurance boundary 
and the treatment of any stream of bytes as public or secret are matters 
of convention rather than enforced policy.

I'm going to stop talking on this set of threads now.  My head hurts.

Mike