diff --git a/src/libmdb/file.c b/src/libmdb/file.c index 58450aa..697f423 100644 --- a/src/libmdb/file.c +++ b/src/libmdb/file.c @@ -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 + */ + +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) diff --git a/src/libmdb/write.c b/src/libmdb/write.c index 24f9040..31b9b62 100644 --- a/src/libmdb/write.c +++ b/src/libmdb/write.c @@ -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) {