# PKCS12 key derivation

In older versions of PKCS#12 there was a key derivation function that, near as I can tell, isn't used anywhere outside of that standard:

https://tools.ietf.org/html/rfc7292#appendix-B

That discusses it. So in that standard there's a loop:

   6.  For i=1, 2, ..., c, do the following:

A.  Set A2=H^r(D||I). (i.e., the r-th hash of D||1,
H(H(H(... H(D||I))))

B.  Concatenate copies of Ai to create a string B of length v
bits (the final copy of Ai may be truncated to create B).

C.  Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit
blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by
setting I_j=(I_j+B+1) mod 2^v for each j.

7.  Concatenate A_1, A_2, ..., A_c together to form a pseudorandom
bit string, A.


There's an open errata against the RFC that suggests that step A ought to read more like this:

Set A2=H^r(D||I). (i.e., the r-th hash of D||I, H(H(H(... H(D||I))))


ie. it ought to replace D||1 with D||I. My question is... should A2 be replaced with Ai? Because if not then it doesn't appear that A2 is actually used anywhere whereas AI is.

Of course, even if that's done... if I is being changed each time then it seems to me like you'd have to be doing hash a lot. Like instead of performing the hash operation c times you'd need to do it this many times:

$$\sum _{ n=1 }^{ c }{ n }$$

Is that a correct interpretation?

## 2 Answers

Yes, it should be Ai, or more exactly A_i denoting subscript. Note that i (the chunk subscript) is not I (the salted password input). I submitted this to rfc-editor in Feb (see https://security.stackexchange.com/questions/112627/what-password-based-key-derivation-does-pkcs-12-use) and they said they were going to fix it; I guess it got lost.

For confirmation you can see the source document from RSAlabs-now-EMC linked there, at least as long as Dell doesn't start mangling the EMC website(s) the way EMC for years mangled the RSAlabs website.

And that PKCS12 PBE is still used, even though PBES2/PBKDF2 from PKCS5v2 is now recommended (and other options like bcrypt, scrypt, Argon2 even more).

There's plenty of inconsistencies in RFC7292 including in Appendix B.

Yes, it should be Ai, or rather A_i (usage is inconsistent). But, rather than the sum expression you included, I believe the hash is computed c * r times.

Then a few lines down you'll notice it says I_j=(I_j+B+1) but I and B are both explicitly defined as octet strings, not integers. Apparently what the implementations do here (at least OpenSSL's crypto/pkcs12/p12_key.c:PKCS12_key_gen_uni does) is treat them as big-endian big integers for the needs of this operation, i.e. the 1 is added to the sum of the last bytes of the v-bit chunks and then the carry flags propagate to preceding bytes.