mirror of
https://github.com/mdbtools/mdbtools.git
synced 2025-04-05 20:31:00 +08:00
Patch 120-decrypt from David Mansfield
This commit is contained in:
parent
7a073df76e
commit
4c83570d41
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user