diff --git a/README.md b/README.md index 0082019..2d1fecb 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,66 @@ pegh ---- +pegh is a file encryption tool using passwords and authenticated encryption. It is simple, secure, and returns proper exit codes so you can tell whether encryption or decryption failed or not. + [pegh](http://klingonska.org/dict/?q=tlh%3Apegh) is Klingon for secret -pegh is a file encryption tool using passwords and authenticated encryption. It returns proper exit codes so you can tell whether encryption/decryption failed or not. +Usage +----- -pegh implements a simple versioned file format so encryption parameters can change in the future, but currently version 0 derives a 256-bit key from your password with scrypt, and uses that to encrypt/decrypt your file with aes-256-gcm. +```sh +# encrypt file.txt to file.txt.pegh with password SUPER_SECRET_1942 +pegh -e SUPER_SECRET_1942 file.txt.pegh -todo: document usage and file format \ No newline at end of file +# decrypt file.txt.pegh to file.txt with password SUPER_SECRET_1942 +pegh -d SUPER_SECRET_1942 file.txt +``` + +The easiest way to scale cost/time it takes for bruteforcing is simply to continue doubling -s, on both encryption and decryption commands. + +full help: +``` +$ pegh -h +usage: pegh [-demNrpshV] password + -e encrypt stdin to stdout, default mode + -d decrypt stdin to stdout + -m maximum megabytes of ram to use when deriving key from password + with scrypt, applies for encryption AND decryption, must + almost linearly scale with -N, if too low operation will fail, + default: 64 + -N scrypt parameter N, only applies for encryption, default 32768 + this is rounded up to the next highest power of 2 + -r scrypt parameter r, only applies for encryption, default 8 + -p scrypt parameter p, only applies for encryption, default 1 + -s multiplication factor to apply to both -N and -m for easy + work scaling, rounded up to the next highest power of 2, + default: 1 + -h print this usage text + -V show version number and format version support then quit + +For additional info on scrypt params refer to: + https://blog.filippo.io/the-scrypt-parameters/ + https://tools.ietf.org/html/rfc7914#section-2 +``` + +pegh file format +---------------- + +pegh implements a simple versioned file format so encryption parameters can change in the future. Numbers here are inclusive 0-based byte array indices, 0th byte is always version number, everything else depends on version number, currently only version 0 exists. + +Version 0, scrypt key derivation, aes-256-gcm encryption, 51 byte header, 16 byte footer: + +| indices | format | value interpretation | +|--------------|---------------------------------------------|--------------------------------| +| 0 | 8 bit unsigned byte | pegh file format version | +| 1-4 | 32 bit unsigned integer in big endian order | scrypt N parameter | +| 5 | 8 bit unsigned byte | scrypt r parameter | +| 6 | 8 bit unsigned byte | scrypt p parameter | +| 7-38 | 32 randomly generated bytes | scrypt key derivation seed | +| 39-50 | 12 randomly generated bytes | AES-256-GCM IV | +| 51-X | any number of bytes | AES-256-GCM encrypted data | +| (X+1)-(X+16) | 16 bytes, always last 16 bytes in file | AES-256-GCM authentication tag | + +License +------- +AGPLv3 for now, message me if you have a problem with this diff --git a/pegh.c b/pegh.c index a42226d..e70c3f3 100644 --- a/pegh.c +++ b/pegh.c @@ -29,7 +29,7 @@ #include /* - * tweak scrypt hardness params here + * tweak default scrypt hardness params here * * https://tools.ietf.org/html/rfc7914#section-2 * https://blog.filippo.io/the-scrypt-parameters/ @@ -43,6 +43,27 @@ #define BYTES_PER_READ (1024 * 32) /* 32kb */ #define INITIAL_BUFFER_SIZE (1024 * 256) /* 256kb, must be at least 2*BYTES_PER_READ */ +/* + * pegh file format, numbers are inclusive 0-based byte array indices + * + * 0th byte is always version number, everything else depends on version number + * + * |---------------------------------------------------------------------------------------------| + * | Version 0, scrypt key derivation, aes-256-gcm encryption, 51 byte header, 16 byte footer | + * |--------------|---------------------------------------------|--------------------------------| + * | indices | format | value interpretation | + * |--------------|---------------------------------------------|--------------------------------| + * | 0 | 8 bit unsigned byte | pegh file format version | + * | 1-4 | 32 bit unsigned integer in big endian order | scrypt N parameter | + * | 5 | 8 bit unsigned byte | scrypt r parameter | + * | 6 | 8 bit unsigned byte | scrypt p parameter | + * | 7-38 | 32 randomly generated bytes | scrypt key derivation seed | + * | 39-50 | 12 randomly generated bytes | AES-256-GCM IV | + * | 51-X | any number of bytes | AES-256-GCM encrypted data | + * | (X+1)-(X+16) | 16 bytes, always last 16 bytes in file | AES-256-GCM authentication tag | + * |---------------------------------------------------------------------------------------------| + */ + /* don't touch below here unless you know what you are doing */ #define PEGH_VERSION "1.0.0" @@ -323,9 +344,9 @@ int pegh(char *password, int decrypt, int help(int exit_code) { /* this ridiculous split is because C89 only supports strings of 509 characters */ fprintf(stderr, "\ -usage: pegh [-demNrphV] password\n\ - -d decrypt stdin to stdout, default mode\n\ - -e encrypt stdin to stdout\n\ +usage: pegh [-demNrpshV] password\n\ + -e encrypt stdin to stdout, default mode\n\ + -d decrypt stdin to stdout\n\ -m maximum megabytes of ram to use when deriving key from password\n\ with scrypt, applies for encryption AND decryption, must\n\ almost linearly scale with -N, if too low operation will fail,\n\ @@ -336,9 +357,10 @@ usage: pegh [-demNrphV] password\n\ -r scrypt parameter r, only applies for encryption, default %d\n\ -p scrypt parameter p, only applies for encryption, default %d\n\ -s multiplication factor to apply to both -N and -m for easy\n\ - work scaling, rounded up to the next highest power of 2,\n\ - default: 1\n", SCRYPT_N, SCRYPT_R, SCRYPT_P); + work scaling, rounded up to the next highest power of 2,\n", SCRYPT_N, SCRYPT_R, SCRYPT_P); fprintf(stderr, "\ + BEWARE: -s 32 requires 2G ram, -s 64 requires 4G and so on,\n\ + default: 1\n\ -h print this usage text\n\ -V show version number and format version support then quit\n\ \nFor additional info on scrypt params refer to:\n\ @@ -388,7 +410,7 @@ uint32_t next_highest_power_of_2(uint32_t v) { /* returns 0 on success, 1 on openssl failure, 2 on other failure */ int main(int argc, char **argv) { - int optind, decrypt = 1; + int optind, decrypt = 0; char *password = NULL; uint32_t N = SCRYPT_N, scrypt_max_mem_mb = SCRYPT_MAX_MEM_MB, scale = 1; uint8_t r = SCRYPT_R, p = SCRYPT_P; diff --git a/test.sh b/test.sh index f479929..25b95c7 100755 --- a/test.sh +++ b/test.sh @@ -13,8 +13,8 @@ echo "key: $key" test () { bin=$1 - tee >(md5sum 1>&2) < /dev/shm/randombytes | $bin -e $key | $bin $key | md5sum 1>&2 - #$bin -e $key < /dev/shm/randombytes | $bin $key &>/dev/null + tee >(md5sum 1>&2) < /dev/shm/randombytes | $bin -e $key | $bin -d $key | md5sum 1>&2 + #$bin -e $key < /dev/shm/randombytes | $bin -d $key &>/dev/null } time test ./pegh