Patch 120-decrypt from David Mansfield

This commit is contained in:
Brian Bruns 2010-06-17 22:23:45 -04:00
parent 7a073df76e
commit 4c83570d41
2 changed files with 113 additions and 0 deletions

View File

@ -52,8 +52,69 @@ MdbFormatConstants MdbJet3Constants = {
2048, 0x08, 12, 25, 27, 31, 35, 36, 43, 8, 13, 16, 1, 18, 39, 3, 14, 5
};
typedef struct _RC4_KEY
{
unsigned char state[256];
unsigned char x;
unsigned char y;
} RC4_KEY;
#define swap_byte(x,y) t = *(x); *(x) = *(y); *(y) = t
static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, unsigned long pg);
static void RC4_set_key(RC4_KEY *key, int key_data_len, unsigned char *key_data_ptr)
{
unsigned char t;
unsigned char index1;
unsigned char index2;
unsigned char* state;
short counter;
state = &key->state[0];
for(counter = 0; counter < 256; counter++)
state[counter] = counter;
key->x = 0;
key->y = 0;
index1 = 0;
index2 = 0;
for(counter = 0; counter < 256; counter++) {
index2 = (key_data_ptr[index1] + state[counter] + index2) % 256;
swap_byte(&state[counter], &state[index2]);
index1 = (index1 + 1) % key_data_len;
}
}
/*
* this algorithm does 'encrypt in place' instead of inbuff/outbuff
* note also: encryption and decryption use same routine
* implementation supplied by (Adam Back) at <adam at cypherspace dot org>
*/
static void RC4(RC4_KEY *key, int buffer_len, unsigned char * buff)
{
unsigned char t;
unsigned char x;
unsigned char y;
unsigned char* state;
unsigned char xorIndex;
short counter;
x = key->x;
y = key->y;
state = &key->state[0];
for(counter = 0; counter < buffer_len; counter++) {
x = (x + 1) % 256;
y = (state[x] + y) % 256;
swap_byte(&state[x], &state[y]);
xorIndex = (state[x] + state[y]) % 256;
buff[counter] ^= state[xorIndex];
}
key->x = x;
key->y = y;
}
/**
* mdb_find_file:
* @filename: path to MDB (database) file
@ -108,6 +169,8 @@ static char *mdb_find_file(const char *file_name)
MdbHandle *mdb_open(const char *filename, MdbFileFlags flags)
{
MdbHandle *mdb;
int key[] = {0x86, 0xfb, 0xec, 0x37, 0x5d, 0x44, 0x9c, 0xfa, 0xc6, 0x5e, 0x28, 0xe6, 0x13, 0xb6};
int j, pos;
int open_flags;
mdb = (MdbHandle *) g_malloc0(sizeof(MdbHandle));
@ -164,6 +227,42 @@ MdbHandle *mdb_open(const char *filename, MdbFileFlags flags)
mdb_close(mdb);
return NULL;
}
mdb->f->db_key = mdb_get_int32(mdb->pg_buf, 0x3e);
/* I don't know if this value is valid for some versions?
* it doesn't seem to be valid for the databases I have
*
* f->db_key ^= 0xe15e01b9;
*/
mdb->f->db_key ^= 0x4ebc8afb;
/* fprintf(stderr, "Encrypted file, RC4 key seed= %d\n", mdb->f->db_key); */
if (mdb->f->db_key) {
/* write is not supported for encrypted files yet */
mdb->f->writable = FALSE;
/* that should be enought, but reopen the file read only just to be
* sure we don't write invalid data */
close(mdb->f->fd);
open_flags = O_RDONLY;
#ifdef _WIN32
open_flags |= O_BINARY;
#endif
mdb->f->fd = open(mdb->f->filename, open_flags);
if (mdb->f->fd==-1) {
fprintf(stderr, "Couldn't ropen file %s in read only\n", mdb->f->filename);
mdb_close(mdb);
return NULL;
}
}
/* get the db password located at 0x42 bytes into the file */
for (pos=0;pos<14;pos++) {
j = mdb_get_int32(mdb,0x42+pos);
j ^= key[pos];
if ( j != 0)
mdb->f->db_passwd[pos] = j;
else
mdb->f->db_passwd[pos] = '\0';
}
mdb_iconv_init(mdb);
return mdb;
@ -277,6 +376,18 @@ static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, unsigned long pg)
/* fprintf(stderr,"EOF reached %d bytes returned.\n",len, mdb->fmt->pg_size); */
return 0;
}
/*
* unencrypt the page if necessary.
* it might make sense to cache the unencrypted data blocks?
*/
if (pg != 0 && mdb->f->db_key != 0)
{
RC4_KEY rc4_key;
unsigned int tmp_key = mdb->f->db_key ^ pg;
RC4_set_key(&rc4_key, 4, (unsigned char *)&tmp_key);
RC4(&rc4_key, mdb->fmt->pg_size, pg_buf);
}
return len;
}
void mdb_swap_pgbuf(MdbHandle *mdb)

View File

@ -446,6 +446,7 @@ mdb_new_data_pg(MdbCatalogEntry *entry)
return new_pg;
}
/* could be static */
int
mdb_update_indexes(MdbTableDef *table, int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum)
{
@ -476,6 +477,7 @@ mdb_init_index_chain(MdbTableDef *table, MdbIndex *idx)
return 1;
}
/* could be static */
int
mdb_update_index(MdbTableDef *table, MdbIndex *idx, unsigned int num_fields, MdbField *fields, guint32 pgnum, guint16 rownum)
{