Skip to content

Commit

Permalink
Office formats: Support Office 2007 documents using 256-bit keys.
Browse files Browse the repository at this point in the history
Before this, the CPU format bailed out with an error while the OpenCL
format unfortunately just produced false negatives.

Closes openwall#4780
  • Loading branch information
magnumripper committed Aug 9, 2021
1 parent c2ed3a6 commit b2709ed
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 39 deletions.
5 changes: 5 additions & 0 deletions doc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ Major changes from 1.9.0-jumbo-1 (May 2019) in this bleeding-edge version:

- Add BestCrypt Volume Encryption V4 format. [Jean-Christophe Delaunay; 2021]

- Added missing code to the Office formats for cracking Office 2007 documents
with a 256-bit key (apparently very uncommon). The CPU format would bail
with a message (hence the issue reported) but unfortunately the OpenCL format
just produced false negatives until now. [magnum; 2021]


Major changes from 1.8.0-jumbo-1 (December 2014) to 1.9.0-jumbo-1 (May 2019):

Expand Down
39 changes: 32 additions & 7 deletions run/opencl/office_kernel.cl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Office 2007, 2010 and 2013 formats
*
* Copyright 2012-2017, magnum
* Copyright 2012-2021, magnum
* This software is hereby released to the general public under
* the following terms: Redistribution and use in source and binary
* forms, with or without modification, are permitted.
Expand Down Expand Up @@ -122,6 +122,7 @@ void HashLoop0710(__global ms_office_state *state)
__kernel
void Final2007(__global ms_office_state *state,
__global ms_office_out *out,
__constant ms_office_salt *salt,
__constant ms_office_blob *blob)
{
uint i;
Expand All @@ -130,6 +131,10 @@ void Final2007(__global ms_office_state *state,
uchar c[20];
uint w[20/4];
} output;
union {
uchar c[40];
uint w[40/4];
} X3;
uint gid = get_global_id(0);
union {
unsigned char c[16];
Expand Down Expand Up @@ -178,19 +183,39 @@ void Final2007(__global ms_office_state *state,
W[i] = output.w[i] ^ 0x36363636;
for (i = 5; i < 16; i++)
W[i] = 0x36363636;
sha1_single(uint, W, output.w);
sha1_single(uint, W, X3.w);
/* sha1_final (last block was 64 bytes) */
W[0] = 0x80000000;
for (i = 1; i < 6; i++)
W[i] = 0;
W[15] = 64 << 3;
sha1_block_160Z(uint, W, output.w);
sha1_block_160Z(uint, W, X3.w);

/* Endian-swap to output (we only use 16 bytes) */
for (i = 0; i < 4; i++)
output.w[i] = SWAP32(output.w[i]);
/* Endian-swap to output */
for (i = 0; i < 5; i++)
X3.w[i] = SWAP32(X3.w[i]); /* This is X1 in MS-OFFCRYPTO */

if (salt->verifierHashSize < salt->keySize / 8) {
uint *X2 = &X3.w[5];

for (i = 0; i < 5; i++)
W[i] = output.w[i] ^ 0x5c5c5c5c;
for (i = 5; i < 16; i++)
W[i] = 0x5c5c5c5c;
sha1_single(uint, W, X2);
/* sha1_final (last block was 64 bytes) */
W[0] = 0x80000000;
for (i = 1; i < 6; i++)
W[i] = 0;
W[15] = 64 << 3;
sha1_block_160Z(uint, W, X2);

/* Endian-swap to output */
for (i = 0; i < 5; i++)
X2[i] = SWAP32(X2[i]);
}

AES_set_decrypt_key(output.c, 128, &akey);
AES_set_decrypt_key(X3.c, salt->keySize, &akey);
AES_ecb_decrypt(blob->encryptedVerifier, decryptedVerifier.c, 16, &akey);
AES_ecb_decrypt(blob->encryptedVerifierHash, decryptedVerifierHash.c, 16, &akey);

Expand Down
57 changes: 27 additions & 30 deletions src/office_fmt_plug.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Office 2007 cracker patch for JtR. This software is
* Copyright (c) 2012 Dhiru Kholia <dhiru.kholia at gmail.com>.
* Copyright (c) 2012-2019 magnum
* Copyright (c) 2012-2021 magnum
* and is hereby released to the general public under the following terms:
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
Expand Down Expand Up @@ -83,6 +83,8 @@ static struct fmt_tests office_tests[] = {
{"$office$*2007*20*128*16*fbd4cc5dab9b8e341778ddcde9eca740*46bef371486919d4bffe7280110f913d*b51af42e6696baa097a7109cebc3d0ff7cc8b1d8", "myhovercraftisfullofeels"},
/* 2007-Default_myhovercraftisfullofeels_.xltx */
{"$office$*2007*20*128*16*fbd4cc5dab9b8e341778ddcde9eca740*1addb6823689aca9ce400be8f9e55fc9*e06bf10aaf3a4049ffa49dd91cf9e7bbf88a1b3b", "myhovercraftisfullofeels"},
/* Github issue #4780 (256-bit key length) */
{"$office$*2007*20*256*16*3e94c22e93f35e14162402da444dec28*7057eb00b1e0e1cce5c85ba0727e9686*ff4f3a5a9e872c364e6d83f07af904ce518b53e6", "12Qwaszx"},
/* 2010-Default_myhovercraftisfullofeels_.docx */
{"$office$*2010*100000*128*16*213aefcafd9f9188e78c1936cbb05a44*d5fc7691292ab6daf7903b9a8f8c8441*46bfac7fb87cd43bd0ab54ebc21c120df5fab7e6f11375e79ee044e663641d5e", "myhovercraftisfullofeels"},
/* 2010-Default_myhovercraftisfullofeels_.dotx */
Expand Down Expand Up @@ -122,7 +124,7 @@ static UTF16 (*saved_key)[PLAINTEXT_LENGTH + 1];
static int *saved_len;
static int *cracked;

static uint8_t (*encryptionKey)[20];
static uint8_t (*encryptionKey)[40];
static uint8_t (*verifierKeys1)[64];
static uint8_t (*verifierKeys512)[128];

Expand Down Expand Up @@ -161,47 +163,45 @@ static void done(void)
MEM_FREE(verifierKeys512);
}

static uint8_t *DeriveKey(uint8_t *hashValue, uint8_t *X1)
static uint8_t *DeriveKey(uint8_t *hashValue, uint8_t *X3)
{
int i;
uint8_t derivedKey[64];
SHA_CTX ctx;
int cbRequiredKeyLength = cur_salt->keySize / 8;
uint8_t *X1 = X3;
uint8_t *X2 = &X3[20];

// This is step 4a in 2.3.4.7 of MS_OFFCRYPT version 1.0
// and is required even though the notes say it should be
// used only when the encryption algorithm key > hash length.
// See 2.3.4.7 of MS-OFFCRYPTO
for (i = 0; i < 64; i++)
derivedKey[i] = (i < 20 ? 0x36 ^ hashValue[i] : 0x36);

SHA1_Init(&ctx);
SHA1_Update(&ctx, derivedKey, 64);
SHA1_Final(X1, &ctx);

if (cur_salt->verifierHashSize > cur_salt->keySize / 8)
return X1;
if (cur_salt->verifierHashSize < cbRequiredKeyLength) {
for (i = 0; i < 64; i++)
derivedKey[i] = (i < 20 ? 0x5C ^ hashValue[i] : 0x5C);

/* TODO: finish up this function */
//for (i = 0; i < 64; i++)
// derivedKey[i] = (i < 30 ? 0x5C ^ hashValue[i] : 0x5C);

fprintf(stderr, "\n\n*** ERROR: DeriveKey() entered Limbo.\n");
fprintf(stderr, "Please report to john-dev mailing list.\n");
error();
SHA1_Init(&ctx);
SHA1_Update(&ctx, derivedKey, 64);
SHA1_Final(X2, &ctx);
}

return NULL;
return X3;
}

#ifdef SIMD_COEF_32
static void GeneratePasswordHashUsingSHA1(int idx,
uint8_t final[SHA1_LOOP_CNT][20])
static void GeneratePasswordHashUsingSHA1(int idx, uint8_t final[SHA1_LOOP_CNT][40])
{
uint8_t hashBuf[20];
/*
* H(0) = H(salt, password)
* hashBuf = SHA1Hash(salt, password);
* create input buffer for SHA1 from salt and unicode version of password
*/
uint8_t X1[20];
uint8_t X3[40];
SHA_CTX ctx;
uint8_t _IBuf[64*SHA1_LOOP_CNT + MEM_ALIGN_CACHE], *keys;
uint32_t *keys32;
Expand Down Expand Up @@ -270,12 +270,11 @@ static void GeneratePasswordHashUsingSHA1(int idx,

/* Now convert back into a 'flat' value, which is a flat array. */
for (i = 0; i < SHA1_LOOP_CNT; i++)
memcpy(final[i], DeriveKey(&keys[20 * i], X1), cur_salt->keySize / 8);
memcpy(final[i], DeriveKey(&keys[20 * i], X3), cur_salt->keySize / 8);
}
#else
// for non SIMD, SHA1_LOOP_CNT is 1
static void GeneratePasswordHashUsingSHA1(int idx,
uint8_t final[SHA1_LOOP_CNT][20])
static void GeneratePasswordHashUsingSHA1(int idx, uint8_t final[SHA1_LOOP_CNT][40])
{
uint8_t hashBuf[20], *key;
UTF16 *passwordBuf = saved_key[idx];
Expand All @@ -286,7 +285,7 @@ static void GeneratePasswordHashUsingSHA1(int idx,
* create input buffer for SHA1 from salt and unicode version of password
*/
uint32_t inputBuf[(0x14 + 0x04 + 4) / sizeof(int)];
uint8_t X1[20];
uint8_t X3[40];
int i;
SHA_CTX ctx;

Expand Down Expand Up @@ -327,11 +326,10 @@ static void GeneratePasswordHashUsingSHA1(int idx,
SHA1_Update(&ctx, &inputBuf[1], 0x14 + 0x04);
SHA1_Final(hashBuf, &ctx);

key = DeriveKey(hashBuf, X1);
key = DeriveKey(hashBuf, X3);

/*
* Should handle the case of longer key lengths as shown in 2.3.4.9
* Grab the key length bytes of the final hash as the encrypytion key
* Grab the key length bytes of the final hash as the encryption key
*/
memcpy(final[0], key, cur_salt->keySize / 8);
}
Expand Down Expand Up @@ -477,8 +475,7 @@ static void GenerateAgileEncryptionKey(int idx,
#endif

#ifdef SIMD_COEF_64
static void GenerateAgileEncryptionKey512(int idx,
uint8_t hashBuf[SHA512_LOOP_CNT][128])
static void GenerateAgileEncryptionKey512(int idx, uint8_t hashBuf[SHA512_LOOP_CNT][128])
{
uint8_t tmpBuf[64], *keys;
uint32_t i, j, k;
Expand Down Expand Up @@ -646,11 +643,11 @@ static int PasswordVerifier(ms_office_binary_blob *blob, uint8_t *key)
SHA_CTX ctx;
uint8_t checkHash[20];

AES_set_decrypt_key(key, 128, &akey);
AES_set_decrypt_key(key, cur_salt->keySize, &akey);
AES_ecb_encrypt(blob->encryptedVerifier, decryptedVerifier,
&akey, AES_DECRYPT);

AES_set_decrypt_key(key, 128, &akey);
AES_set_decrypt_key(key, cur_salt->keySize, &akey);
AES_ecb_encrypt(blob->encryptedVerifierHash, decryptedVerifierHash,
&akey, AES_DECRYPT);

Expand Down
7 changes: 5 additions & 2 deletions src/opencl_office_fmt_plug.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* MS Office >= 2007 cracker for JtR. OpenCL support by magnum.
*
* This software is Copyright (c) 2012, Dhiru Kholia <dhiru.kholia at gmail.com>
* and Copyright (c) 2012-2017, magnum
* and Copyright (c) 2012-2021, magnum
* and it is hereby released to the general public under the following terms:
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
Expand Down Expand Up @@ -49,6 +49,8 @@ static struct fmt_tests tests[] = {
{"$office$*2010*100000*128*16*213aefcafd9f9188e78c1936cbb05a44*d5fc7691292ab6daf7903b9a8f8c8441*46bfac7fb87cd43bd0ab54ebc21c120df5fab7e6f11375e79ee044e663641d5e", "myhovercraftisfullofeels"},
/* 2013-openwall.pptx */
{"$office$*2013*100000*256*16*9b12805dd6d56f46d07315153f3ecb9c*c5a4a167b51faa6629f6a4caf0b4baa8*87397e0659b2a6fff90291f8e6d6d0018b750b792fefed77001edbafba7769cd", "openwall"},
/* Github issue #4780 (256-bit key length) */
{"$office$*2007*20*256*16*3e94c22e93f35e14162402da444dec28*7057eb00b1e0e1cce5c85ba0727e9686*ff4f3a5a9e872c364e6d83f07af904ce518b53e6", "12Qwaszx"},
#if DEBUG
/* 2007-Default_myhovercraftisfullofeels_.dotx */
{"$office$*2007*20*128*16*56ea65016fbb4eac14a6770b2dbe7e99*8cf82ce1b62f01fd3b2c7666a2313302*21443fe938177e648c482da72212a8848c2e9c80", "myhovercraftisfullofeels"},
Expand Down Expand Up @@ -205,7 +207,8 @@ static void create_clobj(size_t gws, struct fmt_main *self)

HANDLE_CLERROR(clSetKernelArg(Final2007, 0, sizeof(cl_mem), (void*)&cl_state), "Error setting argument 0");
HANDLE_CLERROR(clSetKernelArg(Final2007, 1, sizeof(cl_mem), (void*)&cl_out), "Error setting argument 1");
HANDLE_CLERROR(clSetKernelArg(Final2007, 2, sizeof(cl_mem), (void*)&cl_blob), "Error setting argument 2");
HANDLE_CLERROR(clSetKernelArg(Final2007, 2, sizeof(cl_mem), (void*)&cl_salt), "Error setting argument 2");
HANDLE_CLERROR(clSetKernelArg(Final2007, 3, sizeof(cl_mem), (void*)&cl_blob), "Error setting argument 3");

HANDLE_CLERROR(clSetKernelArg(Generate2010key, 0, sizeof(cl_mem), (void*)&cl_state), "Error setting argument 0");
HANDLE_CLERROR(clSetKernelArg(Generate2010key, 1, sizeof(cl_mem), (void*)&cl_out), "Error setting argument 1");
Expand Down

0 comments on commit b2709ed

Please sign in to comment.