RC4 CryptoAPI Encryption Password Verification

-=- Dominic Salemno -=-

 

Information security is important in this day and age. The most important core asset of any particular company is their information. Hence, the essential need for cryptography has become more apparent due to the various security breaches that many companies have encountered. Using cryptography, unauthorized access to a company’s information, will show a useless collection of bytes. Only the holder of the *decryption key* can truly understand this raw set of bytes.

Many companies use Microsoft Office documents on a daily basis. Regarding the current topic, Microsoft Office allows the user to encrypt the contents of a specific document to prevent prying eyes viewing data that does not concern them.

Password encrypted documents can be created using several mechanisms all of which are defined in the [MS-OFFCRYPTO].pdf document found on Microsoft’s Open Specifications site (http://msdn.microsoft.com/en-us/library/cc313071.aspx). The focus of this blog is to explain the RC4 CryptoAPI password verification procedure detailed in 2.3.5.6. The encryption mechanism is a combination of RC4 and SHA-1.

The verification procedure itself is broken down into 5 high-level steps. The first step in 2.3.5.6 points to another section (2.3.5.2) which includes an additional 2 steps.

Attached to this posting is an example PowerPoint file that has been encrypted with the password “crypto”. Converting the password string into a sequence of UTF-16 bytes (represented in little-endian byte order), you should get the following:

63 00 72 00 79 00 70 00 74 00 6F 00

This is part of the header with the essential parts needed to explain the password verification process. The rest of the header is contained within the header.txt file attached to this blog with a detail explanation of each field.

EncryptionHeader

KeySize: 00 00 00 00

EncryptionVerifier

Salt:  DB 57 5D DA 2E 45 0A B3 DF DF 77 A2 E9 B3 D4 C7
EncryptedVerifier:  AB 18 3C 4C 8B 5E 5D D7 B9 F3 AF 8A E5 FF F3 1A
EncryptedVerifierHash:  B6 35 94 44 7F AE 7D 49 45 D2 DA FD 11 3F D8 C9 F6 19 1B F5

Now for the fun!

1.       Following section of 2.3.5.2, we generate H0 by performing the following, utilizing the hashing algorithm specified (in this case, SHA-1):

H0 represents the password hash which is generated by the SHA-1 hashing algorithm by performing the following:

H0 = H(salt + password)

H0 = SHA-1 (DB 57 5D DA 2E 45 0A B3 DF DF 77 A2 E9 B3 D4 C7 63 00 72 00 79 00 70 00 74 00 6F 00)
H0 = 99 1A E8 18 8C B3 9B 43 AC AA BA 8B 19 2C 6D 30 44 97 38 53

Following this step the encryption key is generated by using the previous hash data plus the block again using the SHA-1 hashing algorithm:

Hfinal = H(H0 + block)

The block number is a 32-bit number, and according to the documentation will be:

0x00000000

Hfinal = SHA-1 (99 1A E8 18 8C B3 9B 43 AC AA BA 8B 19 2C 6D 30 44 97 38 53 00 00 00 00)
Hfinal = D7 BE C9 31 88 E3 39 D7 7E 1B 99 1E DF 47 C9 8C 8D 6A 99 40

The resulting series of bytes of Hfinal is part of our derived encryption key. Inside of the header is a field denoted “keyLength”. This is the length of the key in *bits*. One must take the first n-bits of the resulting Hfinal operation and this will be the key. However, please note that if keyLength is equal to 0, then consider the key in question to be of 40-bits. Thus, take the first 40-bits of Hfinal. This 40-bit key must then be appended with 88 bits set to zero with the resulting derived encryption key equal to 128 bits).

derived encryption key = D7 BE C9 31 88 00 00 00 00 00 00 00 00 00 00 00

2.       Utilizing the RC4 algorithm, decrypt the EncryptedVerifier field.

DecryptedVerifier =  RC4 (AB 18 3C 4C 8B 5E 5D D7 B9 F3 AF 8A E5 FF F3 1A )
DecryptedVerifier = 44 65 87 98 44 0 0 10 11 41 65 AA A8 BA DC ED

3.       Decrypt the EncryptedVerifierHash field, once again using the RC4 algorithm:

DecryptedVerifierHash = RC4 (B6 35 94 44 7F AE 7D 49 45 D2 DA FD 11 3F D8 C9 F6 19 1B F5)
DecryptedVerifierHash = 97 17 92 3 C1 89 6A 33 C2 C1 E8 2 A6 76 6F 8B 24 E4 B0 7C

4.       Perform the SHA-1 hashing algorithm against the decrypted EncryptedVerifier field (the result of step 2) will give us a particular value that will be used for the final comparison.

SHA-1 (44 65 87 98 44 0 0 10 11 41 65 AA A8 BA DC ED)
Result = 97 17 92 3 C1 89 6A 33 C2 C1 E8 2 A6 76 6F 8B 24 E4 B0 7C

5.       The final step of this verification procedure is to compare the result of the decrypted EncryptedVerifierHash field (the result of step 3) with the SHA-1 hash of the decrypted EncryptedVerifier field (the result of step 4). If these two results are equal, we now know that we have the right password and can proceed to decrypt the entire document. Otherwise, the password is incorrect, and must perform the process again with another password.

Note that when the RC4 call is made, the CryptoAPI does not implicitly reset after a particular operation. Therefore, in most other implementations, it would be the equivalent of taking both the EncryptedVerifier and EncryptedVerifierHash fields and passing them both as if they were one string of contiguous bytes. By using the attached file as an example, we would have the following:

RC4 (AB 18 3C 4C 8B 5E 5D D7 B9 F3 AF 8A E5 FF F3 1A B6 35 94 44 7F AE 7D 49 45 D2 DA FD 11 3F D8 C9 F6 19 1B F5)

The result of which is:

44 65 87 98 44 0 0 10 11 41 65 AA A8 BA DC ED 97 17 92 3 C1 89 6A 33 C2 C1 E8 2 A6 76 6F 8B 24 E4 B0 7C

The first 16 bytes of which are the decrypted EncryptedVerifier, and subsequent 20 bytes are the decrypted EncryptedVerifierHash.

Hope this helps!