/*
* You might have heard of Meganet's Virtual Matrix Encryption. They've
* had a series of crack this code contests, but won't tell us how their
* code works. The program below was reverse-engineered from the shareware
* software which is available on their web site, and can decrypt VME files.
* This is not a cracking program (you need to supply the required secret
* information in order to decrypt) but maybe someone can use it to build
* one.
*
* If you try to decrypt Meganet's old encrypted challenge files with this
* code, you'll get garbage. However, it's exactly the same garbage that
* you'll get if you decrypt the files with their shareware software. This
* is not due to the much-hyped Date Limiting Algorithm (see below for
* details). Apparantly either a) the shareware version is broken, or
* b) Meganet decided to make certain nobody would win the challenge by
* encrypting random numbers instead of a meaningful file. This code can
* correctly decrypt files that were encrypted with the shareware version.
*/
#include stdio.h
#include string.h
#include ctype.h
int vme_decrypt(FILE *data_file, char *passwords[], FILE *config_file,
FILE *secret_file, FILE *out_file);
/* Test driver. Sorry there isn't a proper user interface here. */
int main()
{
FILE *data_file, *config_file, *secret_file, *out_file;
char *passwords[] = {
[EMAIL PROTECTED], /* sender */
[EMAIL PROTECTED], /* recipient */
VME Challenge 2001, /* description */
, /* password */
};
data_file = fopen(vme2001.vme, rb);
config_file = fopen(vme2001.cfg, rb);
secret_file = fopen(vme2001.txt, rb);
out_file = fopen(decrypt.out, wb);
if ( vme_decrypt(data_file, passwords, config_file, secret_file, out_file) )
printf(Decryption failed\n);
return 0;
}
/* There are a number of incompatible changes between
the 2000 and 2002 versions. */
/* #define VME_2002 1 */
#define VME_NUM_PASS 4
#define VME_PASS_SIZE 0x40
#define VME_KEY_SIZE 0x10
#define VME_BUF_SIZE 0x100
#define VME_MBK_SIZE 0x8000
#define VME_MAXINT 0xu
#define SWAP(x,y) { int temp = (x); (x) = (y); (y) = temp; }
#define LROT(x,y) ( ((x)(y) | (x)(8-(y))) 0xff )
#define RROT(x,y) ( ((x)(y) | (x)(8-(y))) 0xff )
#define VME_RAND(r) ( (r)=((r)*0x19660du+0x3c6ef35fu)VME_MAXINT )
#define VME_RAND8(r) ( (r)=((r)*0x0d+0x5f)0xff )
struct vme_state {
int num_funcs, have_secret, key_xor, randb1, randb10;
unsigned main_key;
unsigned char func_order[VME_KEY_SIZE], key_order[VME_KEY_SIZE];
unsigned char key3[VME_KEY_SIZE];
unsigned char stk[VME_BUF_SIZE], key1[VME_BUF_SIZE], key2[VME_BUF_SIZE];
unsigned char perm1[VME_BUF_SIZE], perm2[VME_BUF_SIZE];
unsigned char invperm2[VME_BUF_SIZE], mul[VME_BUF_SIZE];
unsigned char rmbk1[VME_BUF_SIZE], rmbk2[VME_BUF_SIZE];
unsigned char rmbk3[VME_BUF_SIZE], rmbk4[VME_BUF_SIZE];
unsigned char mbk1[VME_MBK_SIZE], mbk2[VME_MBK_SIZE];
unsigned char mbk3[VME_MBK_SIZE], mbk4[VME_MBK_SIZE];
};
static int vme_load_config(FILE *config_file, struct vme_state *vme);
static int vme_load_stk(FILE *data_file, struct vme_state *vme);
static int vme_main_init(FILE *data_file, char *passwords[],
FILE *secret_file, struct vme_state *vme);
static void vme_key_init(struct vme_state *vme);
static void vme_mbk_init(FILE *secret_file, struct vme_state *vme);
static void vme_decrypt_loop(FILE *data_file, FILE *out_file,
struct vme_state *vme);
static int vme_table1(int c, int n, int k, struct vme_state *vme);
static int vme_table2(int c, int n, unsigned rand);
int vme_decrypt(FILE *data_file, char *passwords[], FILE *config_file,
FILE *secret_file, FILE *out_file)
{
struct vme_state vme;
if ( vme_load_config(config_file, vme) ) return 1;
if ( vme_load_stk(data_file, vme) ) return 1;
if ( vme_main_init(data_file, passwords, secret_file, vme) ) return 1;
vme_key_init(vme);
vme_mbk_init(secret_file, vme);
vme_decrypt_loop(data_file, out_file, vme);
return 0;
} /* vme_decrypt */
/*
* The configuration file gives the initial order of the functions applied
* to the data as it is encrypted.
*/
static int vme_load_config(FILE *config_file, struct vme_state *vme)
{
int i, c, f, n, rand_state;
if (config_file == NULL) return 1;
fseek(config_file, 0, SEEK_SET);
rand_state = 0xff;
n = 0;
for (i = 0; i VME_KEY_SIZE; i++) {
c = getc(config_file);
if (c == EOF) return 1;
c ^= VME_RAND8(rand_state);
f = c 4;
vme-func_order[i] = f;
vme-key_order[i] = (f == 0xe) ? 0xe : c 0xf;
if (f != 0xf) n = i;
}
vme-num_funcs = n + 1;
return 0;
} /* vme_load_config */
/*
* The enrypted file is prefixed with a 256-byte header which contains
* the Specific Transaction Key (STK) and some encoded information.
* Instead of using the manufacturer-recommended procedure to decode
* the information using the passwords, this code just does an
* exhaustive key search. You're going to bust a gut laughing when you
* see this.
*/