OfficeOpenXml: Agile Encryption
Recently danyelljc contacted me to point out that the code associated with an earlier article did not include an example of using the “Agile Encryption” (see section 2.3.4.10 – 2.3.4.15 in MS-OFFCRYPTO) which is used as the default encryption in Office 2010. This post corrects my omission.
Update 2011-05-29: The example decryption code now includes routines which implement password verification and data integrity tests.
Update 2011-06-07: Included an option to use a SHA1 hash that uses the crypto api directly instead of using the managed code implementation of the algorithm. It’s about 2x faster. Also included public properties to make testing the password and data integrity option. In the earlier versions about 5/7th of the time is spent in password verification and data integrity testing.
Update 2012-04-04: @Webie has created a C implementation of the password validation routines for use on Linux using OpenSSL and libgsf (to read OLE Storage files). At this time, support is provided for 2007 and 2010 Agile encryption. You will find his implementation here: https://github.com/magnumripper/magnum-jumbo
Back in 2008 I wrote an article about how to decrypt Office 2007 files and especially to provide some conformance data. There is no conformance data in MS-OFFCRYPTO (the reference document which describes the algorithms to encrypt and decrypt Office documents of all types). The lack of this data makes it difficult for developers to develop code to create their own encryption routines.
Implementing Agile decryption is straight forward. Here’s a class which provides an example implementation. Generally the process of Agile decryption is the same as the “standard” encryption/decryption process (which the earlier post covered) but with some significant differences:
- The “EncryptionInfo” which provides key decryption information is an Xml document rather than binary data
- The package itself is encrypted in 4K blocks.
Warning: The code includes an entry point method (DecryptToArray()) which will not work for you. It relies on one of our libraries to open and access the file type used by Office to store encrypted documents. However it shows the steps you need to take to extract the EncryptionInfo and EncryptedPackage stream content so you are in a position begin the process of decryption.



Nice work on this one – I’ve used it to do password verification. The hash operation is horribly slow though due to the spin count of 100000 (default for 2010 docs). I used a high res timer on the spin loop in GenerateAgileEncryptionKey and got 390ms. By putting the .ComputeHash call directly into this method, I managed to shave off 70ms bringing the time down to 320ms. What’s more is that GenerateAgileEncryptionKey is called twice for a single password verification and that time coupled with the overhead of the other ops (decrypt and one-time hashing) brings the time up to about 800ms/core on my machine.
When I started experimenting with this using your initial project, I thought I’d get substantially better performance on that type of implementation as opposed to using the Excel API. However, using that API I get around 10 attempts/sec/core – 12x faster than the .net implementation! I expect a good chunk of the time is going to marshaling the data but to get decent performance you’d need to write an unmanaged implementation of at least the GenerateAgileEncryptionKey method.
According to http://blogs.msdn.com/b/david_leblanc/archive/2008/12/04/new-improved-office-crypto.aspx, Elcomsoft achieved 5000 iterations/sec on the Standard version. If memory serves, that version only used one “spun” hash operation with a spin count of 50000. That would bring the relative number down to 1500/sec which still seems very fast by comparison.