From 873c6a027e644c22ebb8e15ca11b17519d584def Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 17 May 2021 07:21:44 +0200 Subject: [PATCH 1/5] Extract RC4 code to separate file --- include/mdbtools.h | 3 ++ src/libmdb/Makefile.am | 2 +- src/libmdb/file.c | 76 +++++------------------------------------- src/libmdb/rc4.c | 67 +++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 69 deletions(-) create mode 100644 src/libmdb/rc4.c diff --git a/include/mdbtools.h b/include/mdbtools.h index cbe1fd0..e524239 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -648,6 +648,9 @@ void mdb_iconv_init(MdbHandle *mdb); void mdb_iconv_close(MdbHandle *mdb); const char* mdb_target_charset(MdbHandle *mdb); +/* rc4.c */ +void mdb_rc4(unsigned char *key, guint32 key_len, unsigned char *buf, guint32 buf_len); + /** @}*/ #ifdef __cplusplus diff --git a/src/libmdb/Makefile.am b/src/libmdb/Makefile.am index 29436fd..ec6cc23 100644 --- a/src/libmdb/Makefile.am +++ b/src/libmdb/Makefile.am @@ -1,5 +1,5 @@ lib_LTLIBRARIES = libmdb.la -libmdb_la_SOURCES= catalog.c file.c table.c data.c dump.c backend.c money.c sargs.c index.c like.c write.c stats.c map.c props.c worktable.c options.c iconv.c version.c +libmdb_la_SOURCES= catalog.c file.c table.c data.c dump.c backend.c money.c sargs.c index.c like.c write.c stats.c map.c props.c worktable.c options.c iconv.c version.c rc4.c libmdb_la_LDFLAGS = -version-info $(VERSION_INFO) if FAKE_GLIB libmdb_la_SOURCES += fakeglib.c diff --git a/src/libmdb/file.c b/src/libmdb/file.c index bffd71c..15eef5d 100644 --- a/src/libmdb/file.c +++ b/src/libmdb/file.c @@ -66,69 +66,8 @@ MdbFormatConstants MdbJet3Constants = { .tab_row_col_num_offset = 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 @@ -232,10 +171,13 @@ static MdbHandle *mdb_handle_from_stream(FILE *stream, MdbFileFlags flags) { return NULL; } - RC4_KEY rc4_key; - unsigned int tmp_key = 0x6b39dac7; - RC4_set_key(&rc4_key, 4, (unsigned char *)&tmp_key); - RC4(&rc4_key, mdb->f->jet_version == MDB_VER_JET3 ? 126 : 128, mdb->pg_buf + 0x18); + guint32 tmp_key = 0x6b39dac7; + mdb_rc4( + (unsigned char *)&tmp_key, + 4, + mdb->pg_buf + 0x18, + mdb->f->jet_version == MDB_VER_JET3 ? 126 : 128 + ); if (mdb->f->jet_version == MDB_VER_JET3) { mdb->f->lang_id = mdb_get_int16(mdb->pg_buf, 0x3a); @@ -436,10 +378,8 @@ static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, unsigned long pg) */ 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); + mdb_rc4((unsigned char*)&tmp_key, 4, pg_buf, mdb->fmt->pg_size); } return mdb->fmt->pg_size; diff --git a/src/libmdb/rc4.c b/src/libmdb/rc4.c new file mode 100644 index 0000000..5d50b96 --- /dev/null +++ b/src/libmdb/rc4.c @@ -0,0 +1,67 @@ +#include "mdbtools.h" + +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 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; +} + +void mdb_rc4(unsigned char *key, guint32 key_len, unsigned char *buf, guint32 buf_len) { + RC4_KEY rc4_key; + RC4_set_key(&rc4_key, key_len, key); + RC4(&rc4_key, buf_len, buf); +} \ No newline at end of file From 89ce71637c5d8b669badd833a8b604bab92f5c91 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 17 May 2021 07:27:49 +0200 Subject: [PATCH 2/5] Re-encrypt pages on write --- src/libmdb/file.c | 2 -- src/libmdb/write.c | 18 +++++++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/libmdb/file.c b/src/libmdb/file.c index 15eef5d..f7cd2d0 100644 --- a/src/libmdb/file.c +++ b/src/libmdb/file.c @@ -191,8 +191,6 @@ static MdbHandle *mdb_handle_from_stream(FILE *stream, MdbFileFlags flags) { /* Bug - JET3 supports 20 byte passwords, this is currently just 14 bytes */ memcpy(mdb->f->db_passwd, mdb->pg_buf + 0x42, sizeof(mdb->f->db_passwd)); } - /* write is not supported for encrypted files yet */ - mdb->f->writable = mdb->f->writable && !mdb->f->db_key; mdb_iconv_init(mdb); diff --git a/src/libmdb/write.c b/src/libmdb/write.c index 891b121..8501522 100644 --- a/src/libmdb/write.c +++ b/src/libmdb/write.c @@ -16,6 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include "mdbtools.h" @@ -70,6 +71,7 @@ mdb_write_pg(MdbHandle *mdb, unsigned long pg) { ssize_t len; off_t offset = pg * mdb->fmt->pg_size; + unsigned char *buf = mdb->pg_buf; fseeko(mdb->f->stream, 0, SEEK_END); /* is page beyond current size + 1 ? */ @@ -78,7 +80,21 @@ mdb_write_pg(MdbHandle *mdb, unsigned long pg) return 0; } fseeko(mdb->f->stream, offset, SEEK_SET); - len = fwrite(mdb->pg_buf, 1, mdb->fmt->pg_size, mdb->f->stream); + + if (pg != 0 && mdb->f->db_key != 0) + { + buf = g_malloc(mdb->fmt->pg_size); + memcpy(buf, mdb->pg_buf, mdb->fmt->pg_size); + unsigned int tmp_key = mdb->f->db_key ^ pg; + mdb_rc4((unsigned char*)&tmp_key, 4, buf, mdb->fmt->pg_size); + } + + len = fwrite(buf, 1, mdb->fmt->pg_size, mdb->f->stream); + + if (buf != mdb->pg_buf) { + g_free(buf); + } + if (ferror(mdb->f->stream)) { perror("write"); return 0; From 5fb273fb60b322bcbbc3ccc51da361610d7406a0 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Mon, 17 May 2021 15:47:59 +0200 Subject: [PATCH 3/5] Fix accidental include --- src/libmdb/write.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libmdb/write.c b/src/libmdb/write.c index 8501522..2909501 100644 --- a/src/libmdb/write.c +++ b/src/libmdb/write.c @@ -16,7 +16,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include #include #include "mdbtools.h" From ee5789ebc7a1c5df7113f403b4aa08632bd1e785 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Tue, 18 May 2021 07:20:58 +0200 Subject: [PATCH 4/5] Review comments --- include/mdbprivate.h | 8 ++++++-- src/libmdb/rc4.c | 20 +++++++++++++++++++- src/libmdb/write.c | 5 ++--- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/include/mdbprivate.h b/include/mdbprivate.h index 88c625d..02204cb 100644 --- a/include/mdbprivate.h +++ b/include/mdbprivate.h @@ -19,13 +19,17 @@ #ifndef _mdbprivate_h_ #define _mdbprivate_h_ +#include "mdbtools.h" + /* - * This header is for stuff lacking a MDB_ or mdb_ something, so they won't be - * exported to calling programs. + * This header is for stuff lacking a MDB_ or mdb_ something, or functions only + * used within mdbtools so they won't be exported to calling programs. */ #ifndef HAVE_G_MEMDUP2 #define g_memdup2 g_memdup #endif +void mdb_rc4(unsigned char *key, guint32 key_len, unsigned char *buf, guint32 buf_len); + #endif diff --git a/src/libmdb/rc4.c b/src/libmdb/rc4.c index 5d50b96..2956d17 100644 --- a/src/libmdb/rc4.c +++ b/src/libmdb/rc4.c @@ -1,4 +1,22 @@ -#include "mdbtools.h" +/* MDB Tools - A library for reading MS Access database files + * Copyright (C) 2000 Brian Bruns + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "mdbprivate.h" typedef struct _RC4_KEY { diff --git a/src/libmdb/write.c b/src/libmdb/write.c index 2909501..1d791ab 100644 --- a/src/libmdb/write.c +++ b/src/libmdb/write.c @@ -18,7 +18,7 @@ #include #include -#include "mdbtools.h" +#include "mdbprivate.h" //static int mdb_copy_index_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg); static int mdb_add_row_to_leaf_pg(MdbTableDef *table, MdbIndex *idx, MdbIndexPage *ipg, MdbField *idx_fields, guint32 pgnum, guint16 rownum); @@ -82,8 +82,7 @@ mdb_write_pg(MdbHandle *mdb, unsigned long pg) if (pg != 0 && mdb->f->db_key != 0) { - buf = g_malloc(mdb->fmt->pg_size); - memcpy(buf, mdb->pg_buf, mdb->fmt->pg_size); + buf = g_memdup2(mdb->pg_buf, mdb->fmt->pg_size); unsigned int tmp_key = mdb->f->db_key ^ pg; mdb_rc4((unsigned char*)&tmp_key, 4, buf, mdb->fmt->pg_size); } From 9401d3cd844b32eda81e4a8ee4e41587bd34a15f Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Wed, 19 May 2021 07:45:43 +0200 Subject: [PATCH 5/5] Rename function to mdbi_rc4 to prevent it from being exported --- include/mdbprivate.h | 14 +++++++++++--- include/mdbtools.h | 3 --- src/libmdb/file.c | 4 ++-- src/libmdb/rc4.c | 4 ++-- src/libmdb/write.c | 2 +- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/include/mdbprivate.h b/include/mdbprivate.h index 02204cb..5e6c84c 100644 --- a/include/mdbprivate.h +++ b/include/mdbprivate.h @@ -16,8 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _mdbprivate_h_ -#define _mdbprivate_h_ +#ifndef MDBPRIVATE_H +#define MDBPRIVATE_H #include "mdbtools.h" @@ -30,6 +30,14 @@ #define g_memdup2 g_memdup #endif -void mdb_rc4(unsigned char *key, guint32 key_len, unsigned char *buf, guint32 buf_len); +#ifdef __cplusplus + extern "C" { +#endif + +void mdbi_rc4(unsigned char *key, guint32 key_len, unsigned char *buf, guint32 buf_len); + +#ifdef __cplusplus + } +#endif #endif diff --git a/include/mdbtools.h b/include/mdbtools.h index e524239..cbe1fd0 100644 --- a/include/mdbtools.h +++ b/include/mdbtools.h @@ -648,9 +648,6 @@ void mdb_iconv_init(MdbHandle *mdb); void mdb_iconv_close(MdbHandle *mdb); const char* mdb_target_charset(MdbHandle *mdb); -/* rc4.c */ -void mdb_rc4(unsigned char *key, guint32 key_len, unsigned char *buf, guint32 buf_len); - /** @}*/ #ifdef __cplusplus diff --git a/src/libmdb/file.c b/src/libmdb/file.c index f7cd2d0..b4cb5cc 100644 --- a/src/libmdb/file.c +++ b/src/libmdb/file.c @@ -172,7 +172,7 @@ static MdbHandle *mdb_handle_from_stream(FILE *stream, MdbFileFlags flags) { } guint32 tmp_key = 0x6b39dac7; - mdb_rc4( + mdbi_rc4( (unsigned char *)&tmp_key, 4, mdb->pg_buf + 0x18, @@ -377,7 +377,7 @@ static ssize_t _mdb_read_pg(MdbHandle *mdb, void *pg_buf, unsigned long pg) if (pg != 0 && mdb->f->db_key != 0) { unsigned int tmp_key = mdb->f->db_key ^ pg; - mdb_rc4((unsigned char*)&tmp_key, 4, pg_buf, mdb->fmt->pg_size); + mdbi_rc4((unsigned char*)&tmp_key, 4, pg_buf, mdb->fmt->pg_size); } return mdb->fmt->pg_size; diff --git a/src/libmdb/rc4.c b/src/libmdb/rc4.c index 2956d17..5596736 100644 --- a/src/libmdb/rc4.c +++ b/src/libmdb/rc4.c @@ -18,7 +18,7 @@ #include "mdbprivate.h" -typedef struct _RC4_KEY +typedef struct { unsigned char state[256]; unsigned char x; @@ -78,7 +78,7 @@ static void RC4(RC4_KEY *key, int buffer_len, unsigned char * buff) key->y = y; } -void mdb_rc4(unsigned char *key, guint32 key_len, unsigned char *buf, guint32 buf_len) { +void mdbi_rc4(unsigned char *key, guint32 key_len, unsigned char *buf, guint32 buf_len) { RC4_KEY rc4_key; RC4_set_key(&rc4_key, key_len, key); RC4(&rc4_key, buf_len, buf); diff --git a/src/libmdb/write.c b/src/libmdb/write.c index 1d791ab..6ae073a 100644 --- a/src/libmdb/write.c +++ b/src/libmdb/write.c @@ -84,7 +84,7 @@ mdb_write_pg(MdbHandle *mdb, unsigned long pg) { buf = g_memdup2(mdb->pg_buf, mdb->fmt->pg_size); unsigned int tmp_key = mdb->f->db_key ^ pg; - mdb_rc4((unsigned char*)&tmp_key, 4, buf, mdb->fmt->pg_size); + mdbi_rc4((unsigned char*)&tmp_key, 4, buf, mdb->fmt->pg_size); } len = fwrite(buf, 1, mdb->fmt->pg_size, mdb->f->stream);