Index: examples/peterglen =================================================================== --- examples/peterglen +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dfa86ac48e894848e1f4891fbf33b62d70f0e88d Index: examples/peterglen/Makefile =================================================================== --- /dev/null +++ examples/peterglen/Makefile @@ -0,0 +1,92 @@ +# These point to already built sub parts. Edit it if you move +# the files to a different directory. +# This is so one can use the parts without installation. + +INC2=../../../libgpg-error-1.27/src +INC3=../../src +LIB2=../../src/.libs/ +LIB3=../../../libgpg-error-1.27/src/.libs +LIB4= -l gcrypt -l gpg-error +CC=gcc +OPT2=-I $(INC2) -I $(INC3) -L $(LIB2) -L $(LIB3) $(LIB4) + +# This is to create templates for test expectations. We substitue memory +# locations with zeros, so diff is happy + +FILTER=sed s/0x[0-9A-F]*/0x00000000/g +ENCTEST=asencrypt.exe -i sample.txt -o sample.enc testkey.pub +ENCTEST2=asdecrypt.exe -i sample.enc -o sample.dec -p 1111 testkey.key + +.c.o: + $(CC) $(OPT2) -c $< + +OBJS = base64.o gcry.o getpass.o zmalloc.o gsexp.o + +all: encrypt.exe keygen.exe encdec.exe asencrypt.exe asdecrypt.exe dump.exe + +tests: build_tests + @echo Tests pass if diffs are silent. + @test_base64a.exe > test.tmp + @diff test_base64a.org test.tmp + @test_base64.exe > test.tmp + @diff test_base64.org test.tmp + @test_zmalloc.exe | $(FILTER) > test.tmp + @diff test_zmalloc.org test.tmp + @$(ENCTEST); $(ENCTEST2) + @diff sample.txt sample.dec + @-rm test.tmp + +build_tests: test_base64.exe test_base64a.exe test_zmalloc.exe asencrypt.exe asdecrypt.exe + +prep_tests: + @test_base64.exe > test_base64.org + @test_base64a.exe > test_base64a.org + @test_zmalloc.exe | $(FILTER) > test_zmalloc.org + $(ENCTEST) > enctest.org + +encrypt.exe: encrypt.c zmalloc.c + $(CC) encrypt.c $(OPT2) zmalloc.c -o encrypt + +keygen.exe: $(OBJS) keygen.c + $(CC) keygen.c $(OBJS) $(OPT2) -o keygen + +encdec.exe: $(OBJS) encdec.c + $(CC) encdec.c $(OBJS) $(OPT2) -o encdec + +asencrypt.exe: $(OBJS) asencrypt.c + $(CC) asencrypt.c $(OBJS) $(OPT2) -o asencrypt + +asdecrypt.exe: $(OBJS) asdecrypt.c + $(CC) asdecrypt.c $(OBJS) $(OPT2) -o asdecrypt + +test_base64.exe: test_base64.c base64.c zmalloc.c + gcc test_base64.c base64.c zmalloc.c -o test_base64 + +test_base64a.exe: test_base64a.c base64.c zmalloc.c + gcc test_base64a.c base64.c zmalloc.c -o test_base64a + +test_zmalloc.exe: test_zmalloc.c zmalloc.c + gcc test_zmalloc.c zmalloc.c -o test_zmalloc + +dump.exe: $(OBJS) dump.c + $(CC) dump.c $(OBJS) $(OPT2) -o dump.exe + +clean: + @-rm aa.* >aa 2>&1 + @-rm bb.* >aa 2>&1 + @-rm cc.* >aa 2>&1 + @-rm *.exe >aa 2>&1 + @-rm *.o >aa 2>&1 + @-rm aa + + + + + + + + + + + + Index: examples/peterglen/README =================================================================== --- /dev/null +++ examples/peterglen/README @@ -0,0 +1,78 @@ +README + + These are encryption / decryption samples for the gcrypt library. + + They can be used as a standalone project for + + key generation / encryption / decryption. + +FILES + + keygen -- Key generator. + asencrypt -- Asymmetric encryption with public key. + asdecrypt -- Asymmetric decryption with private key. + + + Encryption: + + asencrypt.exe -i infile.txt -o outfile.enc testkey.pub + + Decryption: + + asdecrypt.exe -i infile.enc -o outfile.dec -p password_for_key testkey.key + + See Makefile for typical usage. The programs will print basic usage +information on request. + +BUILD + + All the files are built on Windows using MSYS and MinGW. The files should +build on linux and variants with little modification. + +PREP + + Build the glibcrypt library first. This project will look for the built +libs and includes in the .lib subdir under the original build directories. +This allows installation-less build. (for test and experimentation) + +NOTABLES + + I made a small malloc subsystem. It can be used to detect leaks very easily. +Use zalloc() like you would use malloc(). If you make an alloc mistake, this +malloc gently prints a string like: + + zmalloc: Memory leak on gcry.c at line 711 (0x010A1178) + + Also created a base64 encode / decode subsystem. See headers and source +for more info. + +FILE FORMAT + + The output format of the encrypted file is base64 line aligned to 64 char +length. The header and trailer line contains the RSA string delimiter. +"-----BEGIN GCRYPT RSA CYPHER-----" etc ... +Under the hood the file is in chunks, determined by the key size. +The chunk starts with a two byte length and data follows. The next +chunk start is calculated from the length of the current chunk. Like this: + + LEN LEN DATA ..... DATA LEN LEN DATA .... + |------------------------| + + This is the simplest (I think) way to adapt tho the variable length output +of the asymmetric encryption. + + +TESTING + + 'make tests' will build the needed files and execute a diff on generated +outputs. It is comparing them with expected output of the original files. +Test passes if the diffs are silent. + +FEEDBACK + +This code was developed for a larger project. However, taming the library is +a common task, so I shared it ... + +peterglen99@gmail.com + + Index: examples/peterglen/README.md =================================================================== --- /dev/null +++ examples/peterglen/README.md @@ -0,0 +1,78 @@ +README + + These are encryption / decryption samples for the gcrypt library. + + They can be used as a standalone project for + + key generation / encryption / decryption. + +FILES + + keygen -- Key generator. + asencrypt -- Asymmetric encryption with public key. + asdecrypt -- Asymmetric decryption with private key. + + + Encryption: + + asencrypt.exe -i infile.txt -o outfile.enc testkey.pub + + Decryption: + + asdecrypt.exe -i infile.enc -o outfile.dec -p password_for_key testkey.key + + See Makefile for typical usage. The programs will print basic usage +information on request. + +BUILD + + All the files are built on Windows using MSYS and MinGW. The files should +build on linux and variants with little modification. + +PREP + + Build the glibcrypt library first. This project will look for the built +libs and includes in the .lib subdir under the original build directories. +This allows installation-less build. (for test and experimentation) + +NOTABLES + + I made a small malloc subsystem. It can be used to detect leaks very easily. +Use zalloc() like you would use malloc(). If you make an alloc mistake, this +malloc gently prints a string like: + + zmalloc: Memory leak on gcry.c at line 711 (0x010A1178) + + Also created a base64 encode / decode subsystem. See headers and source +for more info. + +FILE FORMAT + + The output format of the encrypted file is base64 line aligned to 64 char +length. The header and trailer line contains the RSA string delimiter. +"-----BEGIN GCRYPT RSA CYPHER-----" etc ... +Under the hood the file is in chunks, determined by the key size. +The chunk starts with a two byte length and data follows. The next +chunk start is calculated from the length of the current chunk. Like this: + + LEN LEN DATA ..... DATA LEN LEN DATA .... + |------------------------| + + This is the simplest (I think) way to adapt tho the variable length output +of the asymmetric encryption. + + +TESTING + + 'make tests' will build the needed files and execute a diff on generated +outputs. It is comparing them with expected output of the original files. +Test passes if the diffs are silent. + +FEEDBACK + +This code was developed for a larger project. However, taming the library is +a common task, so I shared it ... + +peterglen99@gmail.com + + Index: examples/peterglen/asdecrypt.c =================================================================== --- /dev/null +++ examples/peterglen/asdecrypt.c @@ -0,0 +1,373 @@ + +/* =====[ asdecrypt.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include +#include +#include + +#include "gcrypt.h" +#include "gcry.h" +#include "zmalloc.h" +#include "getpass.h" +#include "gsexp.h" + +static int dump = 0; +static int verbose = 0; +static int test = 0; +static int ppub = 0; +static int nocrypt = 0; +static int use_stdin = 0; + +static char infile[MAX_PATH] = {'\0'}; +static char outfile[MAX_PATH] = {'\0'}; +static char keyfile[MAX_PATH] = {'\0'}; +static char thispass[MAX_PATH] = {'\0'}; + +char usestr[] = "asdecrypt [options] keyfile"; + +opts opts_data[] = { + 'i', "infile", NULL, infile, 0, 0, NULL, + "-i --infile - input file name", + + 'o', "outfile", NULL, outfile, 0, 0, NULL, + "-o --outfile - output file name", + + 'p', "pass", NULL, thispass, 0, 0, NULL, + "-p --pass - pass in for key (testing only)", + + 'k', "keyfile", NULL, keyfile, 0, 0, NULL, + "-k --keyfile - key file name", + + 'r', "stdin", NULL, NULL, 0, 0, &use_stdin, + "-r --stdin - use stdin as input", + + 'v', "verbose", NULL, NULL, 0, 0, &verbose, + "-v --verbose - Verbosity on", + + 'd', "dump", NULL, NULL, 0, 0, &dump, + "-d --dump - Dump buffers", + + 't', "test", NULL, NULL, 0, 0, &test, + "-t --test - test on", + + 'n', "nocrypt", NULL, NULL, 0, 0, &nocrypt, + "-n --nocrypt - do not decypt private key", + + 'x', "printpub", NULL, NULL, 0, 0, &ppub, + "-x --printpub - print public key", + + 0, NULL, NULL, NULL, 0, 0, NULL, NULL, + }; + + +static void myfunc(int sig) +{ + printf("\nSignal %d (segment violation)\n", sig); + exit(111); +} + +int main(int argc, char** argv) +{ + signal(SIGSEGV, myfunc); + + char *err_str; + int nn = parse_commad_line(argv, opts_data, &err_str); + if (err_str) + { + printf(err_str); + usage(usestr, opts_data); exit(2); + } + + if (argc - nn != 2 && strlen(keyfile) == 0) { + printf("Missing argument for ascrypt."); + usage(usestr, opts_data); exit(2); + } + + //printf("thispass '%s'\n", thispass); + + //zverbose(TRUE); + //gcry_set_allocation_handler(zalloc, NULL, NULL, zrealloc, zfree); + + gcrypt_init(); + gcry_error_t err; + + char* fname = argv[1 + nn]; + + FILE* lockf = fopen(fname, "rb"); + if (!lockf) { + xerr2("Opening of composite key failed on file '%s'.", fname); + } + + /* Read and decrypt the key pair from disk. */ + unsigned int flen = getfsize(lockf); + zline2(__LINE__, __FILE__); + char* fbuf = zalloc(flen + 1); + if (!fbuf) { + xerr("malloc: could not allocate rsa buffer"); + } + if (fread(fbuf, flen, 1, lockf) != 1) { + xerr2("Reading of composite key failed on file '%s'.", fname); + } + fclose(lockf); + + //fbuf[flen] = '\0'; + zcheck(fbuf, __LINE__); + + zline2(__LINE__, __FILE__); + int rsa_len = flen; + char *rsa_buf = decode_comp_key(fbuf, &rsa_len, &err_str); + zfree(fbuf); + + //if(dump) + // dump_mem(rsa_buf, rsa_len); + + if (!rsa_buf) { + //printf("%s\n", err_str); + xerr2("Decode key failed. %s", err_str); + } + + //if(dump) + // dump_mem(fbuf, flen); + + zline2(__LINE__, __FILE__); + /* Grab a key pair password and create an AES context with it. */ + if(thispass[0] == '\0' && !nocrypt) + { + //getpass2(thispass, MAXPASSLEN, TRUE, TRUE); + getpassx passx; + passx.prompt = "Enter keypair pass:"; + passx.pass = thispass; + passx.maxlen = MAXPASSLEN; + passx.minlen = 3; + passx.weak = TRUE; + passx.nodouble = TRUE; + passx.strength = 4; + int ret = getpass2(&passx); + if(ret < 0) + xerr("Error on password entry."); + } + + //printf("thispass '%s'\n", thispass); + + gcry_cipher_hd_t aes_hd; + get_aes_ctx(&aes_hd, thispass, strlen(thispass)); + + zline2(__LINE__, __FILE__); + if(!nocrypt) + { + // Decrypt buffer + err = gcry_cipher_decrypt(aes_hd, (unsigned char*) rsa_buf, + rsa_len, NULL, 0); + if (err) { + xerr("gcrypt: failed to decrypt key pair"); + } + } + + //if(dump) + // dump_mem(rsa_buf, rsa_len); + + // Extract our key + //gcry_sexp_t glib_keys; + //err = gcry_sexp_new(&glib_keys, rsa_buf, rsa_len, TRUE); + //if(err) + // { + // xerr("Cannot decompose glib keys\n"); + // } + + //gcry_sexp_t rsa_raw = gcry_sexp_find_token(glib_keys, "keydata", 0); + //if(rsa_raw == NULL) + // { + // xerr("No key data here\n"); + // } + + zline2(__LINE__, __FILE__); + /* Load the key pair components into sexps. */ + gcry_sexp_t rsa_keypair; + err = gcry_sexp_new(&rsa_keypair, rsa_buf, rsa_len, 0); + if(err) + { + // Delay a little to fool DOS attacks + struct timespec ts = {0, 300000000}; + nanosleep(&ts, NULL); + xerr2("Failed to load composit key. (pass?)"); + } + + gcry_sexp_t privk = gcry_sexp_find_token(rsa_keypair, "private-key", 0); + if(privk == NULL) + { + xerr2("No private key present in '%s'", fname); + } + //print_sexp(privk); + + zline2(__LINE__, __FILE__); + int keylen = gcry_pk_get_nbits(privk) / 8 ; + //printf("Key length : %d\n", keylen); + + char *data_buf = NULL; + unsigned int data_len; + + if(use_stdin) + { + //printf("Using stdin\n"); + zline2(__LINE__, __FILE__); + char *fbuf2 = zalloc(20000); + int xidx = 0; + while(TRUE) + { + char chh = getc(stdin); + if(feof(stdin)) + { + data_len = xidx; + break; + } + fbuf2[xidx++] = chh; + if(xidx > 10000) + xerr("Out of preallocated stdin buffer\n"); + } + + //printf("Got stdin buffer %d byte\n%s\n", data_len, fbuf2); + + char *err_str; + data_buf = decode_rsa_cyph(fbuf2, &data_len, &err_str); + if(!data_buf) + { + xerr2("Cannot decode input file. %s\n", err_str); + } + zfree(fbuf2); + } + else if(infile[0] != '\0') + { + FILE* lockf2 = fopen(infile, "rb"); + if (!lockf2) { + xerr2("Cannot open input file '%s'.", infile); + } + + /* Read and decrypt the key pair from disk. */ + data_len = getfsize(lockf2); + zline2(__LINE__, __FILE__); + char* fbuf2 = zalloc(data_len + 1); + if (!fbuf2) { + xerr("Could not allocate plain text buffer"); + } + if (fread(fbuf2, data_len, 1, lockf2) != 1) { + xerr("Cannot reead input data."); + } + fclose(lockf2); + //dump_mem(fbuf2, data_len); + + char *err_str; + data_buf = decode_rsa_cyph(fbuf2, &data_len, &err_str); + if(!data_buf) + { + xerr2("Cannot decode input file. %s\n", err_str); + } + zfree(fbuf2); + } + else + { + xerr("Need data to decrypt.\n"); + } + + //dump_mem(data_buf, data_len); + int outlen2 = 0; + zline2(__LINE__, __FILE__); + int limlen = data_len * 2 + keylen; + char *outptr = zalloc(limlen); + if(!outptr) + { + xerr("Cannot allocate output memory."); + } + for(int loop = 0; loop < data_len; /* loop += keylen */) + { + short curr_len = *( (short*) (data_buf + loop) ); + loop += sizeof(short); + //printf("data %p len = %d ", data_buf + loop, curr_len); + + if(loop + curr_len > data_len) + { + xerr2("Reading past last byte."); + } + + /* Create a message. */ + gcry_sexp_t ciph; + int err_offs; + gcry_error_t err2 = gcry_sexp_build(&ciph, NULL, + "(enc-val (rsa (a %b)))", + curr_len, data_buf + loop); + //print_sexp(ciph); + + /* Decrypt the message. */ + gcry_sexp_t plain; + err = gcry_pk_decrypt(&plain, ciph, privk); + if (err) { + xerr("gcrypt: decryption failed"); + } + + /* Pretty-print the results. */ + gcry_mpi_t out_msg = gcry_sexp_nth_mpi(plain, 0, GCRYMPI_FMT_USG); + + int plen = 0; unsigned char *buffm; + err = gcry_mpi_aprint(GCRYMPI_FMT_USG, &buffm, &plen, out_msg); + if (err) + { + xerr("failed to stringify mpi"); + } + //printf("outlen %d\n", plen); + + if(outlen2 + plen > limlen) + { + xerr("Could not write all mem to buffer"); + } + memcpy(outptr + outlen2, buffm, plen); + outlen2 += plen; + loop += curr_len; + } + FILE* outf = stdout; + if(strlen(outfile)) + { + outf = fopen(outfile, "wb"); + if(!outf) + { + xerr("Cannnot open outfile"); + } + } + int retf = fwrite(outptr, outlen2, 1, outf); + if(retf != 1) + { + xerr("Cannot write to file"); + } + if(outf != stdout) + { + fclose(outf); + } + + /* Release contexts. */ + gcry_sexp_release(rsa_keypair); + gcry_sexp_release(privk); + gcry_cipher_close(aes_hd); + + zline2(__LINE__, __FILE__); + zfree(outptr); + zline2(__LINE__, __FILE__); + zfree(data_buf); + zline2(__LINE__, __FILE__); + zfree(rsa_buf); + + zleak(); + return 0; +} + +/* EOF */ + + Index: examples/peterglen/asencrypt.c =================================================================== --- /dev/null +++ examples/peterglen/asencrypt.c @@ -0,0 +1,373 @@ + +/* =====[ ascrypt.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.22.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include +#include + +#include "gcrypt.h" +#include "gcry.h" +#include "zmalloc.h" +#include "getpass.h" +#include "base64.h" +#include "gsexp.h" + +char *decode_pub_key(char *rsa_buf, int *prsa_len, char **err_str); + +static int dump = 0; +static int verbose = 0; +static int test = 0; +static int ppub = 0; + +static char infile[MAX_PATH] = {'\0'}; +static char outfile[MAX_PATH] = {'\0'}; +static char keyfile[MAX_PATH] = {'\0'}; + +/* char opt; + char *long_opt; + int *val; + char *strval; + int minval, maxval; + int *flag; + char *help; */ + +opts opts_data[] = { + 'i', "infile", NULL, infile, 0, 0, NULL, + "-i --infile - input file name", + + 'o', "outfile", NULL, outfile, 0, 0, NULL, + "-o --outfile - output file name", + + 'k', "keyfile", NULL, keyfile, 0, 0, NULL, + "-k --keyfile - key file name", + + 'v', "verbose", NULL, NULL, 0, 0, &verbose, + "-v --verbose - Verbosity on", + + 'd', "dump", NULL, NULL, 0, 0, &dump, + "-d --dump - Dump buffers", + + 't', "test", NULL, NULL, 0, 0, &test, + "-t --test - test on", + + 'b', "ppub", NULL, NULL, 0, 0, &ppub, + "-p --ppub - print public key", + + 0, NULL, NULL, NULL, 0, 0, NULL, NULL, + }; + +char *test_str = //"Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." + "Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." + "Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world."; + +char tmp_str[MAX_PATH]; + +char usestr[] = "ascrypt [options] keyfile"; + +static void myfunc(int sig) +{ + printf("\nSignal %d (segment violation)\n", sig); + exit(111); +} + +////////////////////////////////////////////////////////////////////////// + +int main(int argc, char** argv) + +{ + signal(SIGSEGV, myfunc); + + char *err_str; + int nn = parse_commad_line(argv, opts_data, &err_str); + if (err_str) + { + printf(err_str); + usage(usestr, opts_data); exit(2); + } + + if(verbose) + { + //printf("nn=%d test=%d verbose=%d\n", nn, test, verbose); + printf("infile='%s' outfile='%s' keyfile='%s'\n", infile, outfile, keyfile); + } + + if (argc - nn != 2 && strlen(keyfile) == 0) { + printf("Missing argument for ascrypt."); + usage(usestr, opts_data); exit(2); + } + + if(argc - nn >= 2) + { + strncpy(keyfile, argv[nn + 1], sizeof(keyfile)); + } + + //zverbose(1); + gcrypt_init(); + gcry_error_t err; + //char* fname = argv[nn + 1]; + + FILE* lockf = fopen(keyfile, "rb"); + if (!lockf) { + xerr2("fopen() failed on file '%s'", keyfile); + } + + /* Grab the public key and key size */ + unsigned int rsa_len = getfsize(lockf); + if(verbose) + printf("Key file size %d\n", rsa_len); + + zline(__LINE__); + char* rsa_buf = zalloc(rsa_len + 1); + if (!rsa_buf) { + xerr("malloc: could not allocate rsa buffer"); + } + if (fread(rsa_buf, rsa_len, 1, lockf) != 1) { + xerr("fread() on public key failed"); + } + + fclose(lockf); + + //rsa_buf[rsa_len] = '\0'; + int outlen = rsa_len; + char *dec_err_str; + char *mem = decode_pub_key(rsa_buf, &outlen, &dec_err_str); + if(mem == NULL) + { + //printf("%s\n", dec_err_str); + //xerr("Cannot decode public key"); + xerr2("Cannot decode public key: %s", dec_err_str); + } + + if(ppub) + dump_mem(mem, outlen); + + gcry_sexp_t pubkey; + err = gcry_sexp_new(&pubkey, mem, outlen, 1); + zfree(mem); + if (err) { + printerr(err, "encrypt"); + xerr("gcrypt: failed to read public key."); + } + + if(ppub) + print_sexp(pubkey); + + int keylen = gcry_pk_get_nbits(pubkey) / 8; + //printf("keylen %d\n", keylen); + + /* Read in a buffer */ + char* data_buf; + unsigned int data_len; + if(strlen(infile)) + { + FILE* dataf = fopen(infile, "rb"); + if (!dataf) { + xerr2("Cannot open data file: '%s'", infile); + } + data_len = getfsize(dataf); + //printf("data file size %d\n", rsa_len); + zline(__LINE__); + data_buf = zalloc(data_len + 1); + if (!data_buf) { + xerr("malloc: could not allocate data buffer"); + } + if (fread(data_buf, data_len, 1, dataf) != 1) { + xerr("fread() on data file failed"); + } + } + else + { + data_len = strlen(test_str); + zline(__LINE__); + data_buf = zalloc(data_len + 1); + memcpy(data_buf, test_str, data_len); + } + //if(dump) + // { + // dump_mem(data_buf, data_len); + // } + + int outlen2 = 0, outlim = data_len * 2 + keylen * 2; + zline(__LINE__); + char *outptr = zalloc(outlim); + if(!outptr) + { + xerr("Cannot allocate memory"); + } + + /* Create a message. Parse keylen chunks, padd last chunk with zeros */ + for(int loop = 0; loop < data_len; loop += keylen) + { + int curr_len = keylen; + if(data_len - loop < keylen) + { + curr_len = data_len - loop; + //if(loop + keylen > outlim) + // { + // xerr("Output limit overwite prevented"); + // } + //memset(data_buf + data_len, keylen - (data_len % keylen), '\0'); + //printf("magic len %d\n", keylen - (data_len % keylen)); + } + + //printf("data %p len = %d ", data_buf + loop, curr_len); + + gcry_mpi_t msg; + err = gcry_mpi_scan(&msg, GCRYMPI_FMT_USG, data_buf + loop, + curr_len, NULL); + + if (err) { + xerr("failed to create a mpi from the message"); + } + + gcry_sexp_t enc_data; + err = gcry_sexp_build(&enc_data, NULL, + "(data (flags raw) (value %m))", msg); + + if (err) { + printerr(err, "bulding sexp"); + xerr("failed to create a sexp from the message"); + } + + /* Encrypt the message. */ + gcry_sexp_t ciph; + err = gcry_pk_encrypt(&ciph, enc_data, pubkey); + if (err) { + printerr(err, "encryption"); + xerr("gcrypt: encryption failed"); + } + + //if(dump) + // print_sexp(ciph); + + gcry_sexp_t ddd = gcry_sexp_find_token(ciph, "a", 1); + //print_sexp(ddd); + + if(ddd == NULL) + if (err) { + xerr("Internal: find token failed"); + } + + unsigned int plen = 0; + const char *dptr = gcry_sexp_nth_data(ddd, 1, &plen); + + //printf("outlen %d\n", plen); + if(dump) + { + //printf("Output:\n"); + dump_mem(dptr, plen); + } + // Add to our cummulative buffer + + if(outlen2 + plen > outlim) + { + xerr("Could not write all mem to buffer"); + } + *( (short *)(outptr + outlen2)) = (short) plen & 0xffff; + outlen2 += sizeof(short); + memcpy(outptr + outlen2, dptr, plen); + outlen2 += plen; + + /* Release contexts. */ + gcry_mpi_release(msg); + gcry_sexp_release(enc_data); + gcry_sexp_release(ciph); + } + int outx, plen; + char *mem3 = base_and_lim(outptr, outlen2, &outx); + + FILE* outf = stdout; + if(strlen(outfile)) + { + outf = fopen(outfile, "wb"); + if(!outf) + { + xerr("Cannnot open outfile"); + } + } + int fullen = strlen(cyph_start) + strlen(cyph_start) + outx + 10; + char *mem4 = malloc(fullen); + if(!mem4) + xerr("Cannot allocate memory"); + + int add = snprintf(mem4, fullen, "%s\n", cyph_start); + add += snprintf(mem4 + add, fullen - add, "%.*s\n", outx, mem3); + add += snprintf(mem4 + add, fullen - add, "%s\n", cyph_end); + + //dump_mem(mem4, add); + int retf = fwrite(mem4, add, 1, outf); + if(retf != 1) + { + xerr("Cannot write to file"); + } + + //fprintf(outf, "%s\n", cyph_start); + //fprintf(outf, "%*s\n", outx, mem3); + //fprintf(outf, "%s\n", cyph_end); + + if(outf != stdout) + { + fclose(outf); + } + + zfree(mem3); + zfree(data_buf); + + /* Release contexts. */ + gcry_sexp_release(pubkey); + + zline(__LINE__); + zfree(rsa_buf); + zfree(outptr); + + zleak(); + return 0; +} + + +#if 0 + + int outlen = base64_calc_encodelen(strlen(s)); + zline(__LINE__); + char *mem = zalloc(outlen); + base64_encode(s, strlen(s), mem, &outlen); + zcheck(mem, __LINE__); + printf("base64\n%s\n", mem); + + int declen = base64_calc_decodelen(outlen); + char *dmem = zalloc(declen); + base64_decode(mem, outlen, dmem, &declen); + printf("dec base64\n%s\n", dmem); + //dump_mem(dmem, strlen(dmem)); + zcheck(dmem, __LINE__); + zfree(mem); + #endif + +/* EOF */ + + + + + + + + + + + + + + + + + Index: examples/peterglen/base64.h =================================================================== --- /dev/null +++ examples/peterglen/base64.h @@ -0,0 +1,29 @@ + +/* =====[ keygen.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + 0.00 aug.03.2017 Peter Glen Added baselim + + ======================================================================= */ + +int base64_calc_encodelen(int len); +int base64_calc_decodelen(int len); + +int base64_encode(const unsigned char *data, + int input_length, char *encoded_data, int *output_length) ; + +int base64_decode(const char *data, + int input_length, unsigned char *decoded_data, + int *output_length) ; + +int base64_limline(const char *inp, int inlen, char *outp, int *olen, int linelen); +int base64_clean(const char *inp, int inlen, char *outp, int *olen); + +/* EOF */ Index: examples/peterglen/base64.c =================================================================== --- /dev/null +++ examples/peterglen/base64.c @@ -0,0 +1,272 @@ + +/* =====[ base64.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include +#include +#include + +////////////////////////////////////////////////////////////////////////// +// Clumsy attempt to detect 32 bit build + +//#define SIZEOF(x) ((char*)(&(x) + 1) - (char*)&(x)) + +#ifndef UINTPTR_MAX +#error Not defined UINTPTR_MAX +#endif + +#ifndef UINT_MAX +#error Not defined UINT_MAX +#endif + +#if UINT_MAX != 0xffffffff + #error "Unexpected integer size, expecting a 32 bit machine." +#endif + +#if UINTPTR_MAX <= UINT_MAX + // Compile 32 bit + #ifndef uint32_t + typedef unsigned int uint32_t ; + #endif +#else + #error Integer is not 32 bit, editing needed __SIZEOF_INT__ +#endif + +static void build_decoding_table() ; +static char decoding_table[256] = {0}; +static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/'}; + +static int mod_table[] = {0, 2, 1}; + +// Encode + +int base64_calc_encodelen(int len) +{ + return ((4 * (len + 2)) / 3) + 3; +} + +int base64_encode(const unsigned char *data, + int input_length, char *encoded_data, int *output_length) +{ + int ret = 0; + + if (*output_length < 4 * ((input_length + 2) / 3) + 1) + return -1; + + if (encoded_data == NULL) return -1; + int domlen = (input_length / 3) * 3; + //printf("input_length=%d domlen=%d outlen=%d\n", + // input_length, domlen, (domlen / 3) * 4); + int ii, jj; + for (ii = 0, jj = 0; ii < domlen;) { + + uint32_t octet_a = ii < input_length ? (unsigned char)data[ii++] : 0; + uint32_t octet_b = ii < input_length ? (unsigned char)data[ii++] : 0; + uint32_t octet_c = ii < input_length ? (unsigned char)data[ii++] : 0; + + uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + + encoded_data[jj++] = encoding_table[(triple >> 3 * 6) & 0x3F]; + encoded_data[jj++] = encoding_table[(triple >> 2 * 6) & 0x3F]; + encoded_data[jj++] = encoding_table[(triple >> 1 * 6) & 0x3F]; + encoded_data[jj++] = encoding_table[(triple >> 0 * 6) & 0x3F]; + } + + // Output final sequence + if((input_length) % 3 == 2) + { + //printf("add two %c %c ", data[ii], data[ii + 1]); + uint32_t octet_a = ii < input_length ? (unsigned char)data[ii++] : 0; + uint32_t octet_b = ii < input_length ? (unsigned char)data[ii++] : 0; + + uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08); + + encoded_data[jj++] = encoding_table[(triple >> 3 * 6) & 0x3F]; + encoded_data[jj++] = encoding_table[(triple >> 2 * 6) & 0x3F]; + encoded_data[jj++] = encoding_table[(triple >> 1 * 6) & 0x3F]; + encoded_data[jj++] = '='; + } + if((input_length % 3) == 1) + { + //printf("add one %c ", data[ii]); + uint32_t octet_a = ii < input_length ? (unsigned char)data[ii++] : 0; + + uint32_t triple = (octet_a << 0x10); + + encoded_data[jj++] = encoding_table[(triple >> 3 * 6) & 0x3F]; + encoded_data[jj++] = encoding_table[(triple >> 2 * 6) & 0x3F]; + encoded_data[jj++] = '='; + encoded_data[jj++] = '='; + } + + if(jj < *output_length) + encoded_data[jj] = '\0'; + *output_length = jj; + return ret; +} + +int base64_calc_decodelen(int len) +{ + return (len / 4) * 3 + 1; +} + +// Decode + +int base64_decode(const char *data, + int input_length, unsigned char *decoded_data, + int *output_length) +{ + int ret = 0; + + if (decoding_table[0] == 0) build_decoding_table(); + + if (decoded_data == 0L) return -1; + + if (input_length % 4 != 0) + { + printf("Length not divided by four"); + return -1; + } + int expected_length = (input_length * 3) / 4; + if (*output_length < expected_length) + { + printf("Short buffer passed."); + return -1; + } + if (data[input_length - 1] == '=') expected_length--; + if (data[input_length - 2] == '=') expected_length--; + + int domlen = (input_length / 4) * 4; + //printf("input_length=%d domlen=%d outlen=%d\n", + // input_length, domlen, (domlen / 4) * 3); + + int ii, jj; + for (ii = 0, jj = 0; ii < domlen; /*none*/) + { + uint32_t sextet_a = data[ii] == '=' ? 0 & ii++ : decoding_table[data[ii++]]; + uint32_t sextet_b = data[ii] == '=' ? 0 & ii++ : decoding_table[data[ii++]]; + uint32_t sextet_c = data[ii] == '=' ? 0 & ii++ : decoding_table[data[ii++]]; + uint32_t sextet_d = data[ii] == '=' ? 0 & ii++ : decoding_table[data[ii++]]; + + uint32_t triple = (sextet_a << 3 * 6) + + (sextet_b << 2 * 6) + + (sextet_c << 1 * 6) + + (sextet_d << 0 * 6); + + if (jj < expected_length) decoded_data[jj++] = (triple >> 2 * 8) & 0xFF; + if (jj < expected_length) decoded_data[jj++] = (triple >> 1 * 8) & 0xFF; + if (jj < expected_length) decoded_data[jj++] = (triple >> 0 * 8) & 0xFF; + } + + if(jj < *output_length) + decoded_data[jj] = '\0'; + *output_length = jj; + return ret; +} + +////////////////////////////////////////////////////////////////////////// +// Limit the line length of base64 strings + + +int base64_limline(const char *inp, int inlen, char *outp, int *olen, int linelen) + +{ + int ret = 0, loop = 0, cnt = 0, prog = 0; + + for(loop = 0; loop < inlen; loop ++) + { + outp[prog] = inp[loop]; prog ++; + if(prog >= *olen) { ret = -1; break; } + + if((prog % (linelen + 1)) == linelen) + { + outp[prog] = '\n'; prog++; + if(prog >= *olen) { ret = -1; break; } + } + } + // Zero terminate + if(prog < *olen) + { + outp[prog] = '\0'; + + // Do not do this, as it cheats on binary data ... + // however it is a safety catch in case you put printf to it + // prog ++; + } + else + { ret = -1; } + *olen = prog; + return ret; +} + +int base64_clean(const char *inp, int inlen, char *outp, int *olen) +{ + int ret = 0, loop = 0, cnt = 0, prog = 0; + + for(loop = 0; loop < inlen; loop ++) + { + unsigned char cch = inp[loop]; + if( (cch == '+') || (cch == '/') || (cch == '=') || + ((cch >= 'a') && (cch <= 'z')) || + ((cch >= 'A') && (cch <= 'Z')) || + ((cch >= '0') && (cch <= '9')) + ) + { + outp[prog] = cch; prog ++; + if(prog >= *olen) + { + ret = -1; break; + } + } + } + + if(prog < *olen) + { + //outp[prog] = '\0'; //prog ++; + } + else + { ret = -1; } + *olen = prog; + return ret; +} + +////////////////////////////////////////////////////////////////////////// +// Helpers + +static void build_decoding_table() +{ + for (int i = 0; i < 64; i++) + decoding_table[(unsigned char) encoding_table[i]] = (unsigned char)i; + +} + + + + + + + + + + + + + + Index: examples/peterglen/bigsample.dec =================================================================== --- /dev/null +++ examples/peterglen/bigsample.dec @@ -0,0 +1,22 @@ +Big file Test + +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. + +End test. + + Index: examples/peterglen/bigsample.enc =================================================================== --- /dev/null +++ examples/peterglen/bigsample.enc @@ -0,0 +1,24 @@ +-----BEGIN GCRYPT RSA CYPHER----- +AQIAlHfpa4EyAuPAkx1wB3Mv0nHrVtwLMVSEEYSK5X8lSSH3k9jjnusiyMH4nvDi +QDRSHZRdXZOP2Wbg1EIfMPQD++yUEZAs15yKpd+tbwEAYnkelNakjplcjUc2aUqq +ZkzIqwnnyNih7mmV4DSKPmtkvGG0iTa2z61IBDh+yjNqInFMx6qdqe5aSmzX+fCQ +cFkDj4A5phnK8j4MqgEqEyo+T/kjt7rqjY6xYUaZhH/yMeFJzcIOV3v3gVdThLlg +Cu1EvNpkyKMqvqHCp+py1TOd7+IeqpzDCAoAjv8nC8PrcJs1sdNPs0AadrNwBnq1 +U9plK0GqTMAYhtrrEM38A9e86vHS48pLYg4UhQClgqpnrP1ssMh44ZEuddCmbEL0 +HiAnGs305oTzS45jG46fSRxAI8gGffB8ZX5V7YA9LLapw753rWcZlO0ZGYlBYu/V +8gphwbY5XqERBCHdGa80AnQO/4gjWC8IG6K0LO0u7qL8Z6SqDaDj3iT+zBMZhWuS +TlLShRkfjrIZNIdnL0CiUN9Qs/hmbixxGyr8UcH2G1yv5nQewglkyfVlLZBt/ILq +XtH7pqNs+7m2g14kjRMOvzUSZLvRcGrWIBts66fH/kkfSHKsMUzgFzw14SJU8ZWR +zsdcOyLzkVuHggTZTUJHiuVHqjWwHI7xTR9/zRAHNGYI84MAAlqMbvuWoqSXDZId +fLc9wTLuBSTC/E2Kw04r6i28DbrxzI0+qfwHkumpXiCVYOJxmhAN8cKOoA5lDQU7 +CuGyogWytHiI09ywmS9swZIkpKQFSC5n/2Ssje1RXjRSVXABcdpEE/wPnaEs60Fw +H4zyObuEYwBhcCcntsAKT5/wrrTt34Uc7EWJwk5DdYGyDW0m0W2ZJaC+2LlK+Z6i +FzHfRSEO11h6WTjzLbiAepQYlrmlyGPX/UtW3nZ6TgqdZDhz2yNbbRogs5/LtUv7 +fwasmREyW8NkJJIrFaVJ2gAiBjcbwSsW85UCCW/Z5f/LIRFwQD24iqv1JQeMcbMZ +4cliGqLJQlTd0fr/RRhz8cLwlYOLQMpn0oaHfFUYYkSuu+ATaKiNN3f1bJWVdehS +AL9zGuwnsXmEen2sfzY9n23/L4UwVW1IrNLknadh9+BGZTg2qr+BaqbtiBnAS2oO +N8EcAhC0M2uWNOoeu6Ad3l1hiYmjz7piBqyADokpZlbDei/Gf654tAlVYyPofYvR +JAOlrX/tcsj959xziC3ofa0oy4+FDaTreC5Ay8dAikH31BqbYGrVUDyStZqfO92m +3TItoHz1vJsiKscCsB4qgCeKGzuAZsuskrV/CWuia41bbzJcQMR4Gur2Rr/ulgTa +F3ySIIYlBLAVAEj7un5YTnzg34rH +-----END GCRYPT RSA CYPHER----- Index: examples/peterglen/bigsample.txt =================================================================== --- /dev/null +++ examples/peterglen/bigsample.txt @@ -0,0 +1,22 @@ +Big file Test + +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. + +End test. + + Index: examples/peterglen/blocksample.dec =================================================================== --- /dev/null +++ examples/peterglen/blocksample.dec @@ -0,0 +1,17 @@ +Block size sample. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +1234567890 +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +End test. + + + Index: examples/peterglen/blocksample.enc =================================================================== --- /dev/null +++ examples/peterglen/blocksample.enc @@ -0,0 +1,13 @@ +-----BEGIN GCRYPT RSA CYPHER----- +bR+dTRHLhHmDsG2its+Axzk8pqGhlQAMS4oKJi3aiLPxzR6dlXY9D64BvpDkTJ13 +x9BuT8VTkzNRTYeojMWq2flWidx8MFX4212HlGGMbdhyr1XX7X20KJOmTrXQNrdl +5AJZzBA9aDWcJGHQs2mvK4TgC99TlmKGTf7ogxePCpH/NRTkWS36oCx4SYmMzAce +6nZEslSBfB7h45X8R7FtQcF3hbrXe7FW2Ry15w4Zb+iEAWCjuQL8nJGPJT+59XYP +uSHpgunYydmKXU15IT1/KExvGPeXJIEmZCsPy091MR0kTpuyTD1q0PknXs/41r+K +uqGXtM+Kwk5RQClPxTYb12DcHkYkJ29+SupdBIeQS1aSfkUjC0E1e6bGVOjqTNl4 +HgKn29f2x08EpD0pqqZe38Zy9bluys/j0Lww5QosIRg+dYfU26+NinLQyzjn+iF2 +TZxrnHE+Jj+JZeaDTpXqFCmT3l+7yT6LDGQJO8jcK/AVFDz5wJ78Yi2bJ0+geg9j +eUOrVvA4JhqRq24rWN88jdd+B/SodOq+b1lSJO//JUhDjlAFq7ysXDM014syQl1I +DShH40WEmqeSJWoSGEyrLnpenotCGvzhz0TiXEinc7mbsZROEYxZrBYrbhY9XesL +FJ6AgVk9zaGNy6d+D0LUz3Ejj/YUnpgD+Xr/DAtb7z0= +-----END GCRYPT RSA CYPHER----- Index: examples/peterglen/blocksample.txt =================================================================== --- /dev/null +++ examples/peterglen/blocksample.txt @@ -0,0 +1,17 @@ +Block size sample. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +1234567890 +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +This is a sample text to encrypt. It is a text file +with some characters in it. +End test. + + + Index: examples/peterglen/dibautil.c =================================================================== --- /dev/null +++ examples/peterglen/dibautil.c @@ -0,0 +1 @@ + Index: examples/peterglen/dump.c =================================================================== --- /dev/null +++ examples/peterglen/dump.c @@ -0,0 +1,61 @@ + +/* =====[ dump.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include + +#include "gcrypt.h" +#include "gcry.h" +#include "gsexp.h" +#include "getpass.h" +#include "zmalloc.h" + +//int keysize = 4096; +int keysize = 1024; + +int main(int argc, char** argv) +{ + if (argc != 2) { + fprintf(stderr, "Usage: dump.exe filename\n"); + xerr("Invalid arguments."); + } + + char* fname = argv[1]; + + FILE* lockf = fopen(fname, "rb"); + if (!lockf) { + xerr("fopen() failed"); + } + + /* Grab the file */ + + unsigned int mem_len = getfsize(lockf); + //printf("File size %d\n", mem_len); + + zline(__LINE__); + void* mem_buf = zalloc(mem_len); + if (!mem_buf) { + xerr("malloc: could not allocate rsa buffer"); + } + + if (fread(mem_buf, mem_len, 1, lockf) != 1) { + xerr("fread() failed"); + } + dump_mem(mem_buf, mem_len); + //printf("%s\n", mem_buf); + zfree(mem_buf); + zleak(); +} + + + Index: examples/peterglen/encdec.c =================================================================== --- /dev/null +++ examples/peterglen/encdec.c @@ -0,0 +1,218 @@ + +/* =====[ encdec.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include + +#include "gcrypt.h" +#include "gcry.h" +#include "gsexp.h" +#include "zmalloc.h" +#include "getpass.h" +#include "base64.h" + +//static int keysize = 2048; + +static void myfunc(int sig) +{ + printf("\nSignal %d (segment violation)\n", sig); + exit(111); +} + +int main(int argc, char** argv) +{ + signal(SIGSEGV, myfunc); + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + xerr("Invalid arguments."); + } + + printf("Showing mutated cypher text.\n"); + + gcrypt_init(); + gcry_error_t err; + char* fname = argv[1]; + + FILE* lockf = fopen(fname, "rb"); + if (!lockf) { + xerr2("fopen() on '%s' failed.", fname); + } + + //int pkv = gcry_pk_map_name("rsa"); + //printf("Public key algo: %d Name: '%s'\n", pkv, gcry_pk_algo_name(pkv) ); + + /* Read and decrypt the key pair from disk. */ + unsigned int flen = getfsize(lockf); + zline2(__LINE__, __FILE__); + char* fbuf = zalloc(flen + 1); + + if (!fbuf) { + xerr("malloc: could not allocate rsa buffer"); + } + + if (fread(fbuf, flen, 1, lockf) != 1) { + xerr("fread() on composit key failed"); + } + fbuf[flen] = '\0'; + zcheck(fbuf, __LINE__); + + char *err_str; + int rsa_len = flen; + char *rsa_buf = decode_comp_key(fbuf, &rsa_len, &err_str); + + if (!rsa_buf) { + xerr2("decode key failed. %s", err_str); + } + + /* Grab a key pair password and create an AES context with it. */ + char passwd[MAXPASSLEN]; int weak = TRUE; + + getpassx passx; + passx.prompt = "Enter keypair pass:"; + passx.pass = passwd; + passx.maxlen = MAXPASSLEN; + passx.minlen = 3; + passx.weak = TRUE; + passx.nodouble = TRUE; + int ret = getpass2(&passx); + if(ret < 0) + xerr("Error on password entry."); + + gcry_cipher_hd_t aes_hd; + get_aes_ctx(&aes_hd, passwd, strlen(passwd)); + + err = gcry_cipher_decrypt(aes_hd, (unsigned char*) rsa_buf, + rsa_len, NULL, 0); + if (err) { + xerr("gcrypt: failed to decrypt key pair"); + } + + /* Load the key pair components into sexps. */ + gcry_sexp_t rsa_keypair; + err = gcry_sexp_new(&rsa_keypair, rsa_buf, rsa_len, 0); + if(err) + { + xerr("gcrypt: failed to rate key pair S-expr (pass?)"); + } + + gcry_sexp_t pubk = gcry_sexp_find_token(rsa_keypair, "public-key", 0); + gcry_sexp_t privk = gcry_sexp_find_token(rsa_keypair, "private-key", 0); + + if(privk == NULL) + { + xerr("No private key here."); + } + //printf("keylen %d\n", gcry_pk_get_nbits(privk)); + + /* Create a message. */ + gcry_mpi_t msg; + gcry_sexp_t data; + const unsigned char* ss = (const unsigned char*) + //"Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." + //"Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." + "Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world."; + + printf("Original message -> %d bytes \n'%s'\n", strlen(ss), (char*) ss); + + err = gcry_mpi_scan(&msg, GCRYMPI_FMT_USG, ss, + strlen((const char*) ss), NULL); + + if (err) { + xerr("failed to create a mpi from the message"); + } + + err = gcry_sexp_build(&data, NULL, + "(data (flags raw) (value %m))", msg); + if (err) { + xerr("failed to create a sexp from the message"); + } + + /* Encrypt the message. */ + gcry_sexp_t ciph; + err = gcry_pk_encrypt(&ciph, data, pubk); + if (err) { + xerr("gcrypt: encryption failed"); + } + + gcry_mpi_t msg2; + gcry_sexp_t data2; + char *sss = strdup(ss); + sss[1] = 'f'; + err = gcry_mpi_scan(&msg2, GCRYMPI_FMT_USG, sss, + strlen((const char*) sss), NULL); + + err = gcry_sexp_build(&data2, NULL, + "(data (flags raw) (value %m))", msg2); + if (err) { + xerr("failed to create a sexp from the message"); + } + gcry_sexp_t ciph2; + err = gcry_pk_encrypt(&ciph2, data2, pubk); + if (err) { + xerr("gcrypt: encryption failed"); + } + + printf("\n" "Cypher:\n"); + gcry_sexp_t ddd = gcry_sexp_find_token(ciph, "a", 1); + print_sexp(ddd); + + unsigned int plen = 0; + const char *ptr = gcry_sexp_nth_data(ddd, 1, &plen); + + printf("\n" "Cypher2:\n"); + gcry_sexp_t ddd2 = gcry_sexp_find_token(ciph2, "a", 1); + print_sexp(ddd2); + + unsigned int plen2 = 0; + const char *ptr2 = gcry_sexp_nth_data(ddd2, 1, &plen2); + //dump_mem(ptr2, plen2); + + /* Decrypt the message. */ + gcry_sexp_t plain; + err = gcry_pk_decrypt(&plain, ciph, privk); + if (err) { + xerr("gcrypt: decryption failed"); + } + gcry_mpi_t out_msg = gcry_sexp_nth_mpi(plain, 0, GCRYMPI_FMT_USG); + + unsigned char *buffm; + int written; + err = gcry_mpi_aprint(GCRYMPI_FMT_USG, &buffm, &written, out_msg); + if (err) { + xerr("failed to stringify mpi"); + } + printf("Decrypted message -> (%d bytes)\n'%s'\n", strlen(buffm), (char*) buffm); + + /* Release contexts. */ + gcry_mpi_release(msg); + gcry_mpi_release(out_msg); + gcry_sexp_release(rsa_keypair); + gcry_sexp_release(pubk); + gcry_sexp_release(privk); + gcry_sexp_release(data); + gcry_sexp_release(ciph); + gcry_sexp_release(plain); + gcry_cipher_close(aes_hd); + zfree(rsa_buf); + //fclose(lockf); + + return 0; +} + + + + + + + Index: examples/peterglen/encrypt.c =================================================================== --- /dev/null +++ examples/peterglen/encrypt.c @@ -0,0 +1,122 @@ + +/* =====[ encrypt.c ]========================================================= + + Description: Encryption examples. Feasability study for diba + [Digital Bank]. Testing libgcrypt library. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include +#include +#include + +#include "zmalloc.h" + +char key[] = "This is the key we are using"; + +void printerr(int err, char *str) + +{ + fprintf (stderr, "%s\n", str); + + fprintf (stderr, "Failure: %s/%s\n", + gcry_strsource (err), + gcry_strerror (err)); + fprintf (stdout, "Failure: %s/%s\n", + gcry_strsource (err), + gcry_strerror (err)); + +} + +void printhex(void *mem, int len) +{ + int aa; + char *ptr = (char *)mem; + for(aa = 0; aa < len; aa++) + { + printf("%02x ", ptr[aa] & 0xff); + if (aa % 32 == 31) + printf("\n"); + } +} + +////////////////////////////////////////////////////////////////////////// + +int main() + +{ + gcry_cipher_hd_t handle; + gcry_error_t err = 0; + + char *plain_text, *out, *deout ; + + gcry_check_version (NULL); + gcry_control( GCRYCTL_DISABLE_SECMEM_WARN ); + gcry_control( GCRYCTL_INIT_SECMEM, 16384, 0 ); + + //err = gcry_cipher_open (&handle, GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 0); + + int cyp = GCRY_CIPHER_TWOFISH; + //int cyp = GCRY_CIPHER_IDEA; + int mode = GCRY_CIPHER_MODE_ECB; + + err = gcry_cipher_open (&handle, cyp, mode, 0); + if (err) + printerr(err, "open"); + + int keysize = gcry_cipher_get_algo_keylen(cyp); + int blklen = gcry_cipher_get_algo_blklen(cyp); + printf("Keysize: %d Blocklength: %d\n", keysize, blklen); + + //size_t size_of_plain = sizeof(char) * 6; + size_t size_of_crypt = sizeof(char) * 2 * blklen; + + out = zalloc (size_of_crypt); + deout = zalloc (size_of_crypt); + + plain_text = zalloc (blklen); + strncpy(plain_text , "Secret Text", blklen); + plain_text[blklen - 1] = 0; + + err = gcry_cipher_setkey (handle, key, keysize); + if (err) + printerr(err, "setkey"); + + //gcry_cipher_final(handle); + err = gcry_cipher_encrypt (handle, + (unsigned char *)out, size_of_crypt, (const unsigned char *)plain_text, blklen); + if (err) + printerr(err, "encrypt"); + + err = gcry_cipher_setkey (handle, key, keysize); + if (err) + printerr(err, "setkey"); + + //gcry_cipher_final(handle); + err = gcry_cipher_decrypt (handle, + (unsigned char *)deout, size_of_crypt, (const unsigned char *)out, blklen); + if (err) + { + printerr(err, "decrypt"); + } + + printf("Plain text: (len=%d) '%s'", strlen(plain_text), plain_text); + printf("\nCypher:\n"); + printhex(out, size_of_crypt); + printf("\nCypher end.\n"); + printf("Decr text: '%s'\n", deout); + + zfree(plain_text); + zfree(out); + zfree(deout); + gcry_cipher_close(handle); + return 0; +} + + Index: examples/peterglen/gcry.h =================================================================== --- /dev/null +++ examples/peterglen/gcry.h @@ -0,0 +1,77 @@ + +/* =====[ gcry.h ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.17.2017 Peter Glen Added dump mem + 0.00 jul.22.2017 Peter Glen Sexp helpers + + ======================================================================= */ + +// Unified strings for files + +const char *pub_start; +const char *pub_end; +const char *comp_start; +const char *comp_end; +const char *cyph_start; +const char *cyph_end; +const char *mod_start; +const char *mod_end; +const char *exp_start; +const char *exp_end; + +typedef struct _opts +{ + char opt; + char *long_opt; + int *val; + char *strval; + int minval, maxval; + int *flag; + char *help; +} opts; + +int parse_commad_line(char **argv, opts *popts_data, char **err_str); +void usage(const char *progname, opts *opts_data); + +// /* Crash routines. */ +void xerr(const char* msg); +void xerr2(const char* msg, ...); +void printerr(int err, char *str); + +// /* Initialize libgcrypt. */ +void gcrypt_init(); + +unsigned int getfsize(FILE *fp); + +// /* Estimate the size of the encrypted key pair. */ +size_t get_keypair_size(int nbits); + +// /* Create an AES context out of a user's password. */ +void get_aes_ctx(gcry_cipher_hd_t* aes_hd, const char *passwd, int pass_len); +void print_cypher_details(const char *str); + +char *decode_comp_key(char *rsa_buf, int *prsa_len, char **err_str); +char *decode_rsa_cyph(char *rsa_buf, int *prsa_len, char **err_str); +char *decode_pub_key(char *rsa_buf, int *prsa_len, char **err_str); + +int write_pubkey(gcry_sexp_t *rsa_keypair, const char *xfname2); +int write_mod_exp(gcry_sexp_t *rsa_keypair, const char *xfname2); + +int pk_encrypt_buffer(const char *buf, int len, gcry_sexp_t pubk, gcry_sexp_t *ciph); + +char *base_and_lim(const char *mem, int len, int *olen); +char *randstr(int len); +char *tobase64(char *mem, int *len); +char *datestr(); +char *zstrcat(const char *str1, const char* str2); + +// EOF + + Index: examples/peterglen/gcry.c =================================================================== --- /dev/null +++ examples/peterglen/gcry.c @@ -0,0 +1,739 @@ + +/* =====[ gcry.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + 0.00 jul.17.2017 Peter Glen Added dump mem + + ======================================================================= */ + +#include +#include + +#include "gcrypt.h" +#include "gcry.h" +#include "gsexp.h" +#include "zmalloc.h" +#include "getpass.h" +#include "base64.h" + +// ----------------------------------------------------------------------- +// Unified strings for key files, definitons + +const char *pub_start = "-----BEGIN GCRYPT RSA PUBLIC KEY-----"; +const char *pub_end = "-----END GCRYPT RSA PUBLIC KEY-----"; + +const char *comp_start = "-----BEGIN GCRYPT RSA COMPOSITE KEY-----"; +const char *comp_end = "-----END GCRYPT RSA COMPOSITE KEY-----"; + +const char *cyph_start = "-----BEGIN GCRYPT RSA CYPHER-----"; +const char *cyph_end = "-----END GCRYPT RSA CYPHER-----"; + +const char *mod_start = "-----BEGIN RSA PUBLIC MODULUS-----"; +const char *mod_end = "-----END RSA PUBLIC MODULUS-----"; + +const char *exp_start = "-----BEGIN RSA PUBLIC EXPONENT-----"; +const char *exp_end = "-----END RSA PUBLIC EXPONENT-----"; + +void xerr(const char* msg) +{ + fprintf(stderr, "%s\n", msg); + exit(2); +} + +void xerr2(const char* msg, ...) +{ + va_list ap; + va_start(ap, msg); + + vfprintf(stderr, msg, ap); + exit(2); +} + +////////////////////////////////////////////////////////////////////////// + +void printerr(int err, char *str) + +{ + if(str) + fprintf (stderr, "%s\n", str); + + fprintf (stderr, "Failure: %s/%s\n", + gcry_strsource (err), + gcry_strerror (err)); + + //fprintf (stdout, "Failure: %s/%s\n", + // gcry_strsource (err), + // gcry_strerror (err)); +} + +////////////////////////////////////////////////////////////////////////// + +void gcrypt_init() + +{ + /* Version check should be the very first call because it + makes sure that important subsystems are intialized. */ + if (!gcry_check_version (GCRYPT_VERSION)) + { + xerr("gcrypt: library version mismatch"); + } + + gcry_error_t err = 0; + + /* We don't want to see any warnings, e.g. because we have not yet + parsed program options which might be used to suppress such + warnings. */ + err = gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); + + /* ... If required, other initialization goes here. Note that the + process might still be running with increased privileges and that + the secure memory has not been intialized. */ + + /* Allocate a pool of 16k secure memory. This make the secure memory + available and also drops privileges where needed. */ + err |= gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0); + + /* It is now okay to let Libgcrypt complain when there was/is + a problem with the secure memory. */ + err |= gcry_control (GCRYCTL_RESUME_SECMEM_WARN); + + /* ... If required, other initialization goes here. */ + + /* Tell Libgcrypt that initialization has completed. */ + err |= gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + + if (err) { + xerr("gcrypt: failed initialization"); + } +} + +size_t get_keypair_size(int nbits) +{ + size_t aes_blklen = gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES128); + + // format overhead * {pub,priv}key (2 * bits) + size_t keypair_nbits = 4 * (2 * nbits); + + size_t rem = keypair_nbits % aes_blklen; + return (keypair_nbits + rem) / 8; +} + +void get_aes_ctx(gcry_cipher_hd_t* aes_hd, const char *passwd, int pass_len) +{ + const size_t keylen = 16; + char passwd_hash[keylen]; + + int err = gcry_cipher_open(aes_hd, GCRY_CIPHER_AES128, + GCRY_CIPHER_MODE_CFB, 0); + if (err) { + xerr("gcrypt: failed to create aes handle"); + } + + gcry_md_hash_buffer(GCRY_MD_MD5, (void*) &passwd_hash, + (const void*) passwd, pass_len); + + err = gcry_cipher_setkey(*aes_hd, (const void*) &passwd_hash, keylen); + if (err) { + xerr("gcrypt: could not set cipher key"); + } + + err = gcry_cipher_setiv(*aes_hd, (const void*) &passwd_hash, keylen); + if (err) { + xerr("gcrypt: could not set cipher initialization vector"); + } +} + +////////////////////////////////////////////////////////////////////////// +// Return file size + +unsigned int getfsize(FILE *fp) + +{ + size_t org_pos = ftell(fp); + fseek(fp, 0, SEEK_END); + size_t file_len = ftell(fp); + fseek(fp, org_pos, SEEK_SET); + + return file_len; +} + +// Helper for command line + +static char tmp_error[MAX_PATH]; + +static int parse_one(const char *str, opts popts_data[], int idx) + +{ + int ret = 0; + + if(popts_data[idx].strval != NULL) + { + if(str == NULL) + { + return -1; + } + strncpy(popts_data[idx].strval, str, MAX_PATH); + ret = 1; + } + else if(popts_data[idx].val != NULL) + { + int val = atoi(str); + if(popts_data[idx].minval > val || + popts_data[idx].maxval < val) + { + return -1; + } + *popts_data[idx].val = val; + ret = 1; + } + else if(popts_data[idx].flag != NULL) + { + *popts_data[idx].flag = TRUE; + } + return ret; +} + +/* + * Read command line switches, set globals. + * + * In: Arguments, procession options, place for error str + * Out: Args parsed + * Return: Last index processed + # Pointer to an error message or NULL + * + */ + +int parse_commad_line(char **argv, opts *popts_data, char **err_str) + +{ + int got, nn, processed = 0, err = 0; + char *ret_val = NULL; + int inval_arg = 0; + + *err_str = NULL; + + for (nn = 1; argv[nn] != NULL; nn++) + { + got = 0; + // Long option? + if(strlen(argv[nn]) > 2 && (argv[nn][0] == '-' && argv[nn][1] == '-')) + { + char *cmdstr = &argv[nn][2]; + //printf("Long option: '%s'\n", cmdstr); + int idx = 0; + if(strcmp(cmdstr, "help") == 0) + { + *err_str = "Help requested, long form."; + return nn; + } + while(TRUE) + { + if(popts_data[idx].long_opt == NULL && popts_data[idx].opt == 0) + { + if(got == 0) + { + err++; + inval_arg = nn; + } + else + processed++; + break; + } + if(strcmp(popts_data[idx].long_opt, cmdstr) == 0) + { + //printf("Found long option %s arg %s\n", cmdstr, argv[nn]); + int ret = parse_one(argv[nn+1], popts_data, idx); + if(ret < 0) + { + snprintf(tmp_error, sizeof(tmp_error), + "Invalid value on option '--%s'\n", cmdstr); + *err_str = tmp_error; + return nn; + } + processed += ret; + got++; + } + idx++; + } + } + else if(argv[nn][0] == '-' || argv[nn][0] == '/') /* option recognized */ + { + int idx = 0; + //char cmd = tolower(argv[nn][1]); // made it case sensitive + char cmd = argv[nn][1]; + if(cmd == '?' || cmd == 'h') + { + *err_str = "Help requested."; + return nn; + } + while(TRUE) + { + if(popts_data[idx].long_opt == NULL && popts_data[idx].opt == 0) { + if(got == 0) + { + inval_arg = nn; + err++; + } + else + processed++; + break; + } + if(popts_data[idx].opt == cmd) + { + //printf("Got command %c\n", cmd); + got++; + int ret = 0; + if(strlen(argv[nn]) > 2) + { + // Option in line + parse_one(&argv[nn][2], popts_data, idx); + } + else + { + // Next command is option value + ret = parse_one(argv[nn+1], popts_data, idx); + if(ret < 0) + { + snprintf(tmp_error, sizeof(tmp_error), + "Invalid value on option '-%c'\n", cmd); + *err_str = tmp_error; + return nn; + } + } + processed += ret; + } + idx++; + } + } + } + if (err) + { + snprintf(tmp_error, sizeof(tmp_error), + "Invalid option on command line '%s'\n", argv[inval_arg]); + *err_str = tmp_error; + } + return(processed); +} + +void usage(const char *progname, opts *opts_data) + +{ + int idx = 0, ret_val = 0; + + //printf("opts_data %s", opts_data); + + printf("\ +\n\ +Usage: %s\n\ +Options can be: \n\ +", progname); + + while(TRUE) + { + if(opts_data[idx].opt == 0) + break; + + printf(" %s\n", opts_data[idx].help); + idx++; + } + printf("\n"); + printf( " -? --help - displays this help\n"); + printf( " -h --help - displays this help\n"); + printf( "One option per item, last option prevails.\n"); +} + +////////////////////////////////////////////////////////////////////////// + +typedef struct _armor_params +{ + char *rsa_buf; + int *prsa_len; + char **err_str; + int *cleanlen; + const char *starts; + const char *ends; +} +armor_params; + +static char *decode_armor(armor_params *params) + +{ + char *sbegin = strstr(params->rsa_buf, params->starts); + if(sbegin == NULL) + { + *params->err_str = "No start marker"; + return(NULL); + } + char *send = strstr(params->rsa_buf, params->ends); + if(send == NULL) + { + *params->err_str = "No end marker"; + return(NULL); + } + sbegin += strlen(params->starts); + int slen = send - sbegin; + *params->cleanlen = slen; + return sbegin; +} + +////////////////////////////////////////////////////////////////////////// +// Unscramble --Begin --End marks, then base64 unexpand and decode. +// free pointer with zalloc / zfree. + +char *decode_pub_key(char *rsa_buf, int *prsa_len, char **err_str) + +{ + armor_params params; + int slen; + *err_str = NULL; + params.rsa_buf = rsa_buf; params.prsa_len = prsa_len; + params.err_str = err_str; params.cleanlen = &slen; + params.starts = pub_start; params.ends = pub_end; + + char *sbegin = decode_armor(¶ms); + if(!sbegin) + return NULL; + + int cleanlen = slen; + zline2(__LINE__, __FILE__); + char *memc = zalloc(cleanlen); + base64_clean(sbegin, slen, memc, &cleanlen); + + int outlen = base64_calc_decodelen(cleanlen); + zline2(__LINE__, __FILE__); + char *mem = zalloc(cleanlen); + base64_decode(memc, cleanlen, mem, &outlen); + zcheck(mem, __LINE__); + zfree(memc); + *prsa_len = outlen; + return mem; +} + +////////////////////////////////////////////////////////////////////////// +// Unscramble --Begin --End marks, then base64 unexpand and decode. +// free pointer with zalloc / zfree. + +char *decode_rsa_cyph(char *rsa_buf, int *prsa_len, char **err_str) + +{ + armor_params params; + int slen; + *err_str = NULL; + params.rsa_buf = rsa_buf; params.prsa_len = prsa_len; + params.err_str = err_str; params.cleanlen = &slen; + params.starts = cyph_start; params.ends = cyph_end; + + char *sbegin = decode_armor(¶ms); + if(!sbegin) + return NULL; + + int cleanlen = slen; + zline2(__LINE__, __FILE__); + char *memc = zalloc(cleanlen); + base64_clean(sbegin, slen, memc, &cleanlen); + zcheck(memc, __LINE__); + + int outlen = base64_calc_decodelen(cleanlen); + zline2(__LINE__, __FILE__); + char *mem = zalloc(cleanlen); + base64_decode(memc, cleanlen, mem, &outlen); + zcheck(mem, __LINE__); + + zfree(memc); + *prsa_len = outlen; + return mem; +} + +////////////////////////////////////////////////////////////////////////// +// Unscramble --Begin --End marks, then base64 unexpand and decode. +// free pointer with zalloc / zfree. + +char *decode_comp_key(char *rsa_buf, int *prsa_len, char **err_str) + +{ + armor_params params; + int slen; + *err_str = NULL; + params.rsa_buf = rsa_buf; params.prsa_len = prsa_len; + params.err_str = err_str; params.cleanlen = &slen; + params.starts = comp_start; params.ends = comp_end; + + char *sbegin = decode_armor(¶ms); + if(!sbegin) + return(NULL); + + int cleanlen = slen; + zline2(__LINE__, __FILE__); + + char *memc = zalloc(cleanlen); + base64_clean(sbegin, slen, memc, &cleanlen); + + int outlen = base64_calc_decodelen(cleanlen); + zline2(__LINE__, __FILE__); + char *mem = zalloc(cleanlen); + base64_decode(memc, cleanlen, mem, &outlen); + zcheck(mem, __LINE__); + zfree(memc); + *prsa_len = outlen; + return mem; +} + +void print_cypher_details(const char *str) + +{ + int cy = gcry_cipher_map_name(str); + printf("Cypher: %d\n", cy); + printf("Cypher name: '%s'\n", gcry_cipher_algo_name(cy)); + printf("Blocklen: %d\n", gcry_cipher_get_algo_blklen(cy)); + printf("Keylen: %d\n", gcry_cipher_get_algo_keylen(cy)); + printf("\n"); +} + +////////////////////////////////////////////////////////////////////////// + +int pk_encrypt_buffer(const char *buf, int len, gcry_sexp_t pubk, gcry_sexp_t *ciph) + +{ + int ret = 0; + + /* Create a message. */ + gcry_mpi_t msg; + gcry_error_t err = gcry_mpi_scan(&msg, GCRYMPI_FMT_USG, buf, len, NULL); + + if (err) { + printerr(err, "create mpi"); + //xerr("failed to create a mpi from the buffer"); + } + + gcry_sexp_t data; + err = gcry_sexp_build(&data, NULL, "(data (flags raw) (value %m))", msg); + if (err) { + printerr(err, "build"); + //xerr("failed to create a sexp from the message"); + } + + /* Encrypt the message. */ + err = gcry_pk_encrypt(ciph, data, pubk); + if (err) { + print_sexp(*ciph); + printerr(err, "encryption"); + //xerr("gcrypt: encryption failed"); + } + + gcry_sexp_release(data); + gcry_mpi_release(msg); + ret = err; + return ret; +} + +////////////////////////////////////////////////////////////////////////// + +int write_pubkey(gcry_sexp_t *rsa_keypair, const char *fname2) + +{ + int ret = TRUE; + gcry_sexp_t pubk = gcry_sexp_find_token(*rsa_keypair, "public-key", 0); + int klen; + + char *kptr = sprint_sexp(pubk, &klen, GCRYSEXP_FMT_CANON); + if(!kptr) { + //xerr2("sprint failed. %s %d", __FILE__, __LINE__); + printf("Could not sprint S exp for %s\n", fname2); + return -1; + } + int outx; + char *mem5 = base_and_lim(kptr, klen, &outx); + mem5[outx] = '\0'; + + FILE* fp3 = fopen(fname2, "wb"); + if (!fp3) { + { + //xerr("fopen() failed"); + printf("Could not write publick key %s\n", fname2); + return -1; + } + } + fprintf(fp3, "%s\n", pub_start); + fprintf(fp3, "%.*s\n", outx, mem5); + fprintf(fp3, "%s\n", pub_end); + + fclose(fp3); + zfree(mem5); + zfree(kptr); + + return ret; +} + +int write_mod_exp(gcry_sexp_t *rsa_keypair, const char *fname2) + +{ + int ret = TRUE; + + gcry_sexp_t nnn = gcry_sexp_find_token(*rsa_keypair, "n", 0); + if(nnn == NULL) + { + printf("Could not find public modulus. (no .mod file written)\n"); + return -1; + } + //print_sexp(nnn); + + unsigned int pklen = 0; + const char *pkptr = gcry_sexp_nth_data(nnn, 1, &pklen); + //dump_mem(ptr, pklen); + + gcry_sexp_t eee = gcry_sexp_find_token(*rsa_keypair, "e", 0); + if(eee == NULL) + { + printf("Could not find public expenent. (no .mod file written)\n"); + return -1; + } + //print_sexp(eee); + unsigned int elen = 0; + const char *eptr = gcry_sexp_nth_data(eee, 1, &elen); + + FILE* fp2 = fopen(fname2, "wb"); + if (!fp2) { + printf("Could not write .mod file to %s\n", fname2); + return -1; + //xerr("fopen() failed"); + } + int outx; + zline2(__LINE__, __FILE__); + char *mem3 = base_and_lim(pkptr, pklen, &outx); + mem3[outx] = '\0'; + fprintf(fp2, "%s\n", mod_start); + fprintf(fp2, "%.*s\n", outx, mem3); + fprintf(fp2, "%s\n", mod_end); + zline2(__LINE__, __FILE__); + char *mem4 = base_and_lim(eptr, elen, &outx); + mem4[outx] = '\0'; + fprintf(fp2, "%s\n", exp_start); + fprintf(fp2, "%.*s\n", outx, mem4); + fprintf(fp2, "%s\n", exp_end); + + fclose(fp2); + zfree(mem3); + zfree(mem4); + + return ret; +} + +////////////////////////////////////////////////////////////////////////// +// Return an allocated base64 line limited string. +// Must use zfree to free pointer + +char *base_and_lim(const char *mem, int len, int *olen) +{ + int outlen = base64_calc_encodelen(len); + zline2(__LINE__, __FILE__); + char *mem2 = zalloc(outlen); + int ret = base64_encode(mem, len, mem2, &outlen); + if(ret < 0) + return NULL; + zcheck(mem2, __LINE__); + zline2(__LINE__, __FILE__); + + int linelen = 64, limlen = outlen + 4 + outlen / linelen ; + char *mem3 = zalloc(limlen); + int ret2 = base64_limline(mem2, outlen, mem3, &limlen, linelen); + zfree(mem2); + if(ret2 < 0) + return NULL; + *olen = limlen; + + return mem3; +} + +#if 0 + int tm_sec; /* Seconds: 0-60 (to accommodate leap seconds) */ + int tm_min; /* Minutes: 0-59 */ + int tm_hour; /* Hours since midnight: 0-23 */ + int tm_mday; /* Day of the month: 1-31 */ + int tm_mon; /* Months *since* January: 0-11 */ + int tm_year; /* Years since 1900 */ + int tm_wday; /* Days since Sunday (0-6) */ + int tm_yday; /* Days since Jan. 1: 0-365 */ + int tm_isdst; /* +1=Daylight Savings Time, 0=No DST, -1=unknown */ + #endif + +////////////////////////////////////////////////////////////////////////// +// get current date, return pointer. +// must free with zfree + +char *datestr() + +{ + int allocsize = 64; + zline2(__LINE__, __FILE__); + char *ttt = zalloc(allocsize); + time_t tme = time(NULL); + struct tm *tmm = localtime(&tme); + int len = snprintf(ttt, allocsize, "%4d/%02d/%02d %02d:%02d:%02d", + tmm->tm_year + 1900, tmm->tm_mon + 1, tmm->tm_mday, + tmm->tm_hour, tmm->tm_min, tmm->tm_sec ); + zcheck(ttt, __LINE__); + return ttt; +} + +// Must free with zfree + +char *randstr(int len) + +{ + zline2(__LINE__, __FILE__); + char *rrr = zalloc(len); + gcry_randomize(rrr, len, GCRY_STRONG_RANDOM); + //rrr[sizeof(rrr)-1] = '\0'; + int len2 = len; + char *ret = tobase64(rrr, &len2); + zcheck(rrr, __LINE__); + zfree(rrr); + return ret; +} + +// Must free with zfree + +char *tobase64(char *mem, int *len) + +{ + int outlen = base64_calc_encodelen(*len); + zline2(__LINE__, __FILE__); + char *mem2 = zalloc(outlen); + int ret = base64_encode(mem, *len, mem2, &outlen); + if(ret < 0) + return NULL; + zcheck(mem2, __LINE__); + *len = outlen; + return(mem2); +} + +////////////////////////////////////////////////////////////////////////// +// + +char *zstrcat(const char *str1, const char* str2) +{ + //printf("cat %s + %s\n", str1, str2); + int len1 = strlen(str1), len2 = strlen(str2); + zline2(__LINE__, __FILE__); + char *ret = zalloc(len1 + len2 + 4); + strcpy(ret, str1); + strcat(ret, str2); + zcheck(ret, __LINE__); + //printf("cat out %s\n", ret); + return ret; +} + +/* EOF */ + + + + + + Index: examples/peterglen/getpass.h =================================================================== --- /dev/null +++ examples/peterglen/getpass.h @@ -0,0 +1,42 @@ + +/* =====[ getpass.h ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.22.2017 Peter Glen Initial version. + 0.00 jul.30.2017 Peter Glen Added getpass2 + + ======================================================================= */ + +#define MAXPASSLEN 512 +#define ALLOW_TRIES 3 +#define MINPASSLEN 6 + +#define CRTL_C '\3' +#define CRTL_D '\4' + +typedef struct _getpassx + +{ + char *prompt; + char *prompt2; + char *pass; + int maxlen; + int weak; + int nodouble; + int minlen; + int strength; + +} getpassx; + +int getpass(const char *prompt, char *ppp, int maxlen); +int getpass2(getpassx *passx); + +// EOF + + Index: examples/peterglen/getpass.c =================================================================== --- /dev/null +++ examples/peterglen/getpass.c @@ -0,0 +1,213 @@ + +/* =====[ keygen.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include +#include +#include + +#include "getpass.h" +#include "zmalloc.h" + +#define TRUE (1==1) +#define FALSE (1!=1) + +#define CRTL_C '\3' +#define CRTL_D '\4' +#define BACKSPACE '\b' + + +// Strenghts: +// Every item kind adds two points. (upper, lower, number, punct) + +static int getstrength(const char *pass) +{ + int ret = 0; + if(strpbrk((char*)pass, "1234567890")) + { + //printf("number token\n"); + ret += 2; + } + if(strpbrk((char*)pass, "abcdefghijklmnopqrstuvwxyz")) + { + //printf("lowercase token\n"); + ret += 2; + } + if(strpbrk((char*)pass, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")) + { + //printf("uppercase token\n"); + ret += 2; + } + // Incomplete, re visit on finaliation + if(strpbrk((char*)pass, "*&!@#$%^&*()_+")) + { + //printf("punctuation token\n"); + ret += 2; + } + return ret; +} + +////////////////////////////////////////////////////////////////////////// +// Get pass from console. Return -1 for abort. + +int getpass(const char *prompt, char *passptr, int maxlen) + +{ + int ret = 0; + unsigned int idx = 0; + passptr[idx] = 0; + + printf("%s ", prompt); + fflush(stdout); + + while(TRUE) { + unsigned char cc = _getch(); + + //printf(" '%c' %d ", cc, cc & 0xff); + if(cc == 224 || cc == 0) + { + _getch(); // Throw away + continue; + } + + if (cc == '\n') + break; + if (cc == '\r') + break; + if (cc == EOF) + break; + if (cc == CRTL_C) + { ret = -1; break; } + if (cc == CRTL_D) + { ret = -1; break; } + + if (cc == BACKSPACE) + { + //printf("backspace\n"); + if(idx > 0) + { + idx--; + passptr[idx] = '\0'; + putchar('\b'); putchar(' '); + putchar('\b'); + } + } + else + { + passptr[idx] = cc; + passptr[idx + 1] = '\0'; + putchar('*'); + idx ++; + } + + if (idx >= maxlen) + break; + } + //printf("got pass '%s'\n", passptr); + printf("\n"); + return ret; +} + +////////////////////////////////////////////////////////////////////////// +// Get pass + +int getpass2(getpassx *passx) + +{ + int ret = TRUE; + int try = 0; + + if(passx->maxlen == 0) + return -1; + + char *ppp = zalloc(passx->maxlen + 1); + + while((TRUE)) + { + ret = getpass(passx->prompt, ppp, passx->maxlen); + if (ret < 0) + { + ret = -1; + break; + } + if(try++ >= ALLOW_TRIES) + { + printf("Too many tries, giving up\n"); + ret = -1; + break; + } + + if(!passx->weak) + { + if(strlen(ppp) < passx->minlen) + printf("Must be %d characters or more, try again.\n", passx->minlen); + else if(getstrength(ppp) < passx->strength) + printf("Pass must have upper and lower case letters and numbers, try again.\n"); + else + break; + } + else + { + if(strlen(ppp) <= 0) + printf("Cannot use empty pass, try again.\n"); + else + break; + } + } + if(ret < 0) + { + zfree(ppp); + return ret; + } + + if(passx->nodouble == FALSE) + { + char *ppp2 = zalloc(passx->maxlen + 1); + int try2 = 0; + while((TRUE)) + { + ret = getpass(passx->prompt2, ppp2, passx->maxlen); + if(ret < 0) + break; + + if(strcmp(ppp, ppp2) == 0) + break; + + if(try2++ >= ALLOW_TRIES) + { + printf("Too many tries, giving up\n"); + ret = -1; + break; + } + printf("Passes do not match, try again.\n"); + } + zfree(ppp2); + } + //printf("ppp '%s' maxlen %d", ppp, passx->maxlen); + if(ret >= 0) + { + strncpy(passx->pass, ppp, passx->maxlen); + } + zfree(ppp); + + return ret; +} + + + + + + + + + Index: examples/peterglen/gsexp.h =================================================================== --- /dev/null +++ examples/peterglen/gsexp.h @@ -0,0 +1,24 @@ + +/* =====[ keygen.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 aug03.2017 Peter Glen Initial version. + + ======================================================================= */ + +// Sexp helpers +char *sprint_sexp(gcry_sexp_t sexp, int *len, int format); +void print_sexp(gcry_sexp_t rsa_keypair); +int decode_sexp(gcry_sexp_t list, const char *findstr); + +// General memory helpers +void dump_mem(const char *ptr, int len); + + + Index: examples/peterglen/gsexp.c =================================================================== --- /dev/null +++ examples/peterglen/gsexp.c @@ -0,0 +1,147 @@ + +/* =====[ keygen.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 aug03.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include + +#include "gcrypt.h" +#include "gcry.h" +#include "gsexp.h" +#include "zmalloc.h" + +////////////////////////////////////////////////////////////////////////// +// Print sexp to memory +// Free the resulting pointer + +char *sprint_sexp(gcry_sexp_t sexp, int *len, int format) + +{ + int slen = gcry_sexp_sprint(sexp, format, NULL, 0); + *len = 0; + zline2(__LINE__, __FILE__); + char *ppp = (char*)zalloc(slen+1); + if(ppp == NULL) + return NULL; + + gcry_sexp_sprint(sexp, format, ppp, slen); + *len = slen; + // Zero terminate + ppp[slen-1] = '\0'; + return(ppp); +} + +////////////////////////////////////////////////////////////////////////// +// Print sexp to stdout + +void print_sexp(gcry_sexp_t rsa_keypair) + +{ + int len; + char *ppp = sprint_sexp(rsa_keypair, &len, GCRYSEXP_FMT_ADVANCED); + if(ppp == NULL) + return; + printf("%s\n", ppp); + zfree(ppp); +} + +void dump_mem(const char *ptr, int len) + +{ + int loop, cut = 16, base = 0; + + if (ptr == NULL) + { + printf("NULL\n"); + return; + } + + printf("Begin: %p (len=%d)\n", ptr, len); + while(1==1) + { + printf(" "); + for(loop = 0; loop < 16; loop++) + { + if(base + loop < len) + { + printf("%.02x", ptr[base + loop] & 0xff); + if(loop < 15) + printf("-"); + } + else + printf(" "); + } + printf(" "); + for(loop = 0; loop < 16; loop++) + { + if(base + loop < len) + { + unsigned char chh = ptr[base + loop] & 0xff; + if(chh < 128 && chh >= 32 ) + printf("%c", chh); + else + printf("."); + } + else + printf(" "); + } + printf("\n"); + base += 16; + if(base >= len) + break; + } + printf("End\n"); +} + +static int decode_one(gcry_sexp_t list, const char *findstr) + +{ + int len = 0, onelen = gcry_sexp_length(list); + + for(int loop = 0; loop < onelen; loop++) + { + const char *data = gcry_sexp_nth_data(list, loop, &len); + if (data == NULL) + decode_sexp(gcry_sexp_cdr(list), findstr); + else + { + if(strncmp(findstr, data, len) == 0) + { + const char *data2 = gcry_sexp_nth_data(list, loop + 1, &len); + if (data == NULL) + return 0; + //printf("data%d '%.*s'\n", len, len, data); + //dump_mem(data, len); + } + } + } +} + +int decode_sexp(gcry_sexp_t list, const char *findstr) + +{ + int ret = 0; + + for (int loop = 0; loop < gcry_sexp_length(list); loop++) + { + gcry_sexp_t element = gcry_sexp_nth(list, loop); + //printf("element start\n"); + //print_sexp(element); + //printf("\nelement end\n"); + decode_one(element, findstr); + } + return ret; +} + +/* EOF */ + + Index: examples/peterglen/keygen.c =================================================================== --- /dev/null +++ examples/peterglen/keygen.c @@ -0,0 +1,320 @@ + +/* =====[ keygen.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include +#include +#include + +#include "gcrypt.h" +#include "gcry.h" +#include "getpass.h" +#include "gsexp.h" +#include "base64.h" +#include "zmalloc.h" + +int num_bits_set(unsigned int ks); + +//static int keysize = 1024; +static unsigned int keysize = 2048; +//static int keysize = 4096; + +static int weak = FALSE; +static int force = FALSE; +static int dump = 0; +static int verbose = 0; +static int test = 0; +static int nocrypt = 0; + +char usestr[] = "keygen [options] keyfile\n" + "Where keyfile is the basename for .key .pub .mod files."; +static char thispass[MAX_PATH] = {'\0'}; + +/* char opt; + char *long_opt; + int *val; + char *strval; + int minval, maxval; + int *flag; + char *help; */ + +opts opts_data[] = { + //'i', "infile", NULL, infile, 0, 0, NULL, + //"-i --infile - input file name", + + //'o', "outfile", NULL, outfile, 0, 0, NULL, + //"-o --outfile - output file name", + + //'k', "keyfile", NULL, keyfile, 0, 0, NULL, + //"-k --keyfile - key file name", + + 'k', "keylen", &keysize, NULL, 1024, 32768, NULL, + "-k --keylen - key length in bits", + + 'p', "pass", NULL, thispass, 0, 0, NULL, + "-p --pass - pass in for key (testing only)", + + 'v', "verbose", NULL, NULL, 0, 0, &verbose, + "-v --verbose - Verbosity on", + + 'd', "dump", NULL, NULL, 0, 0, &dump, + "-d --dump - Dump buffers", + + 't', "test", NULL, NULL, 0, 0, &test, + "-t --test - test on", + + 'f', "force", NULL, NULL, 0, 0, &force, + "-f --force - force clobbering files", + + 'w', "weak", NULL, NULL, 0, 0, &weak, + "-w --weak - allow weak pass", + + 'n', "nocrypt", NULL, NULL, 0, 0, &nocrypt, + "-n --nocrypt - do not encrypt key (testing only)", + + 0, NULL, NULL, NULL, 0, 0, NULL, NULL, + }; + + +void my_progress_handler (void *cb_data, const char *what, + int printchar, int current, int total) +{ + printf("."); + //printf("%c", printchar); +} + +static void myfunc(int sig) +{ + printf("\nSignal %d (segment violation)\n", sig); + exit(111); +} + +// ----------------------------------------------------------------------- + +int main(int argc, char** argv) +{ + signal(SIGSEGV, myfunc); + + char *err_str; + int nn = parse_commad_line(argv, opts_data, &err_str); + if (err_str) + { + printf(err_str); + usage(usestr, opts_data); exit(2); + } + + if (argc - nn != 2) { + //fprintf(stderr, "Usage: keygen.exe outfile\n"); + //xerr("Invalid arguments."); + usage(usestr, opts_data); exit(2); + } + if(thispass[0] != '\0') + { + if(nocrypt) + xerr("\nConflicting options, cannot provide key with the 'nocrypt' flag.\n"); + } + //if(keysize % 2 ) + // { + // xerr2("Keysize must be even %d", keysize); + // } + + if(num_bits_set(keysize) != 1) + { + xerr2("Keysize must be a power of two. ( ... 1024, 2048, 4096 ...)"); + } + + gcrypt_init(); + + char* fname = zstrcat(argv[nn+1], ".key"); + //printf("fname %s\n", fname); + char* fname2 = zstrcat(argv[nn+1], ".pub"); + //printf("fname2 %s\n", fname2); + + char* fname3 = zstrcat(argv[nn+1], ".mod"); + //printf("fname3 %s\n", fname3); + + if(access(fname, F_OK) >= 0 && !force) + { + xerr("File already exists, use different name or delete the file or use -f (--force) option."); + } + + /* Generate a new RSA key pair. */ + printf("\nRSA key generation (of %d bits) can take a few minutes. Your computer " + "needs to gather random entropy.\n\n", keysize); + printf("Please wait "); + + gcry_set_progress_handler(my_progress_handler, NULL); + + gcry_error_t err = 0; + gcry_sexp_t rsa_parms; + gcry_sexp_t rsa_keypair; + + char *key_str = zalloc(64); + snprintf(key_str, 64, "(genkey (rsa (nbits 4:%d)))", keysize); + err = gcry_sexp_build(&rsa_parms, NULL, key_str); + zfree(key_str); + if (err) { + printerr(err, "create rsa params"); + xerr("gcrypt: failed to create rsa params"); + } + + err = gcry_pk_genkey(&rsa_keypair, rsa_parms); + if (err) { + printerr(err, "create keypair"); + xerr("gcrypt: failed to create rsa key pair"); + } + memset(key_str, sizeof(key_str), '\0'); + + if(dump) + { + //gcry_sexp_dump(rsa_keypair); + //int ss = gcry_sexp_sprint(rsa_keypair, GCRYSEXP_FMT_ADVANCED, NULL, 0); + //char *ppp = (char*)malloc(ss+1); + //gcry_sexp_sprint(rsa_keypair, GCRYSEXP_FMT_ADVANCED, ppp, ss); + //printf("%s\n", ppp); + } + + printf("\n\nRSA key generation complete.\n\n"); + + /* Grab a key pair password and create an encryption context with it. */ + + int ret = 0; + if(thispass[0] == '\0' && !nocrypt) + { + printf("Please enter a password to lock your key pair.\n"); + printf("This password must be retained for later use. Do not loose this password.\n\n"); + if(weak) + printf("Warning! Weak option specified, recommended for testing only.\n"); + getpassx passx; + passx.prompt = "Enter keypair pass:"; + passx.prompt2 = "Confirm keypair pass:"; + passx.pass = thispass; + passx.maxlen = sizeof(thispass); + passx.minlen = 4; + passx.strength = 6; + passx.weak = weak; + passx.nodouble = FALSE; + + ret = getpass2(&passx); + } + if(ret < 0) + { + xerr("Error on entering pass, no keys are written.\n"); + } + //printf("pass '%s'\n", thispass); + + if(write_pubkey(&rsa_keypair, fname2) < 0) + xerr("Could not write pubic key"); + + // Ignore error (if any) + write_mod_exp(&rsa_keypair, fname3); + + gcry_cipher_hd_t aes_hd; + get_aes_ctx(&aes_hd, thispass, strlen(thispass)); + + /* Encrypt the RSA key pair. */ + size_t rsa_len = get_keypair_size(keysize); + zline2(__LINE__, __FILE__); + void* rsa_buf = zalloc(rsa_len); + if (!rsa_buf) { + xerr("malloc: could not allocate rsa buffer"); + } + + char *ttt = datestr(); + char *rrr = randstr(32); + + gcry_sexp_t glib_keys; + err = gcry_sexp_build(&glib_keys, NULL, + "(gcrypt-key (date %s) (key-id %s) ) %S", ttt, rrr, rsa_keypair); + //print_sexp(glib_keys); + zfree(ttt); zfree(rrr); + + //rsa_len = gcry_sexp_sprint(rsa_keypair, GCRYSEXP_FMT_CANON, rsa_buf, rsa_len); + rsa_len = gcry_sexp_sprint(glib_keys, GCRYSEXP_FMT_CANON, rsa_buf, rsa_len); + if(rsa_len == 0) + { + xerr("Cannot sprint keypair"); + } + //if(dump) + // dump_mem(rsa_buf, rsa_len); + + if(!nocrypt) + { + err = gcry_cipher_encrypt(aes_hd, (unsigned char*) rsa_buf, + rsa_len, NULL, 0); + if (err) { + xerr("gcrypt: could not encrypt with AES"); + } + } + + FILE* lockf = fopen(fname, "wb"); + if (!lockf) { + xerr("fopen() failed"); + } + ///* Write the encrypted base64 key pair to disk. */ + int limlen = rsa_len; + char *mem6 = base_and_lim(rsa_buf, rsa_len, &limlen); + + //if(dump) + // dump_mem(mem6, limlen); + + fprintf(lockf, "%s\n", comp_start); + fprintf(lockf, "%*s\n", limlen, mem6); + fprintf(lockf, "%s\n", comp_end); + + fclose(lockf); + zfree(mem6); + + /* Release contexts. */ + gcry_sexp_release(rsa_keypair); + gcry_sexp_release(rsa_parms); + gcry_cipher_close(aes_hd); + zfree(rsa_buf); + + printf("Key successfully saved.\n"); + + zfree(fname); + zfree(fname2); + zfree(fname3); + zleak(); + + return 0; +} + +// See if keysize has more than one bit set (if it is a power of two) + +int num_bits_set(unsigned int ks) +{ + int bits = 0; + //printf("bits of %d (0x%x)\n", ks, ks); + while(TRUE) + { + if(ks & 1) + bits++; + ks >>= 1; + if (ks == 0) + break; + } + //printf("ks bits %d\n", bits); + return bits; +} + + + + + + + + + + Index: examples/peterglen/keygen.cry =================================================================== --- /dev/null +++ examples/peterglen/keygen.cry @@ -0,0 +1,1899 @@ +-----BEGIN GCRYPT RSA CYPHER----- +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 +BpzEqf+8wm2uhHsHMCNiWMiSojIkraqADQQxaNgm70cnfsu0CuBY7qJeF8NioI+N +ASwKiwp7RX1h3gXA8wslpiYxHcypzfIiurCkutCFA8KNM7wNl0c8F8B+OxXg2Yhz +1xWv25SgsNexxdcN0RrM1f3CC/TnWdIjlb3BcvoiVzYEie6492JrujOw+Y1q17fc +/lPKt4D0q7kSSF0s9Y2cGkzFnVIK5Pjmyed6Zutzf7OCNzKsjV//p4GNqhJ/xWJd +7CyAYhANzTlo9CrgjgKZKmK/Og+jtGiGj7k461JCgMdoL3mQJN4XR+l9nojA8QkY +R7X8aonJDnjDdcAAVACGcFje79r3dMtr1ERWSTXAFWmlFJ0ihTY7Ju6NVDQpGuwT +M8aIneIHTlvvMy60r1zqoyUPPyQdKmXwWKXSn1/nKLmbsumHyQEQS1CO8IIXcR2k +s8y7d8S5amG0ISryctZvOceBbPVDp9G1hh1AjPPk++jUOSmccXQ71WC5WyIj3aOm +hdXqHp8B9gdBNPajjh9WvQypD2F/w2/1m04r8Z6yJy4vzwyINU8UuJ8PEQ6bhmwd +ySymOmZTE4StZL82fpjdPcsITOlD2fyjHFz8P1XHRECjFJKBnov0V96lE7FkneS2 +cAuHWiwkdIHqkg1mRWzmSJ2Ya41wsp2mdLiyMbq2fC4aX95ttwMGoy7225W3rxjs +YofOYHQ20dkdl2lqLiaZHp+ADBoKhbP8X7yeiBpxUEt2mJr6p8h3ZWizCAfYyNq0 +c2eUYcM+HaR7tTTlLh8sHB6SSiHJsIcgxbUBI+SMLVwVDpfawrJx03stL8u8056h +acilwO9cVk4mSvxC4ySxvJhD6hXsrfEOXnqbd/FvmCFE8NBs61pPG0D6BrY9iqyg ++cN0SngDQsmjESecAMENxPUSig+xvBtiX8HMvn9w9Exyqph8iqcz33unnEEL3hlr +oa7JcwDO1yk5F+FPVMAMiHP8oC0m+5Bkzukly23lp+tQXikK13JhOiQtd6Y2uwDA +KgjKBv31uxWhdXqU/iouCgkNf/whcCgRB4ewG+vj5uH69AMrlItf+TwaxQhYMmMD +6vpx0fTZjLi5mmpjXkFZMfvh4szwjVuf6DYSug5wo35aJSomuI69dWavQSk9Q7ID +Hcmh651goYdzkSVdSCErsvqwVIWsdIU2AcDLwOMTAJ2BN+tto84Mx2EpccfqH+d8 +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 +-----END GCRYPT RSA CYPHER----- Index: examples/peterglen/makeall =================================================================== --- /dev/null +++ examples/peterglen/makeall @@ -0,0 +1,3 @@ + + +gcc encrypt.c -I ../../libgpg-error-1.27/src -I../src -L ../src/.libs/ -L ../../libgpg-error-1.27/src/.libs -l gcrypt -l gpg-error -o encrypt Index: examples/peterglen/makeone =================================================================== --- /dev/null +++ examples/peterglen/makeone @@ -0,0 +1,3 @@ + + +gcc encrypt.c -I ../../libgpg-error-1.27/src -I../src -L ../src/.libs/ -L ../../libgpg-error-1.27/src/.libs -l gcrypt -l gpg-error -o encrypt Index: examples/peterglen/oh_god.txt =================================================================== --- /dev/null +++ examples/peterglen/oh_god.txt @@ -0,0 +1,50 @@ +Oh God +Please Shine Your Light Tonight +For The World Needs Your Love +More Then Ever + +Oh God +Please Shine Your Light Tonight +For The World Needs Your Love +More Then Ever Now + +Right NOW , Some How +I Know , That There’ll Come a Day +One Day , Some Day +When The World Will Know PEACE + +When There Will Be PEACE +There Will Be PEACE + + +We’re In A Time Of War +When All I Want Is Peace. +In This World Of Evolution +Breeds Money And Greed + +Power And Fame +It’s All The Same +We Play By My Rules +Or We Don’t Play The Game + +It’s A Holy War +Built On Wrong And Right +So Much Confusion +Why Do We All Fight ? + + +I Say Now When , +Will We Come Together ? +And When , +Will We Finally See ? + +When , +Will We Love One Another ? +And When , +Will This Fighting End ? + + +Oh God +Please Shine Your Light Tonight +For The World Needs Your Love +More Then Ever \ No newline at end of file Index: examples/peterglen/sample.dec =================================================================== --- /dev/null +++ examples/peterglen/sample.dec @@ -0,0 +1,7 @@ +Test + +This is a sample text to encrypt. It is a text file +with some characters in it. +123456 + + Index: examples/peterglen/sample.enc =================================================================== --- /dev/null +++ examples/peterglen/sample.enc @@ -0,0 +1,8 @@ +-----BEGIN GCRYPT RSA CYPHER----- +AQEAjtKkt9rxLrJZgjQhvy4Es2lchzlJTf+Xm1p7nVHFuGnMmjUN7ja/fEHBzTnT +yutetHI5ljvflHFZM48ragjzGJD+RpjBzrQLp6Mx6HN/rZOiI/g+9rlV6a7CGTYA +PQ5LDQP/8rxgXJQRoEvSH8I8u3T36fgc+lT9uFt74n/G2+dEyJUiDAMe2Zw1zd0x +iWUNZdnppCy7+5bvhhtovPkrHQ9wVirh3uX/B29ZJa6Z6EJtaR0wv0WlQ1eeRkKa +/HSmBLxR9zazqLxBnLXb84RnWkqNb9K+nWAqkeKq6R5XQiJleKGe/U9cQngRDf0o +qHqxzgnAsrKgbaEns5m+Ssiylg== +-----END GCRYPT RSA CYPHER----- Index: examples/peterglen/sample.txt =================================================================== --- /dev/null +++ examples/peterglen/sample.txt @@ -0,0 +1,7 @@ +Test + +This is a sample text to encrypt. It is a text file +with some characters in it. +123456 + + Index: examples/peterglen/test.txt =================================================================== --- /dev/null +++ examples/peterglen/test.txt @@ -0,0 +1 @@ +1234567890 Index: examples/peterglen/test_asym.c =================================================================== --- /dev/null +++ examples/peterglen/test_asym.c @@ -0,0 +1,267 @@ + +/* =====[ test_asym.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include + +#include "gcrypt.h" +#include "gcry.h" +#include "zmalloc.h" +#include "getpass.h" +#include "gsexp.h" + +static int dump = 0; +static int verbose = 0; +static int test = 0; +static int ppub = 0; +static int nocrypt = 0; + +static char infile[MAX_PATH] = {'\0'}; +static char outfile[MAX_PATH] = {'\0'}; +static char keyfile[MAX_PATH] = {'\0'}; +static char thispass[MAX_PATH] = {'\0'}; + +char usestr[] = "test_asym [options] keyfile"; + +opts opts_data[] = { + 'i', "infile", NULL, infile, 0, 0, NULL, + "-i --infile - input file name", + + 'o', "outfile", NULL, outfile, 0, 0, NULL, + "-o --outfile - output file name", + + 'p', "pass", NULL, thispass, 0, 0, NULL, + "-p --pass - pass in for key (testing only)", + + 'k', "keyfile", NULL, keyfile, 0, 0, NULL, + "-k --keyfile - key file name", + + 'v', "verbose", NULL, NULL, 0, 0, &verbose, + "-v --verbose - Verbosity on", + + 'd', "dump", NULL, NULL, 0, 0, &dump, + "-d --dump - Dump buffers", + + 't', "test", NULL, NULL, 0, 0, &test, + "-t --test - test on", + + 'n', "nocrypt", NULL, NULL, 0, 0, &nocrypt, + "-n --nocrypt - do not decypt private key", + + 'x', "printpub", NULL, NULL, 0, 0, &ppub, + "-x --printpub - print public key", + + 0, NULL, NULL, NULL, 0, 0, NULL, NULL, + }; + + +static void myfunc(int sig) +{ + printf("\nSignal %d (segment violation)\n", sig); + exit(111); +} + +int main(int argc, char** argv) +{ + signal(SIGSEGV, myfunc); + + char *err_str; + int nn = parse_commad_line(argv, opts_data, &err_str); + if (err_str) + { + printf(err_str); + usage(usestr, opts_data); exit(2); + } + + if (argc - nn != 2 && strlen(keyfile) == 0) { + printf("Missing argument for ascrypt."); + usage(usestr, opts_data); exit(2); + } + + //printf("thispass '%s'\n", thispass); + + //zverbose(TRUE); + //gcry_set_allocation_handler(zalloc, NULL, NULL, zrealloc, zfree); + + gcrypt_init(); + gcry_error_t err; + + char* fname = argv[1 + nn]; + + FILE* lockf = fopen(fname, "rb"); + if (!lockf) { + xerr2("fopen() on '%s' failed.", fname); + } + + /* Read and decrypt the key pair from disk. */ + unsigned int flen = getfsize(lockf); + zline2(__LINE__, __FILE__); + char* fbuf = zalloc(flen + 1); + if (!fbuf) { + xerr("malloc: could not allocate rsa buffer"); + } + if (fread(fbuf, flen, 1, lockf) != 1) { + xerr("fread() on composit key failed"); + } + fclose(lockf); + + //fbuf[flen] = '\0'; + zcheck(fbuf, __LINE__); + + if(dump) + dump_mem(fbuf, flen); + + zline2(__LINE__, __FILE__); + int rsa_len = flen; + char *rsa_buf = decode_priv_key(fbuf, &rsa_len, &err_str); + zfree(fbuf); + + if (!rsa_buf) { + //printf("%s\n", err_str); + xerr2("Decode key failed. %s", err_str); + } + //if(dump) + // dump_mem(rsa_buf, rsa_len); + + zline2(__LINE__, __FILE__); + /* Grab a key pair password and create an AES context with it. */ + if(thispass[0] == '\0' && !nocrypt) + { + getpassx passx; + passx.prompt = "Enter keypair pass:"; + passx.pass = thispass; + passx.maxlen = MAXPASSLEN; + passx.minlen = 3; + passx.weak = TRUE; + passx.nodouble = TRUE; + passx.strength = 4; + int ret = getpass2(&passx); + if(ret < 0) + xerr("Error on password entry."); + } + + //printf("thispass '%s'\n", thispass); + + gcry_cipher_hd_t aes_hd; + get_aes_ctx(&aes_hd, thispass, strlen(thispass)); + + zline2(__LINE__, __FILE__); + if(!nocrypt) + { + // Decrypt buffer + err = gcry_cipher_decrypt(aes_hd, (unsigned char*) rsa_buf, + rsa_len, NULL, 0); + if (err) { + xerr("gcrypt: failed to decrypt key pair"); + } + } + if(dump) + dump_mem(rsa_buf, rsa_len); + + zline2(__LINE__, __FILE__); + /* Load the key pair components into sexps. */ + gcry_sexp_t rsa_keypair; + err = gcry_sexp_new(&rsa_keypair, rsa_buf, rsa_len, 0); + if(err) + { + //printerr(err, NULL); + xerr2("gcrypt: failed to load key. (pass?)"); + } + + zline2(__LINE__, __FILE__); + gcry_sexp_t pubk = gcry_sexp_find_token(rsa_keypair, "public-key", 0); + if(pubk == NULL) + xerr2("gcrypt: no public key present"); + //print_sexp(pubk); + gcry_sexp_t privk = gcry_sexp_find_token(rsa_keypair, "private-key", 0); + if(privk == NULL) + xerr2("gcrypt: no private key present"); + //print_sexp(privk); + + zline2(__LINE__, __FILE__); + printf("Key length pub: %d priv: %d\n", + gcry_pk_get_nbits(pubk), gcry_pk_get_nbits(privk)); + + int cycle = gcry_pk_get_nbits(privk)/8; + + const unsigned char* ss = (const unsigned char*) + "Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." + //"Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." + "Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world."; + + printf("Original message -> %d bytes \n'%s'\n", strlen(ss), (char*) ss); + + zline2(__LINE__, __FILE__); + gcry_sexp_t ciph; + int ret = pk_encrypt_buffer(ss, strlen(ss), pubk, &ciph); + //print_sexp(ciph); + decode_sexp(ciph, "a"); + + zline2(__LINE__, __FILE__); + /* Decrypt the message. */ + gcry_sexp_t plain; + zline2(__LINE__, __FILE__); + err = gcry_pk_decrypt(&plain, ciph, privk); + if (err) { + xerr("gcrypt: decryption failed"); + } + + zline2(__LINE__, __FILE__); + /* Pretty-print the results. */ + gcry_mpi_t out_msg = gcry_sexp_nth_mpi(plain, 0, GCRYMPI_FMT_USG); + + zline2(__LINE__, __FILE__); + int written = 0; + unsigned char *buffm; + err = gcry_mpi_aprint(GCRYMPI_FMT_USG, &buffm, &written, out_msg); + + if (err) { + xerr("failed to stringify mpi"); + } + printf("Decrypted message -> (%d bytes)\n'%s'\n", strlen(buffm), (char*) buffm); + + if(strcmp(buffm, ss) == 0) + { + printf("Buffers compare OK\n"); + } + else + { + printf("Buffers DO NOT compare.\n"); + } + + /* Release contexts. */ + gcry_mpi_release(out_msg); + gcry_sexp_release(rsa_keypair); + gcry_sexp_release(pubk); + gcry_sexp_release(privk); + gcry_sexp_release(ciph); + gcry_sexp_release(plain); + gcry_cipher_close(aes_hd); + zline2(__LINE__, __FILE__); + zfree(rsa_buf); + zline2(__LINE__, __FILE__); + gcry_free(buffm); + + zleak(); + return 0; +} + + + + + + + + + + Index: examples/peterglen/test_base64.c =================================================================== --- /dev/null +++ examples/peterglen/test_base64.c @@ -0,0 +1,95 @@ + +/* =====[ test_base64.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + 0.00 aug.04.2017 Peter Glen Terminator added + + ======================================================================= */ + +#include +#include + +#include "zmalloc.h" +#include "base64.h" + +int main(int argc, char** argv) +{ + //printf("Testing base64.\n"); + //char str[] = "Here is a nul string.\0Null."; + //printf(" '%s' '%*s'\n", str, sizeof(str), str); + //return(0); + + const unsigned char* sss = (const unsigned char*) + "Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." + "Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." + "Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world."; + + //zverbose(1); + + int slen = strlen(sss); + printf("org: len=%d\n'%s'\n", slen, sss); + int outlen = base64_calc_encodelen(slen); + zline2(__LINE__, __FILE__); + char *mem = zalloc(outlen + 1); + //printf("base64 encode pre outlen=%d\n", outlen); + base64_encode(sss, slen, mem, &outlen); + mem[outlen] = '\0'; + printf("base64 encode outlen=%d\n'%s'\n", outlen, mem); + zcheck(mem, __LINE__); + + int linelen = 64; + int limlen = outlen + 4 + outlen / linelen ; + zline2(__LINE__, __FILE__); + char *mem3 = zalloc(limlen); + //memset(mem3, limlen, 'a'); + //printf("base64 limline pre limlen=%d\n", limlen); + base64_limline(mem, outlen, mem3, &limlen, linelen); + mem3[limlen] = '\0'; + printf("base64 limline limlen=%d\n'%s'\n", limlen, mem3); + + int ulimlen = limlen; + char *mem4 = zalloc(ulimlen); + int ret = base64_clean(mem3, limlen, mem4, &ulimlen); + mem4[ulimlen] = '\0'; + zcheck(mem4, __LINE__); + printf("base64 unexpand ulimlen=%d\n'%s'\n", ulimlen, mem4); + + int declen = base64_calc_decodelen(ulimlen); + zline2(__LINE__, __FILE__); + char *dmem = zalloc(declen + 1); + base64_decode(mem4, ulimlen, dmem, &declen); + dmem[declen] = '\0'; + printf("dec base64 len=%d\n'%s'\n", declen, dmem); + //dump_mem(dmem, strlen(dmem)); + zline2(__LINE__, __FILE__); + zcheck(dmem, __LINE__); + + if(strcmp(dmem, sss) != 0) + { + printf("\nData strings do not match!!!!\n"); + } + + zline2(__LINE__, __FILE__); + zfree(mem); + zfree(dmem); + zfree(mem3); + zfree(mem4); + + zleak(); +} + + + + + + + + + Index: examples/peterglen/test_base64.org =================================================================== --- /dev/null +++ examples/peterglen/test_base64.org @@ -0,0 +1,15 @@ +org: len=270 +'Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world.Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world.Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world.' +base64 encode outlen=360 +'SGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuSGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuSGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQu' +base64 limline limlen=365 +'SGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29y +bGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuSGVsbG8g +d29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuIEhl +bGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuSGVsbG8gd29ybGQu +IEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuIEhlbGxvIHdv +cmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQu' +base64 unexpand ulimlen=360 +'SGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuSGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuSGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQuIEhlbGxvIHdvcmxkLiBIZWxsbyB3b3JsZC4gSGVsbG8gd29ybGQu' +dec base64 len=270 +'Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world.Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world.Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world.' Index: examples/peterglen/test_base64a.c =================================================================== --- /dev/null +++ examples/peterglen/test_base64a.c @@ -0,0 +1,77 @@ + +/* =====[ test_base64.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + 0.00 aug.04.2017 Peter Glen Terminator added + + ======================================================================= */ + +#include +#include + +#include "zmalloc.h" +#include "base64.h" + +const unsigned char* str = (const unsigned char*) +//"Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." +//"Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." +//"Hello world. Hello world. Hello world. Hello world. Hello world. Hello world. Hello world." +"Hello 1 world"; + + +int main(int argc, char** argv) +{ + //printf("Testing base64.\n"); + // Test /0 printf + //char str2[] = "Here is a nul string.\0This is after nul."; + //printf(" '%s'\n'%.*s'\n", str2, sizeof(str2), str2); + //return(0); + + int slen = strlen(str); + printf("org: len=%d\n'%s'\n\n", slen, str); + int outlen = base64_calc_encodelen(slen); + zline2(__LINE__, __FILE__); + char *mem = zalloc(outlen + 1); + printf("base64 encode pre outlen=%d\n", outlen); + base64_encode(str, slen, mem, &outlen); + //mem[outlen] = '\0'; + printf("base64 encode outlen=%d\n'%s'\n", outlen, mem); + zcheck(mem, __LINE__); + + int dlen = outlen; + char *dmem = zalloc(dlen + 2); + printf("base64 decode pre dlen=%d\n", dlen); + base64_decode(mem, outlen, dmem, &dlen); + //dmem[dlen] = '\0'; + printf("base64 decode dlen=%d\n'%s'\n", dlen, dmem); + zcheck(dmem, __LINE__); + //dump_mem(dmem, outlen); + + if(dlen != slen) + { + printf("\nError! Decode length does not match\n"); + } + if (strcmp(str, dmem) != 0) + { + printf("\nError! Decode does not match\n"); + } + zfree(mem); zfree(dmem); + + zleak(); +} + + + + + + + + + Index: examples/peterglen/test_base64a.org =================================================================== --- /dev/null +++ examples/peterglen/test_base64a.org @@ -0,0 +1,9 @@ +org: len=13 +'Hello 1 world' + +base64 encode pre outlen=23 +base64 encode outlen=20 +'SGVsbG8gMSB3b3JsZA==' +base64 decode pre dlen=20 +base64 decode dlen=13 +'Hello 1 world' Index: examples/peterglen/test_zmalloc.c =================================================================== --- /dev/null +++ examples/peterglen/test_zmalloc.c @@ -0,0 +1,124 @@ + +/* =====[ test_base64.c ]========================================================= + + Description: Encryption excamples. Feasability study for diba + [Digital Bank]. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + + ======================================================================= */ + +#include +#include + +#include "zmalloc.h" +#include "base64.h" + +int main(int argc, char** argv) + +{ + printf("\nTesting zmalloc, silent OK\n"); + + zline2(__LINE__, __FILE__); + char *mem0 = zalloc(1000); + zcheck(mem0, __LINE__); + zline(__LINE__); + char *mem0a = zrealloc(mem0, 1200); + zcheck(mem0a, __LINE__); + zline(__LINE__); + zfree(mem0a); + + #if 0 + zverbose(1); + printf("\nTesting zmalloc, verbose OK\n"); + int outlen = 100; + zline2(__LINE__, __FILE__); + char *mem = zalloc(outlen); + zcheck(mem, __LINE__); + zline(__LINE__); + zfree(mem); + zverbose(0); + #endif + + printf("\nTesting zmalloc, damage past end\n"); + zline2(__LINE__, __FILE__); + int outlen2 = 200; + zline2(__LINE__, __FILE__); + char *mem2 = zalloc(outlen2); + mem2[outlen2] = 'z'; + zline2(__LINE__, __FILE__); + //zcheck(mem2, __LINE__); + zfree(mem2); + + printf("\nTesting zmalloc, damage before beginning\n"); + zline(__LINE__); + int outlen4 = 200; + zline2(__LINE__, __FILE__); + char *mem4 = zalloc(outlen4); + mem4[-1] = 'x'; + zline2(__LINE__, __FILE__); + //zcheck(mem4, __LINE__); + zfree(mem4); + + printf("\nTesing attempt to free memory not allocated\n"); + char *ptr2 = "test"; + zfree(ptr2); + + printf("\nTesting zmalloc, not freed\n"); + zline(__LINE__); + int outlen3 = 300; + zline2(__LINE__, __FILE__); + char *mem3 = zalloc(outlen3); + zline2(__LINE__, __FILE__); + + zleak(); + zfree(mem3); + + printf("\nTesting zmalloc, multiple alloc, some freed\n"); + char *memarr[10]; + int iter = sizeof(memarr) / sizeof(int); + zline2(__LINE__, __FILE__); + for(int loop = 0; loop < iter; loop++) + memarr[loop] = zalloc(20); + for(int loop = 0; loop < iter - 1; loop++) + zfree(memarr[loop]); + zleak(); + // Free it so further reports will not show it: + zfree(memarr[iter-1]); + + printf("\nTesting zmalloc, damage on length indicator\n"); + zline(__LINE__); + int outlen5 = 200; + zline2(__LINE__, __FILE__); + char *mem5 = zalloc(outlen5); + mem4[-5] = 'x'; + zline2(__LINE__, __FILE__); + //zcheck(mem5, __LINE__); + zfree(mem5); + + printf("\nTest corrupted memory\n"); + extern void *zarr[]; + zline2(__LINE__, __FILE__); + char *memc0 = zalloc(1000); + zarr[0] = (void*)100; + zcheck(memc0, __LINE__); + zline(__LINE__); + zfree(memc0); + zarr[0] = (void*)0; + + printf("\nFinal report: (should be blank)\n"); + zleak(); +} + + + + + + + + + Index: examples/peterglen/test_zmalloc.org =================================================================== --- /dev/null +++ examples/peterglen/test_zmalloc.org @@ -0,0 +1,26 @@ + +Testing zmalloc, silent OK +zmalloc: realloc at line 29 from (0x00000000) 1000 bytes to (0x00000000) 1200 bytes + +Testing zmalloc, damage past end +zmalloc: Memory check failed. (at end) Line: 53 Allocated at 50 (test_zmalloc.c) + +Testing zmalloc, damage before beginning +zmalloc: Memory check failed. (at beginning) Line: 63 Allocated at 60 (test_zmalloc.c) + +Tesing attempt to free memory not allocated +zmalloc: Trying to free unallocated memory at line 63 (0x00000000) + +Testing zmalloc, not freed +zmalloc: Memory leak on test_zmalloc.c at line 74 (0x00000000) + +Testing zmalloc, multiple alloc, some freed +zmalloc: Memory leak on test_zmalloc.c at line 84 (0x00000000) + +Testing zmalloc, damage on length indicator +zmalloc: Damaged length, item allocated at line 96 (test_zmalloc.c) 200 bytes. + +Test corrupted memory +zmalloc: possible dangling pointer write. + +Final report: (should be blank) Index: examples/peterglen/testkey.key =================================================================== --- /dev/null +++ examples/peterglen/testkey.key @@ -0,0 +1,31 @@ +-----BEGIN GCRYPT RSA COMPOSITE KEY----- +d9htOQ40v7y/V8krhXh/W9NLhBZVdcXXQ/r96g5DOsRjX02AcGwQgfVHdKwRN+VV +Cqf+EvocoKSiS0+Uz+dTy+kAdJB6rVU1Efzuwa6QidZdVd/UIbr0DFmthJHtYE3/ +h2PEleU1skx6QqvXJi1aPPvTXHuW5sMM2Lsqh55B7AMiY57dtLPfH1dSe98hw2km +7vjj27nESGtppF4VQouzu7JsseQyETtXK/RZy/fsSPyI1OglbgSMbSSJMUYW8teS +2sV4fiVyA46L5WcQpDbhj2bAcNyY1qllgOZUoRVHxT5P38rbtTfVPbjPUPcfl6aQ +/GzTA55FrG1afYCw2ESbC3pn/kiftWr+MX3Cwf0y2yR86anzzY3CaIgiSUT1rDf9 +HDXIgT7usoGssHwsjGWhfOs7L+AdxApo9iHdMrqXBVd2twYVWONgrxP/E/Sfe1M/ +mnFrGgmDzOKMg/1tqUPCLXbPesIWxAsAYO7kHGcM6OujfEoFmzPKY0pkPlOv3FQA +Xj/lRvxg3+DlFmYGk5ZoEYWd7xhD35yRDnUiYv3V02uKxdpPN/T7ovQ8XkrXwj2T +5pF8gQBY86NLCBelTejeM4qnnDuejBX/k5AdY3nDrgJfBcvQuFX4IYbDxsfsEQwq +jxz6kfO7BBNTnnriq4qw8NEwigCFcc5asAzGZt/vFEt9rmOFh7LWEwko9PmUVGbF +DHqFa5v/I0hrbCUDQb/TdLxQj2v9dbMbz0lcuUP56psjhxH0Azz1MWZuhoK3zoaZ +L0I3b3bueybBcwxO4vpSDF0hUpYCB1It8bMq2pNyCJAH0sCL99S2WPxaEScf7c38 +ZRS3dYvQek0d1Gk3m161+dlpgKAamJKGUWWFqeaJHW9ddIoWcLMSfEttK8a4c6e6 +BWOCnTb82F6iiOONBhw+u87OfcpH3i1fWJ6dEKFcqzpQ5hCAVm2HMSMGnUdBkag9 +pFTCHtj/zxYMPeKuURE1NNFRnvKWsaSEFIMB+YDcg8hALehloSFdH7biogRzoiVg +o9MkI6fzhOZPEFp/4gDlCHVgn6EphGSd6C9TSGbsAx5Qa/lTNhWmthTrCdg98j/A +R8lSd/Hiau7fLkZRO4qCzEPHXUyfYFZfJlEcweqWl6z7AcfKVjhqNnKSTec5IL0h +bg4i2QYcoEOtwpaP3cEmB/7X6s/RkC1wKXwwhgz08J0qyM0U7eMF9cGGaIw52D8Z +4Sx9/qF8nfzc/N7HU8gIo/LqwoYyuZAbuulff8aJ1KGk6cYUy/vk7pxY1v4eMUsr +jAccP9srjlPrNte6dLwGYFVYqiB7F7aPP1K01oLDjJEIz1SPZmK6ka/QOx+HhrJY +OAPR/8LgfISYXxESuxXRuk9iptmjPsWMHWkmx+zTPDj3NXhHLo4nvGlYDT6cU4Eb +c12MXKQPycDg8/TeRNjnBiul7NUTidBxrJEv+O2AkSFYxOaFM46tf9yP6pFtWgMQ +i6MZKUo/8dId/YTjVlQgc0Vkkk0VBF/LRlFApnnMGzI0o8TtVSGj5sayB5UWkCZS +HJBiD9szWf2c+u63E23Qdlrn+Wak4kX5C1J66lrr3bUqQ7eu7KbIr6zk5zOmKr+Q +WPiqqmMCcN3dmMx/2x4W66G9L3+ApnrPWhje7r+5eUsosBOxH/wuBust9g1Vxc+E +JAwOziT/YjnWEtKNv9KK6BnBlH5jWQHAThApSAf03MgvB2jkJ/HYku/uyE+Q/aP4 +aBht40wUv7mUvV8M28rkmy+PLyhUrK+FY6+kLfi8/4sQZ0isW3wCYwbN/WdG5e5v +NZerbZ3XkMH8RCi1vdtwWbnnsfTLZPKP3Dd5nzZ/MyxygRQEparp1bJcGSVH +-----END GCRYPT RSA COMPOSITE KEY----- Index: examples/peterglen/testkey.mod =================================================================== --- /dev/null +++ examples/peterglen/testkey.mod @@ -0,0 +1,11 @@ +-----BEGIN RSA PUBLIC MODULUS----- +ALMCF/QawW3hHCCgV0TUeP3wqycobvcog7KPYtIKGs1OWX3PH0zt+VP8vfSF6RMN +b64WIQntR5L4r7tpokI9VSGvRoyUBN/dMiA4kpr6T2jE4no1GB0pqi54xGegF84n +ZgtBrFYPDglikzoQnsLZglrJirgGHNgk0mqZNuG6ySLzM8FbMFVB3wP1US+2erSm +7kkGsJXuDLHtteNUm7vJInlLK9LLtaBZXCKXIJXM9DJuWBd24SIOl4M2aX0rl+je +557n0H0mQWyB0Akr7S2slQitbwCezx0G9VUiC6yD7Wk83pDED7o1XLnluIIz8hNJ +THzdS9+Msi49Csj/Sjvjp7E= +-----END RSA PUBLIC MODULUS----- +-----BEGIN RSA PUBLIC EXPONENT----- +AQAB +-----END RSA PUBLIC EXPONENT----- Index: examples/peterglen/testkey.pub =================================================================== --- /dev/null +++ examples/peterglen/testkey.pub @@ -0,0 +1,9 @@ +-----BEGIN GCRYPT RSA PUBLIC KEY----- +KDEwOnB1YmxpYy1rZXkoMzpyc2EoMTpuMjU3OgCzAhf0GsFt4RwgoFdE1Hj98Ksn +KG73KIOyj2LSChrNTll9zx9M7flT/L30hekTDW+uFiEJ7UeS+K+7aaJCPVUhr0aM +lATf3TIgOJKa+k9oxOJ6NRgdKaoueMRnoBfOJ2YLQaxWDw4JYpM6EJ7C2YJayYq4 +BhzYJNJqmTbhuski8zPBWzBVQd8D9VEvtnq0pu5JBrCV7gyx7bXjVJu7ySJ5SyvS +y7WgWVwilyCVzPQyblgXduEiDpeDNml9K5fo3uee59B9JkFsgdAJK+0trJUIrW8A +ns8dBvVVIgusg+1pPN6QxA+6NVy55biCM/ITSUx83UvfjLIuPQrI/0o746exKSgx +OmUzOgEAASkpKQA= +-----END GCRYPT RSA PUBLIC KEY----- Index: examples/peterglen/zmalloc.h =================================================================== --- /dev/null +++ examples/peterglen/zmalloc.h @@ -0,0 +1,39 @@ + +/* =====[ zmalloc.h ]========================================================= + + Description: Encryption examples. Feasability study for diba + [Digital Bank]. Testing libgcrypt library. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.23.2017 Peter Glen Initial version. + 0.00 jul.24.2017 Peter Glen Added + + ======================================================================= */ + +// Public entry points + +void *zalloc(unsigned int msize); +void *zrealloc(void *ptr, unsigned int msize); +void zfree(void *mem); + +// Informational + +void zline(int line); +void zline2(int line, const char *fname); +void zverbose(int flag); + +void zcheck(void *mem, int line); +void zfree2(void *mem, int line); + +int zleak(); + +// EOF + + + + + + Index: examples/peterglen/zmalloc.c =================================================================== --- /dev/null +++ examples/peterglen/zmalloc.c @@ -0,0 +1,340 @@ + +/* =====[ zmalloc.c ]========================================================= + + Description: Encryption examples. Feasability study for diba + [Digital Bank]. Testing libgcrypt library. + + Revisions: + + REV DATE BY DESCRIPTION + ---- ----------- ---------- ------------------------------ + 0.00 jul.14.2017 Peter Glen Initial version. + 0.00 jul.24.2017 Peter Glen More + 0.00 jul.28.2017 Peter Glen Test, SF release + + ======================================================================= */ + +#include +#include +#include + +#include "zmalloc.h" + +#define POOLSIZE 1024 + +// Cheater malloc. Decorate as follows: +// xxxx 'a' 'b' 'c' 'd' mmmmmmm 'e' 'f' 'g' 'h' +// xxxx is 4 bytes of length, mmmmmm is the requested memory + +// Expose this for testing memory corruption +void *zarr[POOLSIZE] = {NULL}; + +static const char *zfnamearr[POOLSIZE] = {NULL}; +static int zlinearr[POOLSIZE] = {-1}; +static int zlenarr[POOLSIZE] = {-1}; + +static int zlast = 0; +static int zlastline = 0; +static const char *zlastfile = NULL; +static int check_on = (1==1); +static int verbose_on = (1==0); +static int temp_sum = 0; + +static void die() +{ + printf("zmalloc: Cannot allocate memory, error exit\n"); + exit(2); +} + +static int calc_sum(const char *ptr, int len) + +{ + int ret = 0; + for(int loop = 0; loop < len; loop++) + ret += (unsigned char)ptr[loop]; + return ret; +} + + +static int calc_all_sums() + +{ + int ret = 0; + + ret += calc_sum((const char*)zarr, sizeof(zarr)); + ret += calc_sum((const char*)zfnamearr, sizeof(zfnamearr)); + ret += calc_sum((const char*)zlinearr, sizeof(zlinearr)); + ret += calc_sum((const char*)zlenarr, sizeof(zlenarr)); + + //printf("Sum %d\n", ret); + return ret; +} + +void zline2(int line, const char *fname) +{ + zlastline = line; + zlastfile = fname; +} + +void zline(int line) +{ + zlastline = line; +} + +void zverbose(int flag) +{ + verbose_on = flag; +} + +void zcheck(void *mem, int line) + +{ + if(!check_on) + return; + + char *mem2 = (char *)mem; + int *mem3 = (int *)mem; + char *mem4 = (char *)mem; + + mem2 -= 4; + mem3 = (int *)(mem2 - sizeof(int)); + mem4 += *mem3; + + //printf("%p %d '%c %c %c %c' '%c %c %c %c' \n", mem, *mem3, mem2[0], mem2[1], mem2[2], mem2[3], + // mem4[0], mem4[1], mem4[2], mem4[3] ); + + // See where it was allocated + const char *afname = NULL; int aline = 0; + for(int loop = 0; loop < zlast; loop++) + { + if(zarr[loop] == mem) + { + aline = zlinearr[loop]; + afname = zfnamearr[loop]; + } + } + + if(mem2[0] != 'a' || mem2[1] != 'b' || + mem2[2] != 'c' || mem2[3] != 'd') + { + printf("zmalloc: Memory check failed. (at beginning) Line: %d Allocated at %d (%s)\n", + line, aline, afname); + } + if(mem4[0] != 'e' || mem4[1] != 'f' || + mem4[2] != 'g' || mem4[3] != 'h') + { + printf("zmalloc: Memory check failed. (at end) Line: %d Allocated at %d (%s)\n", + line, aline, afname); + } +} + +// Use as usual realloc + +void *zrealloc(void *ptr, unsigned int msize) + +{ + if(ptr == NULL) + { + return zalloc(msize); + } + if(msize == 0) + { + zfree(ptr); + return NULL; + } + + char *mem = (char*)ptr; + int *mem3 = (int *)(mem - (sizeof(int) + 4)); + int xsize = *mem3; + + void *memnew = zalloc(msize); + if(msize < xsize) xsize = msize; // Scrinking + memcpy(memnew, ptr, xsize); + //if(verbose_on) + printf("zmalloc: realloc at line %d from (0x%p) %d bytes to (0x%p) %d bytes\n", + zlastline, ptr, xsize, memnew, msize); + zfree(ptr); + return memnew; +} + +// Use as usual malloc + +void *zalloc(unsigned int msize) + +{ + char *mem2 = NULL; int *mem3 = NULL; + void *mem = malloc (msize + 8 + sizeof(int)); + + if (mem == NULL) + return NULL; + //die(); + + if(zlinearr[0] == -1) + { + memset(zarr, 0, sizeof(zarr)); + memset(zlenarr, 0, sizeof(zlenarr)); + memset(zlinearr, 0, sizeof(zlinearr)); + memset(zfnamearr, 0, sizeof(zfnamearr)); + } + memset(mem, 0, msize); + + // Decorate + mem2 = (char*)mem; mem3 = (int*)mem; + *(mem3) = msize; + *(mem2 + 4) = 'a'; + *(mem2 + 5) = 'b'; + *(mem2 + 6) = 'c'; + *(mem2 + 7) = 'd'; + + *(mem2 + 4 + msize + sizeof(int) + 0) = 'e'; + *(mem2 + 4 + msize + sizeof(int) + 1) = 'f'; + *(mem2 + 4 + msize + sizeof(int) + 2) = 'g'; + *(mem2 + 4 + msize + sizeof(int) + 3) = 'h'; + + //printf("%c %c %c %c \n", mem2[4], mem2[5], + // *(mem2 + msize + sizeof(int)), *(mem2 + msize + sizeof(int)+1) ); + + void *ret = (void *) (mem2 + 4 + sizeof(int)); + zcheck(ret, zlastline ); + + if(verbose_on) + printf("zmalloc: Alloc at line %d (0x%p) %d bytes\n", zlastline, ret, msize); + if(zlast < POOLSIZE) + { + zarr[zlast] = ret; + zlinearr[zlast] = zlastline; + zlenarr[zlast] = msize; + zfnamearr[zlast] = zlastfile; + zlast++; + } + else + { + // Find deleted slot + int loop; + for(loop = 0; loop < zlast; loop++) + { + //printf("Finding slot\n"); + if(zarr[loop] == (void*)0) + { + zarr[loop] = ret; + zlinearr[loop] = zlastline; + zlenarr[loop] = msize; + zfnamearr[loop] = zlastfile; + break; + } + } + if(loop == zlast) + printf("zmalloc: Increase zlast memory pool\n"); + } + + temp_sum = calc_all_sums(); + + return ret; +} + +void zfree(void *mem) + +{ + zfree2(mem, zlastline); +} + +void zfree2(void *mem, int line) + +{ + int *mem3 = (int *)(mem - (sizeof(int) + 4)); + int msize = *mem3; + + if(verbose_on) + printf("zmalloc: Free at line %d (0x%p) %d bytes\n", line, mem, msize); + + // See if our memory was tempered with + if(temp_sum != calc_all_sums()) + printf("zmalloc: possible dangling pointer write.\n"); + + // See where it was allocated + const char *afname = NULL; int aline = -1, xlen = 0; + for(int loop = 0; loop < zlast; loop++) + { + if(zarr[loop] == mem) + { + aline = zlinearr[loop]; + afname = zfnamearr[loop]; + xlen = zlenarr[loop]; + } + } + + // This actually prevents a program from blowing up with illegal + // MEMORY access (buserror) + if(aline == -1) + { + printf("zmalloc: Trying to free unallocated memory at line %d (0x%p)\n", + zlastline, mem); + return; + } + + // Check if length is damaged + if(xlen != msize) + { + if(verbose_on) + printf("zmalloc: Damaged lenght indicator at line %d (0x%p) %d bytes.\n", + zlastline, mem, msize); + + printf("zmalloc: Damaged length, item allocated at line %d (%s) %d bytes.\n", + aline, afname, xlen); + //return; + // Attempt to free smaller memory + if(xlen < msize) + { + *mem3 = xlen; msize = xlen; + } + else + { + // Do not do anything else, serious corrupton suspected + return; + } + } + zcheck(mem, line); + + // Erase it from history + for(int loop = 0; loop < zlast; loop++) + { + if(zarr[loop] == mem) + { + zarr[loop] = NULL; + zfnamearr[loop] = NULL; + zlinearr[loop] = 0; + zlenarr[loop] = 0; + } + } + + // Reset memory before freeing, may apply cryptographic function + memset(mem, '\0', msize); + + char *mem2 = (char *)mem; + mem2 -= 4 + sizeof(int); + + temp_sum = calc_all_sums(); + + free( (void *)mem2 ); +} + +////////////////////////////////////////////////////////////////////////// +// Report leaks. Return how many. + +int zleak() + +{ + int ret = 0; + for(int loop = 0; loop < zlast; loop++) + if(zarr[loop] != NULL) + { + printf("zmalloc: Memory leak on %s at line %d (0x%p)\n", + zfnamearr[loop], zlinearr[loop], zarr[loop]); + ret++; + } + return ret; +} + +// EOF + +