# 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?

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.