~jkaivo/deonebook

fba801355bd8c4d7d57dadfa29362809a5a87b7f — Jakob Kaivo 1 year, 8 months ago 78d6a05 deonebook
implement decryption

adjust command-line to require no file names or exactly two, input and output
remove -G and -R options
specify device with -d option
specify key (in hex) if necessary with -k option
better warnings and errors throughout
9 files changed, 178 insertions(+), 76 deletions(-)

A .gitmodules
M Makefile
M README.md
A decrypt.c
M deonebook.c
M deonebook.h
M extract.sh
A getkey.c
A tiny-AES-c
A .gitmodules => .gitmodules +3 -0
@@ 0,0 1,3 @@
[submodule "tiny-AES-c"]
	path = tiny-AES-c
	url = https://github.com/kokke/tiny-AES-c

M Makefile => Makefile +12 -1
@@ 6,7 6,7 @@

CC=c99
LD=$(CC)
CFLAGS=-Wall -Wextra -Wpedantic -Werror -g
CFLAGS=-Wall -Wextra -Wpedantic -Werror -g3
LDFLAGS=
LDLIBS=
SRCDIR=.


@@ 32,5 32,16 @@ $(OBJDIR)/genkey.o: $(SRCDIR)/deonebook.h
$(OBJDIR)/genkey.o: $(SRCDIR)/genkey.c
	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)/genkey.c

$(BINDIR)/deonebook: $(OBJDIR)/decrypt.o
$(OBJDIR)/decrypt.o: $(SRCDIR)/deonebook.h
$(OBJDIR)/decrypt.o: $(SRCDIR)/decrypt.c
$(OBJDIR)/decrypt.o: $(SRCDIR)/tiny-AES-c/aes.c
	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)/decrypt.c

$(BINDIR)/deonebook: $(OBJDIR)/getkey.o
$(OBJDIR)/getkey.o: $(SRCDIR)/deonebook.h
$(OBJDIR)/getkey.o: $(SRCDIR)/getkey.c
	$(CC) $(CFLAGS) -o $@ -c $(SRCDIR)/getkey.c

$(BINDIR)/deonebook:
	$(LD) $(LDFLAGS) -o $@ $(OBJDIR)/*.o $(LDLIBS)

M README.md => README.md +35 -30
@@ 1,9 1,11 @@
DeOneBook
---------

This program extracts encryption keys from eOneBook SD cards. Eventually I will
add decryption as well, but for now it is enough to extract a key that can be
used passed to `openssl` to do the actual decryption.
This program is designed to decrypt the contents of eOneBook SD cards. It is
able to extract the encryption keys from SD cards to make this automatic with
the proper hardware. Without hardware support, decryption is a two-step
process, extracting a key using the eOneBook itself, and decryption using that
key.

Building
--------


@@ 25,22 27,29 @@ Then build with the cross compiler:

    make CC=arm-linux-gnueabihf-gcc

Use
---
Automatic Decryption
--------------------

If you are using the native version, simply place an eOneBook SD card in your
SD card reader, and run:
If your system has a directly connected SD card reader, you can decrypt files
with:

    ./deonebook -G [devicename]
    deonebook [-d devicename] <input-file> <output-file>

Here, `devicename` is optional, and will default to `mmcblk0`. If your SD card
has a different device name, specify it there. The encryption key will be
presented in hexadecimal.
The default device is `mmcblk0`. If your SD card reader is something else
(n.b. it *must* be an `mmcblk` device), specify that via the `-d` option.
Replace <input-file> with the path to an encrypted file (e.g.
`/media/sd/001/100E`) and <output-file> with the path to place the newly
decrypted file. DeOneBook will determine the encryption key by reading
information directly from the SD card.

For the eOneBook version, it's a little more complex. You'll need to prep the
SD card to execute the program and save its output. First, make sure the SD
card is not write-protected by moving the write-protect slider to the end of
its slot nearest the pins of the card. Mount the SD card somewhere you can
On-device Key Extraction
------------------------

If your system does not have a directly connected SD card reader, you can
use your eOneBook device to extract the encryption key. You'll need to prep
the SD card to execute the program and save its output. First, make sure the
SD card is not write-protected by moving the write-protect slider to the end
of its slot nearest the pins of the card. Mount the SD card somewhere you can
write to it, `cd` to that mount point, and run the following commands,
replacing `$DEONEBOOKDIR` with the path to the compiled DeOneBook.



@@ 52,25 61,21 @@ before attempting this.***
    mv .A001 eonebook                   # rename the official firmware
    cp $DEONEBOOKDIR/deonebook .        # copy over the key extractor
    cp $DEONEBOOKDIR/extract.sh .A001   # copy over the extraction script
    chmod +x deonebook .A001            # ensure deonebook files are executable

Put the SD card in your eOneBook and open it up. When the official interface
comes up, the key extraction is complete. Close the eOneBook and there will be
a file called `eonebook.hex` containing the encryption key for that card.

Decrypting
----------
a file called `eonebook.key` containing the encryption key for that card.

Eventually this will be integrated into DeOneBook itself. For now, you can use
the extracted key along with `openssl` to decrypt files. Replace `$KEY` with
the hex key, either as printed with the native version or the contents of
`eonebook.hex` from the cross-compiled version. Replace `$INFILE` with the name
of an encrypted image (e.g. `002E`), and `$OUTFILE` with a path where you want
the decrypted image to go:
Manual Decryption
-----------------

    openssl aes-128-cbc -d -iv 03030303030303030303030303030303 -K $KEY -in $INFILE -out $OUTFILE
Once you have extraced the key using your eOneBook, you can use that key to
manually decrypt that SD card's files. Run:

You can do a whole directory with something like:
    deonebook -k $KEY <input-file> <output-file>

    for i in *E; do
        openssl aes-128-cbc -d -iv 03030303030303030303030303030303 -K $KEY -in $i -out $i.gray
    done
Replace `$KEY` with the contents of `eonebook.key` from the previous step (you
could also simply replace it with `$(cat eonebook.key)`). Replace <input-file>
with the path to an encrypted file, and <output-file> with the path for the
newly decrypted file.

A decrypt.c => decrypt.c +57 -0
@@ 0,0 1,57 @@
#define _XOPEN_SOURCE 700
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>

#include "deonebook.h"

#define CBC 1
#define ECB 0
#define CTR 0
#include "tiny-AES-c/aes.c"

int decrypt(const unsigned char *key, const char *in, const char *out)
{
	int fd = open(in, O_RDONLY);
	if (fd == -1) {
		perror(in);
		return 1;
	}

	struct stat st;
	if (fstat(fd, &st) != 0) {
		perror(in);
		return 1;
	}

	unsigned char *buf = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
	if (buf == MAP_FAILED) {
		perror(in);
		return 1;
	}

	close(fd);

	unsigned char iv[IV_SIZE];
	memset(iv, '\03', sizeof(iv));

	struct AES_ctx ctx = {0};
	AES_init_ctx_iv(&ctx, key, iv);
	AES_CBC_decrypt_buffer(&ctx, buf, st.st_size);

	fd = open(out, O_WRONLY | O_CREAT, 0644);
	if (fd == -1) {
		perror(out);
		return 1;
	}

	write(fd, buf, st.st_size);
	close(fd);

	return 0;
}

M deonebook.c => deonebook.c +20 -44
@@ 7,21 7,18 @@

int main(int argc, char *argv[])
{
	enum { DECRYPT, GENERATE, READ } mode = DECRYPT;
	char *keystring = NULL;
	char *device = NULL;

	int c;
	while ((c = getopt(argc, argv, "RGk:")) != -1) {
	while ((c = getopt(argc, argv, "k:d:")) != -1) {
		switch (c) {
		case 'R':
			mode = READ;
		case 'k':
			keystring = optarg;
			break;

		case 'G':
			mode = GENERATE;
			break;

		case 'k':
			/* keyfile = optarg; */
		case 'd':
			device = optarg;
			break;

		default:


@@ 29,50 26,29 @@ int main(int argc, char *argv[])
		}
	}

	if (mode != DECRYPT) {
		unsigned char *key = NULL;
		if (mode == READ) {
			key = readkey("./.shm");
		} else {
			char *device = "mmcblk0";
			if (optind < argc) {
				device = argv[optind];
			}

			if (strstr(device, "mmcblk") != device) {
				fprintf(stderr, "device must be an mmcblk device\n");
				return 1;
			}
	unsigned char *key = getkey(keystring, device);

			char path[256];
			snprintf(path, sizeof(path), "/sys/block/%s/device", device);
			DIR *d = opendir(path);
			if (d == NULL) {
				fprintf(stderr, "device '%s' not found\n", device);
				return 1;
			}

			key = genkey(dirfd(d));
		}

		if (key == NULL) {
			return 1;
		}
	if (key == NULL) {
		return 1;
	}

	if (optind >= argc) {
		for (int i = 0; i < KEY_SIZE; i++) {
			printf("%02hhx", key[i]);
		}
		printf("\n");

		return 0;
	}

	if (optind >= argc) {
		fprintf(stderr, "%s: missing operands\n", argv[0]);
	if (optind < argc - 2) {
		fprintf(stderr, "too many operands\n");
		return 1;
	}

	if (optind != argc - 2) {
		fprintf(stderr, "missing output file\n");
		return 1;
	}

	do {
		printf("decrypting %s\n", argv[optind]);
	} while (++optind < argc);
	return decrypt(key, argv[optind], argv[optind + 1]);
}

M deonebook.h => deonebook.h +3 -0
@@ 2,8 2,11 @@
#define DEONEBOOK_H

#define KEY_SIZE 16
#define IV_SIZE 16

unsigned char *genkey(int dirfd);
unsigned char *readkey(const char *path);
unsigned char *getkey(const char *keystring, const char *device);
int decrypt(const unsigned char *key, const char *in, const char *out);

#endif

M extract.sh => extract.sh +1 -1
@@ 1,6 1,6 @@
#!/bin/sh
D=/run/media/mmcblk0p1

$D/deonebook -R > $D/eonebook.hex
$D/deonebook > $D/eonebook.key

exec $D/eonebook || shutdown -h now

A getkey.c => getkey.c +46 -0
@@ 0,0 1,46 @@
#define _XOPEN_SOURCE 700
#include <dirent.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "deonebook.h"

unsigned char *getkey(const char *keystring, const char *device)
{
	if (keystring) {
		static unsigned char key[KEY_SIZE] = "";
		if (strlen(keystring) != (KEY_SIZE * 2)) {
			fprintf(stderr, "key must be %d hex characters\n", KEY_SIZE * 2);
			return NULL;
		}

		for (size_t i = 0; i < sizeof(key); i++) {
			char hex[] = { keystring[i * 2], keystring[i * 2 + 1], '\0' };
			key[i] = (unsigned char)strtoul(hex, NULL, 16);
		}
		return key;
	}

	if (!device) {
		device = "mmcblk0";
	} else if (strstr(device, "mmcblk") != device) {
		fprintf(stderr, "device must be an mmcblk device\n");
		return NULL;
	}

	char path[256];
	snprintf(path, sizeof(path), "/sys/block/%s/device", device);
	DIR *d = opendir(path);
	if (d == NULL) {
		fprintf(stderr, "device '%s' not found\n", device);
		return NULL;
	}

	unsigned char *key = genkey(dirfd(d));
	if (key) {
		return key;
	}

	return readkey("./.shm");
}

A tiny-AES-c => tiny-AES-c +1 -0
@@ 0,0 1,1 @@
Subproject commit 3f69a5899e58e2e398e8c32ce7b3a954dd593ed4