2.3.4.7 ECMA-376 Document Encryption Key Generation (Standard Encryption)
The encryption key for ECMA-376 document encryption [ECMA-376] MUST be generated by using the following method, which is derived from PKCS #5: Password-Based Cryptography Version 2.0 [RFC2898].
Let H() be a hashing algorithm as determined by the EncryptionHeader.AlgIDHash field, Hn be the hash data of the nth iteration, and a plus sign (+) represent concatenation. This hashing algorithm MUST be SHA-1. The password MUST be provided as an array of Unicode characters. Limitations on the length of the password and the characters used by the password are implementation-dependent. The initial password hash is generated as follows:
H0 = H(salt + password)
The salt used MUST be generated randomly and MUST be 16 bytes in size. The salt MUST be stored in the EncryptionVerifier.Salt field contained within the \EncryptionInfo stream (1) as specified in section 2.3.4.5. The hash is then iterated by using the following approach:
Hn = H(iterator + Hn-1)
where iterator is an unsigned 32-bit value that is initially set to 0x00000000 and then incremented monotonically on each iteration until 50,000 iterations have been performed. The value of iterator on the last iteration MUST be 49,999.
After the final hash data has been obtained, the encryption key MUST be generated by using the final hash data, and the block number MUST be 0x00000000. The encryption algorithm MUST be specified in the EncryptionHeader.AlgID field. The encryption algorithm MUST use ECB mode. The method used to generate the hash data that is the input into the key derivation algorithm is as follows:
Hfinal = H(Hn + block)
The encryption key derivation method is specified by the following steps:
Let cbRequiredKeyLength be equal to the size, in bytes, of the required key length for the relevant encryption algorithm as specified by the EncryptionHeader structure. Note that cbRequiredKeyLength MUST be less than or equal to 40.
Let cbHash be the number of bytes output by the hashing algorithm H.
Form a 64-byte buffer by repeating the constant 0x36 64 times. XOR Hfinal into the first cbHash bytes of this buffer, and compute a hash of the resulting 64-byte buffer by using hashing algorithm H. This will yield a hash value of length cbHash. Let the resulting value be called X1.
Form another 64-byte buffer by repeating the constant 0x5C 64 times. XOR Hfinal into the first cbHash bytes of this buffer, and compute a hash of the resulting 64-byte buffer by using hash algorithm H. This yields a hash value of length cbHash. Let the resulting value be called X2.
Concatenate X1 with X2 to form X3, which will yield a value twice the length of cbHash.
Let keyDerived be equal to the first cbRequiredKeyLength bytes of X3.