Merge pull request #305 from filmor/write-encrypted-pages

Write encrypted pages
This commit is contained in:
Evan Miller
2021-05-19 10:08:54 -04:00
committed by GitHub
5 changed files with 126 additions and 77 deletions

View File

@@ -16,16 +16,28 @@
* 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"
/*
* 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
#ifdef __cplusplus
extern "C" {
#endif
void mdbi_rc4(unsigned char *key, guint32 key_len, unsigned char *buf, guint32 buf_len);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -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

View File

@@ -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 <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
@@ -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;
mdbi_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);
@@ -249,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);
@@ -436,10 +376,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);
mdbi_rc4((unsigned char*)&tmp_key, 4, pg_buf, mdb->fmt->pg_size);
}
return mdb->fmt->pg_size;

85
src/libmdb/rc4.c Normal file
View File

@@ -0,0 +1,85 @@
/* 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
{
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 <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;
}
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);
}

View File

@@ -18,7 +18,7 @@
#include <time.h>
#include <inttypes.h>
#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);
@@ -70,6 +70,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 +79,20 @@ 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_memdup2(mdb->pg_buf, mdb->fmt->pg_size);
unsigned int tmp_key = mdb->f->db_key ^ pg;
mdbi_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;