Menu

#6 Access 2013 AES_256 fails to decrypt

2.1.2
closed
None
1
2017-02-04
2016-11-26
JLPP
No

The issue we're encountering is that we're able to use Jackcess Encrypt to decrypt most of our Access .accdb databases which we believe were created in 2013 and with encryption method set to legacy, but not others. And we're not sure exactly what was done differently to create the working ones vs. the failing ones. Possibly a mistaken encryption method selection, possibly a group policy or registry difference, or something else.

Here's the stack trace for the files that fail (Jackcess Encrypt 2.1.0):

java.lang.IllegalStateException: EncryptionHeader[_flags=12,_sizeExtra=0,_cryptoAlg=AES_256,_hashAlg=SHA1,_keySize=256,_providerType=24,_cspName=Microsoft Enhanced RSA and AES Cryptographic Provider] crypto algorithm must be one of [RC4]
at com.healthmarketscience.jackcess.impl.office.EncryptionHeader.read(EncryptionHeader.java:186)
at com.healthmarketscience.jackcess.impl.office.RC4CryptoAPIProvider.<init>(RC4CryptoAPIProvider.java:52)
at com.healthmarketscience.jackcess.impl.OfficeCryptCodecHandler.create(OfficeCryptCodecHandler.java:118)
at com.healthmarketscience.jackcess.CryptCodecProvider.createHandler(CryptCodecProvider.java:114)
at com.healthmarketscience.jackcess.impl.PageChannel.initialize(PageChannel.java:105)
at com.healthmarketscience.jackcess.impl.DatabaseImpl.<init>(DatabaseImpl.java:516)
at com.healthmarketscience.jackcess.impl.DatabaseImpl.open(DatabaseImpl.java:389)
at com.healthmarketscience.jackcess.DatabaseBuilder.open(DatabaseBuilder.java:248)
...</init></init>

We got as far as putting breakpoints in:
com.healthmarketscience.jackcess.impl.OfficeCryptCodecHandler.create(PasswordCallback callback, PageChannel channel, Charset charset).

For the file that failed, the flow gets to:
else if(((vMajor == 2) || (vMajor == 3) || (vMajor == 4)) && (vMinor == 2))

Then into:
if(EncryptionHeader.isFlagSet(flags, EncryptionHeader.FCRYPTO_API_FLAG)) {

Then into:
} else {

Where it gets to the following line, which we were surprised to see since the header says AES_256 rather than RC4:
// OC: 2.3.5.1 - RC4 CryptoAPI Encryption: (2,3,4),2
handler = new RC4CryptoAPIProvider(channel, encodingKey, encProvBuf, pwdBytes);

But even when forcing the flags to get the flow to the following line, it gets further along but eventually errors out anyway:
// OC: 2.3.4.5 - Standard Encryption: (3,4),2
handler = new ECMAStandardEncryptionProvider(channel, encodingKey, encProvBuf, pwdBytes);

MS Access 2013 can open the same database that fails.

Attaced is a newly created DB from Access 2013 using the "legacy" encryption method. It fails in the same way. The password of the file is 'password'.

1 Attachments

Discussion

  • James Ahlborn

    James Ahlborn - 2016-11-28

    At a first pass, i can't make heads or tails of it. The various encryption header values seem to violate what is allowed according to the crypto api docs ( https://msdn.microsoft.com/en-us/library/dd910529(v=office.12).aspx ). tweaking the code to force it down the ecma route seems to fail when verifying the password. likewise, forcing the algorithm to rc4 also fails.

     
  • JLPP

    JLPP - 2016-11-30

    Here's what we see regarding the seeming violation:

    We read the first 4,096 bytes from the file, of which offset 0x299 marks the start of the cryptographic header, according to spec.

    Some values to note from the test file:
    • Length of encryptionHeader: 224
    • vMajor: 4
    • vMinor: 2
    • Flags: 12
    • AlgId: 26128 -> 0x00006610
    • AlgId hash: 32772
    • Key Size: 256

    Per the spec, the value of “Flags” is used to determine if Flags.fCryptoAPI, Flags.fAES and Flags.fExternal are set.

    According to the spec, the flag layout for AlgId: 0x00006610 must be the following:
    Flags.fCryptoAPI Flags.fAES Flags.fExternal AlgID Algorithm
    1 1 0 0x00006610 256-bit AES

    But, the test file is displaying what appears to be an invalid header:
    Flags.fCryptoAPI Flags.fAES Flags.fExternal AlgID Algorithm
    1 0 0 0x00006610 256-bit AES

    For comparison looking at a working access file shows the following header:
    Flags.fCryptoAPI Flags.fAES Flags.fExternal AlgID Algorithm
    1 0 0 0x00006801 RC4

    We appreciate your help.

     
  • James Ahlborn

    James Ahlborn - 2016-11-30

    And, what's more troubling is that even if you force the code to use AES, the code can't decrypt the file successfully. Which seems to imply that the actual encryption used isn't following the spec either (even allowing for the confused flags).

    Do you know what is causing the computer in question to generate the alternate encryption configuration?

     
  • JLPP

    JLPP - 2016-11-30

    We don't know. We have considered the following possibilities:

    • A new/altered Office encryption provider from Microsoft may have been rolled out in a patch.
    • A global policy / registry rollout might have changed the normal behavior and locked us into only certain encryption options.
    • Our MS libraries used by Access and COM may be corrupted. Are you able to open the attached accdb in Access? If so, that might rule out this possibilty.

    We've put a request in to Microsoft to see if they can tell us more about this too.

     

    Last edit: JLPP 2016-11-30
  • James Ahlborn

    James Ahlborn - 2016-11-30

    yes, i can open the file just fine in ms access (2010 and 2013).

    it would be excellent if you could get some details from microsoft, as i don't have any ideas at this point.

     
  • James Ahlborn

    James Ahlborn - 2016-12-03

    Do the systems that generate these files have any interesting values in the registry for:

    HKCU\Software\Policies\Microsoft\Office\14.0\Common\Security
    HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Security\Crypto\CompatMode

     
  • JLPP

    JLPP - 2016-12-05

    I have the following CompatMode setting:
    [HKEY_CURRENT_USER\Software\Policies\Microsoft\office\15.0\access\security\crypto]
    "compatmode"=dword:00000000

    By the way, we've given Microsoft a reproducible test case and spelled out the issue. Namely that the decrypt_fails.accdb fAES comes out as 0, the AlgID comes out as 0x6610, and the spec doesn't allow this combination (http://interoperability.blob.core.windows.net/files/MS-OFFCRYPTO/[MS-OFFCRYPTO].pdf pg 33).

    We'll keep you updated with any news from the ticket.

     
  • JLPP

    JLPP - 2016-12-09

    In Access 2013, with encryption method set to legacy, we tried the following registry settings and got these results in Jackcess. Hopefully this will allow others to experiment to see how the accdb file header changes, whether in agreement or disagreement with Microsoft's spec.

    CompatMode => HKEY_CURRENT_USER\ Software\ Policies\ Microsoft\ office\ 15.0\ access \security\ crypto\ compatmode

    defaultencryption12 => HKEY_CURRENT_USER\ Software\ Policies\ Microsoft\ office\ 15.0\ common\ security\ defaultencryption12

    AES 256 => Microsoft Enhanced RSA and AES Cryptographic Provider,AES 256,256

    RC4 40 => Microsoft Enhanced Cryptographic Provider v1.0,RC4,40

    CompatMode defaultencryption12 Able to decrypt in Jackcess?
    0 AES 256 No
    1 AES 256 Yes
    Absent AES 256 No
    0 RC4 40 Yes
    1 RC4 40 Yes
    Absent RC4 40 Yes
     

    Last edit: JLPP 2016-12-09
  • James Ahlborn

    James Ahlborn - 2016-12-10

    That's curious that jackess can handle the rc4 encryption in all cases. what headers end up in the access db in those cases?

     
  • JLPP

    JLPP - 2016-12-12

    The results of the RC4 40 CompatMode tests are below. Note that we copied Jackcess's header code and printed the results. For CompatMode 1 this code failed (see exception stack) but Jackcess was still able to decrypt the file and read the table. We probably didn't copy all of the necessary header read code so I think this is a false negative. Accdb files are attached.

    java -cp jackcess-encrypt-2.1.0.jar;jackcess-2.1.1.jar;bcprov-jdk15on-1.46.jar;org.apache.commons.logging_1.0.4.jar;commons-lang-2.6.jar;. MicrosoftSupportReproduceTest h:\decrypt_test_defaultencryption12_rc4_40_compatmode_1.accdb password
    Number of bytes available: 376832
    We read : 4096
    Length of encryptionHeader: 1055
    vMajor: 4
    vMinor: 4
    Flags: 64
    Flags binary: 01000000
    fAES binary: 00100000
    Bitwise and of flags and fAES (HERE'S THE fAES VALUE): 0
    curPos=679
    headerLen=1836597052
    Nothing we can do, had an exception on file. h:\decrypt_test_defaultencryption12_rc4_40_compatmode_1.accdb
    java.lang.IllegalArgumentException
            at java.nio.Buffer.limit(Unknown Source)
            at MicrosoftSupportReproduceTest.getEncryptionInfo(MicrosoftSupportReproduceTest.java:132)
            at MicrosoftSupportReproduceTest.testJackcessDatabaseOpen(MicrosoftSupportReproduceTest.java:55)
            at MicrosoftSupportReproduceTest.main(MicrosoftSupportReproduceTest.java:45)
    Continuing w/ file read...        
    Jackcess read table successfully: Table5
    
    java -cp jackcess-encrypt-2.1.0.jar;jackcess-2.1.1.jar;bcprov-jdk15on-1.46.jar;org.apache.commons.logging_1.0.4.jar;commons-lang-2.6.jar;. MicrosoftSupportReproduceTest h:\decrypt_test_defaultencryption12_rc4_40_compatmode_0.accdb password
    Number of bytes available: 376832
    We read : 4096
    Length of encryptionHeader: 198
    vMajor: 4
    vMinor: 2
    Flags: 12
    Flags binary: 00001100
    fAES binary: 00100000
    Bitwise and of flags and fAES (HERE'S THE fAES VALUE): 0
    curPos=679
    headerLen=126
    Flags again: 12
    Flags again binary: 00001100
    fAES again binary: 00100000
    Bitwise and of flags again and fAES (HERE'S THE fAES VALUE): 0
    Size Extra: 0
    HERE'S THE AlgId: 0x6801
    AlgId hash: 0x8004
    Key Size: 40
    Provider Type 1
    Parsed Crypto algorithm: RC4
    Parsed Hash Algorithm: SHA1
    CSP Name: Microsoft Enhanced Cryptographic Provider v1.0
    Continuing w/ file read...        
    Jackcess read table successfully: Table7
    
    java -cp jackcess-encrypt-2.1.0.jar;jackcess-2.1.1.jar;bcprov-jdk15on-1.46.jar;org.apache.commons.logging_1.0.4.jar;commons-lang-2.6.jar;. MicrosoftSupportReproduceTest h:\decrypt_test_defaultencryption12_rc4_40_no_compatmode.accdb password
    Number of bytes available: 376832
    We read : 4096
    Length of encryptionHeader: 198
    vMajor: 4
    vMinor: 2
    Flags: 12
    Flags binary: 00001100
    fAES binary: 00100000
    Bitwise and of flags and fAES (HERE'S THE fAES VALUE): 0
    curPos=679
    headerLen=126
    Flags again: 12
    Flags again binary: 00001100
    fAES again binary: 00100000
    Bitwise and of flags again and fAES (HERE'S THE fAES VALUE): 0
    Size Extra: 0
    HERE'S THE AlgId: 0x6801
    AlgId hash: 0x8004
    Key Size: 40
    Provider Type 1
    Parsed Crypto algorithm: RC4
    Parsed Hash Algorithm: SHA1
    CSP Name: Microsoft Enhanced Cryptographic Provider v1.0
    Continuing w/ file read...        
    Jackcess read table successfully: Table2
    
     

    Last edit: JLPP 2016-12-12
  • JLPP

    JLPP - 2016-12-19

    We've heard more from Microsoft support on this. Here are the highlights:

    a. We should not be using defaultencryption12 of AES 256 with the legacy encryption method in Access (as was the case for decrypt_fails.accdb). This is not a supported configuration because the legacy encryption method must use a stream cipher such as RC4. Though a file can be generated using the legacy encryption method and a block cipher (e.g. AES – see decrypt_fails.accdb) and it may be readable by Access itself and Microsoft libraries, it is still not supported.

    Documents that are saved in the older Office binary formats can only be encrypted by using RC4 to maintain compatibility with older versions of Office. AES, the default and recommended encryption algorithm, is used to encrypt Open XML Format files.

    References:

    Compatibility with previous versions of Office - https://technet.microsoft.com/en-us/library/cc179125.aspx

    b. If we want to use the legacy encryption method in Access in a supported configuration, we must use the RC4 provider, not AES.

    c. If we want to use RC4 40, we should remove the defaultencryption12 key, leave the compatmode set to 0 (or unset?), and continue to use the legacy encryption method in Access. Files will then be written as RC4 40.

    d. If we want to use RC4 128, we should set defaultencryption12 to RC4 128, leave the compatmode to 0, and continue to use the legacy encryption method in Access. Files will then be written as RC4 128.

    Microsoft did not comment on what is happening when the legacy encryption method is used with block cipher. For instance, is the legacy setting ignored and the cipher overrides? Or vice versa? They only warned that the results could be unpredictible.

     
    • James Ahlborn

      James Ahlborn - 2016-12-19

      So, it sounds like jackcess encrypt is handling the "valid" options. As for the "unpredictable" results that ms access clearly handles, i have no ideas. i tried a variety of different possibilities (both aes/rc4 and "stream" versions of aes) and couldn't find anything which successfully decrypted the file.

      so, is this ticket essentially a "won't fix"? i mean, i'd certainly love to make it work even in this unsupported case, but i don't see a means to figuring it out...

       

      Last edit: James Ahlborn 2016-12-19
  • Vladimir B.

    Vladimir B. - 2017-01-29

    James,

    As requested I finally had few hours to look into the code and compatibility. Here is high level logic that would need to be implemented to support the attached decrypt_fails.accdb.

    1. There seems to be the bug with key derivation function. The index is fixed at 0 instead of updating at i. Not sure how this worked before.
    Index: src/main/java/com/healthmarketscience/jackcess/impl/office/ECMAStandardEncryptionProvider.java
    ===================================================================
    --- src/main/java/com/healthmarketscience/jackcess/impl/office/ECMAStandardEncryptionProvider.java      (revision 116)
    +++ src/main/java/com/healthmarketscience/jackcess/impl/office/ECMAStandardEncryptionProvider.java      (working copy)
    
    @@ -127,7 +130,7 @@
         byte[] x = fill(new byte[64], code);
    
         for(int i = 0; i < finalHash.length; ++i) {
    
    -      x[0] ^= finalHash[i];
    +      x[i] ^= finalHash[i];
         }
    
         return x;
    
    1. For this use case OfficeCryptCodecHandler needs to use ECMAStandardEncryptionProvider despite FAES_FLAG not being set.

    2. In the mode used with the DB the 50K hashing iterations need to be skipped. The hacky code to illustrate is:

    Index: src/main/java/com/healthmarketscience/jackcess/impl/office/ECMAStandardEncryptionProvider.java
    ===================================================================
    --- src/main/java/com/healthmarketscience/jackcess/impl/office/ECMAStandardEncryptionProvider.java      (revision 116)
    +++ src/main/java/com/healthmarketscience/jackcess/impl/office/ECMAStandardEncryptionProvider.java      (working copy)
    @@ -113,7 +113,10 @@
         Digest digest = getDigest();
    
         // OC: 2.3.4.7 (after part 1)
    
    -    byte[] iterHash = iterateHash(baseHash, iterations);
    +//    byte[] iterHash = iterateHash(baseHash, iterations);
    +    
    +    byte[] iterHash = baseHash;
    +    
    
         byte[] finalHash = hash(digest, iterHash, blockBytes);
    

    With above hacks I am able to open the DB.

    Hope this will allow you to add support for this unsual mode of encryption

    Vladimir

     

    Last edit: Vladimir B. 2017-01-29
  • James Ahlborn

    James Ahlborn - 2017-01-30

    Good news, I think we now have a working algorithm! (just got a chance to test Vladimir's changes out) Hopefully i will be able to get it into the code base in the next few days.

    Thanks again, Vladimir!

     

    Last edit: James Ahlborn 2017-01-30
  • James Ahlborn

    James Ahlborn - 2017-01-31
    • Group: Unassigned --> 2.1.2
     
  • James Ahlborn

    James Ahlborn - 2017-01-31

    I've made changes to trunk, targeted at the 2.1.2 release, which work with the example database. It would be great if you could test out the changes on your real databases.

     
  • JLPP

    JLPP - 2017-01-31

    Wow! Thank you to you both, James and Vladimir. We will do what we can to test the latest changes with our sample Access databases over the next few days and let you know what we find. Thanks again.

     
  • JLPP

    JLPP - 2017-02-03

    All tests passed. Tested the following scenarios:

    defaultencryption12 + aes 256 + compatmode 0
    defaultencryption12 + aes 256 + compatmode 1
    defaultencryption12 + aes 256 + no compatmode
    defaultencryption12 + rc4 128 + compatmode 0
    defaultencryption12 + rc4 128 + compatmode 1
    defaultencryption12 + rc4 128 + no compatmode
    defaultencryption12 + rc4 40 + compatmode 0
    defaultencryption12 + rc4 40 + compatmode 1
    defaultencryption12 + rc4 40 + no compatmode

    Thank you again.

     
  • James Ahlborn

    James Ahlborn - 2017-02-04

    awesome!

    fixed in trunk, will be in the 2.1.2 release.

     
  • James Ahlborn

    James Ahlborn - 2017-02-04
    • status: open --> closed
     

Log in to post a comment.

MongoDB Logo MongoDB