From bf5556e1ecc3834f62be31be8de3f41bd6e709b5 Mon Sep 17 00:00:00 2001 From: TLINDEN Date: Sat, 2 Nov 2013 11:02:36 +0100 Subject: [PATCH] bugfix in encryption key computing, added new feature: derived public keys --- ChangeLog | 20 +++++++++- Makefile.am | 2 +- Makefile.in | 2 +- TODO | 2 + include/pcp.h | 36 +++++++++--------- libpcp/defines.h | 3 ++ libpcp/fatal.c | 4 ++ libpcp/key.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ libpcp/key.h | 17 +++++++++ libpcp/mac.c | 43 --------------------- libpcp/mac.h | 19 +--------- libpcp/version.h | 4 +- man/pcp1.1 | 4 +- man/pcp1.pod | 2 + src/encryption.c | 73 +++++++++++++++++++++++++++--------- src/encryption.h | 2 +- src/keymgmt.c | 57 +++++++++++++++++++++++----- src/keymgmt.h | 3 +- src/pcp.c | 31 +++++++++------ src/usage.h | 2 + src/usage.txt | 2 + tests/Makefile.am | 10 ++++- tests/Makefile.in | 20 ++++++++-- tests/key-alicia-pub | 48 ++++++++++++------------ tests/key-alicia-sec | 34 ++++++++--------- tests/key-bobby-pub | 52 +++++++++++++------------- tests/key-bobby-sec | 34 ++++++++--------- tests/unittests.cfg | 80 +++++++++++++++++++++++++++++++++------ tests/unittests.pl | 61 ++++++++++++++++++++++-------- 29 files changed, 514 insertions(+), 242 deletions(-) diff --git a/ChangeLog b/ChangeLog index fae3e4b..a3fe0ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,20 @@ -0.1.1 changed output format of encrypted keys. now we +0.1.2 Fixed bug in pcp_derivekey() which derives encryption + keys. it generated collisions due coding error, e.g. + passphase 'a' resulted in the same encryptionkey as + passphase 'r'. Now uses SHA256 witout the xor stuff, + which was the cause for the bug. This also fixes a + segmentation fault which occured invariably by entering + an invalid passphrase. + + Added support for derived public keys using the -R + option, which allows two peers to encrypt messages + without the need to reveal their primary public keys. + That way each peer will have another public key of + the same source. + + Added more unit tests to reflect the above changes. + +0.1.1 Changed output format of encrypted keys. now we encode it properly with the Z85 encoding and add a header and footer to it: @@ -8,4 +24,4 @@ EU]wBzf{UrCgBNSHcGBT -----END CURVE25519 SECRET KEY----- -0.0.1 initial version +0.0.1 Initial version diff --git a/Makefile.am b/Makefile.am index e0f2c95..ad57b01 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@ SUBDIRS = libpcp src man tests ACLOCAL_AMFLAGS = -I config test: - cd tests && make test + cd tests && make test $(CHECK) stresstest: cd tests && make stresstest diff --git a/Makefile.in b/Makefile.in index b2e6ddb..8c514c1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -745,7 +745,7 @@ uninstall-am: test: - cd tests && make test + cd tests && make test $(CHECK) stresstest: cd tests && make stresstest diff --git a/TODO b/TODO index f3d69a8..f9668e6 100644 --- a/TODO +++ b/TODO @@ -1 +1,3 @@ - always save vault to tmp, then validate it and copy if ok + + diff --git a/include/pcp.h b/include/pcp.h index e695e88..fd3c616 100644 --- a/include/pcp.h +++ b/include/pcp.h @@ -170,6 +170,23 @@ unsigned char * pcp_gennonce(); void pcpedit_key(char *keyid); +// proprietary key derivation function. derives an +// secure encryption key from the given passphrase by +// calculating a SALSA20 hash from it HCYCLES times. +// +// turns the result into a proper CURVE25519 secret +// key. allocates memory for key and it is up to the +// user to free it after use. +// +// deprecation warning: maybe removed once the libsodium +// developers incorporated some key derivation function +// into libsodium. so far, there's none but word goes +// that perhaps something like scrypt() from the star +// distribution may be added in the future. +unsigned char *pcp_derivekey(char *passphrase); + +pcp_key_t *pcp_derive_pcpkey (pcp_key_t *ours, char *theirs); + #ifdef __cplusplus } #endif @@ -218,25 +235,8 @@ int pcp_sodium_verify_mac(unsigned char **cleartext, unsigned char *nonce, unsigned char *key); -// generate a nonce from random source arc4random(). -// allocates memory for the returned nonce and -// it is up to the user to free it after use. -void pcp_makenonce(unsigned char **nonce); -// proprietary key derivation function. derives an -// secure encryption key from the given passphrase by -// calculating a SALSA20 hash from it HCYCLES times. -// -// turns the result into a proper CURVE25519 secret -// key. allocates memory for key and it is up to the -// user to free it after use. -// -// deprecation warning: maybe removed once the libsodium -// developers incorporated some key derivation function -// into libsodium. so far, there's none but word goes -// that perhaps something like scrypt() from the star -// distribution may be added in the future. -unsigned char *pcp_derivekey(char *passphrase); + // +++ from libpcp/mem.h: +++ diff --git a/libpcp/defines.h b/libpcp/defines.h index 64d207c..728443c 100644 --- a/libpcp/defines.h +++ b/libpcp/defines.h @@ -47,4 +47,7 @@ void fatal(const char * fmt, ...); // fetch error void fatals_ifany(); +// reset +void fatals_reset(); + #endif // _DEFINES_H diff --git a/libpcp/fatal.c b/libpcp/fatal.c index 963cf77..cf0f285 100644 --- a/libpcp/fatal.c +++ b/libpcp/fatal.c @@ -17,6 +17,10 @@ void fatal(const char * fmt, ...) { PCP_ERRSET = 1; } +void fatals_reset() { + PCP_ERRSET = 0; +} + void fatals_ifany() { if(PCP_ERRSET == 1) { fprintf(stderr, PCP_ERR); diff --git a/libpcp/key.c b/libpcp/key.c index d090ec1..e3f9b60 100644 --- a/libpcp/key.c +++ b/libpcp/key.c @@ -1,5 +1,40 @@ #include "key.h" + +unsigned char *pcp_derivekey(char *passphrase) { + unsigned char *hash32 = ucmalloc(crypto_hash_sha256_BYTES); + unsigned char *key = ucmalloc(crypto_secretbox_KEYBYTES); + + size_t plen = strnlen(passphrase, 255); + unsigned char *temp = ucmalloc(crypto_hash_sha256_BYTES); + int i; + + // make a hash from the passphrase and then HCYCLES times from the result + crypto_hash_sha256(temp, passphrase, plen); + + for(i=0; ipublic, 32, JEN_PSALT); @@ -196,4 +231,58 @@ pcp_pubkey_t *pubkey2native(pcp_pubkey_t *k) { return k; } +pcp_key_t *pcp_derive_pcpkey (pcp_key_t *ours, char *theirs) { + size_t thlen = strnlen(theirs, 255); + size_t inlen = 32 + thlen; + unsigned char *both = ucmalloc(inlen); + unsigned char *hash = ucmalloc(crypto_hash_BYTES); + memcpy(both, ours->secret, 32); + memcpy(&both[32], theirs, thlen); + + if(crypto_hash(hash, both, inlen) != 0) { + fatal("Failed to generate a hash of our pub key and recipient id!\n"); + goto errdp1; + } + + unsigned char *xor = ucmalloc(crypto_secretbox_KEYBYTES); + unsigned char *secret = ucmalloc(crypto_secretbox_KEYBYTES); + int i; + + for(i=0; isecret, secret, 32); + + // calculate pub from secret + crypto_scalarmult_curve25519_base(tmp->public, tmp->secret); + + memcpy(tmp->owner, ours->owner, 255); + memcpy(tmp->mail, ours->mail, 255); + memcpy(tmp->id, pcp_getkeyid(tmp), 17); + + memset(both, 0, inlen); + memset(xor, 0, crypto_secretbox_KEYBYTES); + memset(hash, 0, crypto_hash_BYTES); + + free(both); + free(xor); + free(hash); + + return tmp; + + errdp1: + memset(both, 0, inlen); + free(both); + + return NULL; +} diff --git a/libpcp/key.h b/libpcp/key.h index c6fe146..3ffbb71 100644 --- a/libpcp/key.h +++ b/libpcp/key.h @@ -113,6 +113,23 @@ unsigned char * pcp_gennonce(); void pcpedit_key(char *keyid); +// proprietary key derivation function. derives an +// secure encryption key from the given passphrase by +// calculating a SALSA20 hash from it HCYCLES times. +// +// turns the result into a proper CURVE25519 secret +// key. allocates memory for key and it is up to the +// user to free it after use. +// +// deprecation warning: maybe removed once the libsodium +// developers incorporated some key derivation function +// into libsodium. so far, there's none but word goes +// that perhaps something like scrypt() from the star +// distribution may be added in the future. +unsigned char *pcp_derivekey(char *passphrase); + +pcp_key_t *pcp_derive_pcpkey (pcp_key_t *ours, char *theirs); + #ifdef __cplusplus } #endif diff --git a/libpcp/mac.c b/libpcp/mac.c index 6cc4067..d935d40 100644 --- a/libpcp/mac.c +++ b/libpcp/mac.c @@ -2,49 +2,6 @@ - - -unsigned char *pcp_derivekey(char *passphrase) { - unsigned char *hash64 = ucmalloc(crypto_hash_BYTES); - unsigned char *xor = ucmalloc(crypto_secretbox_KEYBYTES); - unsigned char *key = ucmalloc(crypto_secretbox_KEYBYTES); - - size_t plen = strnlen(passphrase, 255); - unsigned char *temp = ucmalloc(crypto_hash_BYTES); - int i; - - // make a hash from the passphrase and then HCYCLES times from the result - memcpy(temp, passphrase, plen); - for(i=0; i Input file. If not specified, stdin \& will be used. \& \-i \-\-keyid Specify a key id to import/export. +\& \-R \-\-recipient Specify a recpipient, used for public +\& key export and encryption. \& \-t \-\-text Print textual representation of some \& item. Either \-V or \-i must be specified \& as well. diff --git a/man/pcp1.pod b/man/pcp1.pod index 6d1124c..4c34702 100644 --- a/man/pcp1.pod +++ b/man/pcp1.pod @@ -16,6 +16,8 @@ Pretty Curved Privacy - File encryption using eliptic curve cryptography. -I --infile Input file. If not specified, stdin will be used. -i --keyid Specify a key id to import/export. + -R --recipient Specify a recpipient, used for public + key export and encryption. -t --text Print textual representation of some item. Either -V or -i must be specified as well. diff --git a/src/encryption.c b/src/encryption.c index 3bdc54c..7f7da21 100644 --- a/src/encryption.c +++ b/src/encryption.c @@ -67,14 +67,22 @@ int pcpdecrypt(char *id, int useid, char *infile, char *outfile, char *passwd) { if(combined == NULL) goto errde1; - char *senderid = ucmalloc(17); - memcpy(senderid, combined, 16); - senderid[16] = '\0'; + unsigned char *hash = ucmalloc(crypto_hash_BYTES); + unsigned char *check = ucmalloc(crypto_hash_BYTES); + memcpy(hash, combined, crypto_hash_BYTES); - HASH_FIND_STR(pcppubkey_hash, senderid, public); + for(public=pcppubkey_hash; + public != NULL; + public=(pcp_pubkey_t*)(public->hh.next)) { + crypto_hash(check, (unsigned char*)public->id, 16); + if(memcmp(check, hash, crypto_hash_BYTES) == 0) { + // found one + break; + } + } if(public == NULL) { - fatal("Could not find a public key with id 0x%s in vault %s!\n", - senderid, vault->filename); + fatal("Could not find a usable public key in vault %s!\n", + vault->filename); goto errde0; } @@ -85,29 +93,52 @@ int pcpdecrypt(char *id, int useid, char *infile, char *outfile, char *passwd) { pcppubkey_printshortinfo(public); } - unsigned char *encrypted = ucmalloc(clen - 16); - memcpy(encrypted, &combined[16], clen - 16); + unsigned char *encrypted = ucmalloc(clen - crypto_hash_BYTES); + memcpy(encrypted, &combined[crypto_hash_BYTES], clen - crypto_hash_BYTES); size_t dlen; unsigned char *decrypted = pcp_box_decrypt(secret, public, - encrypted, clen - 16, &dlen); + encrypted, + clen - crypto_hash_BYTES, &dlen); + + if(decrypted == NULL) { + // try it with a derived secret from the sender id + pcp_key_t *s = pcp_derive_pcpkey(secret, public->id); + decrypted = pcp_box_decrypt(s, public, + encrypted, + clen - crypto_hash_BYTES, &dlen); + if(decrypted == NULL) { + // now try the senders key mail address + s = pcp_derive_pcpkey(secret, public->mail); + decrypted = pcp_box_decrypt(s, public, + encrypted, + clen - crypto_hash_BYTES, &dlen); + if(decrypted == NULL) { + // try the name + s = pcp_derive_pcpkey(secret, public->owner); + decrypted = pcp_box_decrypt(s, public, + encrypted, + clen - crypto_hash_BYTES, &dlen); + } + } + } if(decrypted != NULL) { + fatals_reset(); fwrite(decrypted, dlen, 1, out); fclose(out); if(ferror(out) != 0) { fatal("Failed to write decrypted output!\n"); } free(decrypted); - } - fprintf(stderr, "Decrypted %d bytes from 0x%s successfully\n", - (int)dlen, senderid); + fprintf(stderr, "Decrypted %d bytes from 0x%s successfully\n", + (int)dlen, public->id); + } free(encrypted); errde0: - free(senderid); free(combined); errde1: @@ -121,7 +152,7 @@ int pcpdecrypt(char *id, int useid, char *infile, char *outfile, char *passwd) { -int pcpencrypt(char *id, char *infile, char *outfile, char *passwd) { +int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, char *recipient) { FILE *in = NULL; FILE *out = NULL; pcp_pubkey_t *public = NULL; @@ -175,6 +206,12 @@ int pcpencrypt(char *id, char *infile, char *outfile, char *passwd) { goto erren2; } + if(recipient != NULL) { + pcp_key_t *derived = pcp_derive_pcpkey(secret, recipient); + memcpy(secret, derived, sizeof(pcp_key_t)); + free(derived); + } + if(debug) { fprintf(stderr, "Using secret key:\n"); pcpkey_printshortinfo(secret); @@ -208,10 +245,12 @@ int pcpencrypt(char *id, char *infile, char *outfile, char *passwd) { goto erren1; size_t zlen; - size_t clen = ciphersize + 16; + size_t clen = ciphersize + crypto_hash_BYTES; unsigned char *combined = ucmalloc(clen); - memcpy(combined, secret->id, 16); - memcpy(&combined[16], cipher, clen - 16); + unsigned char *hash = ucmalloc(crypto_hash_BYTES); + crypto_hash(hash, (unsigned char*)secret->id, 16); + memcpy(combined, hash, crypto_hash_BYTES); + memcpy(&combined[crypto_hash_BYTES], cipher, clen - crypto_hash_BYTES); // combined consists of: // keyid|nonce|cipher diff --git a/src/encryption.h b/src/encryption.h index 828dcee..6c00c42 100644 --- a/src/encryption.h +++ b/src/encryption.h @@ -13,6 +13,6 @@ #include "keyprint.h" int pcpdecrypt(char *id, int useid, char *infile, char *outfile, char *passwd); -int pcpencrypt(char *id, char *infile, char *outfile, char *passwd); +int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, char *recipient); #endif // _HAVE_ENCRYPTION_H diff --git a/src/keymgmt.c b/src/keymgmt.c index 4fdc365..7e0f54e 100644 --- a/src/keymgmt.c +++ b/src/keymgmt.c @@ -1,14 +1,13 @@ #include "keymgmt.h" - char *pcp_getstdin(const char *prompt) { - char line[1024]; + char line[255]; char *out; fprintf(stderr, "%s: ", prompt); - if (fgets(line, 1024, stdin) == NULL) { + if (fgets(line, 255, stdin) == NULL) { fatal("Cannot read from stdin"); goto errgst; } @@ -26,7 +25,6 @@ char *pcp_getstdin(const char *prompt) { return NULL; } - int pcp_storekey (pcp_key_t *key) { if(vault->isnew == 1 || HASH_COUNT(pcpkey_hash) == 0) { key->type = PCP_KEY_TYPE_MAINSECRET; @@ -207,10 +205,46 @@ void pcp_exportsecret(char *keyid, int useid, char *outfile) { } -void pcp_exportpublic(char *keyid, int useid, char *outfile) { - pcp_pubkey_t *key = NULL; +pcp_key_t *pcp_getrsk(pcp_key_t *s, char *recipient, char *passwd) { + if(recipient != NULL) { + if(s->secret[0] == 0) { + // encrypted, decrypt it + char *passphrase; + if(passwd == NULL) { + pcp_readpass(&passphrase, + "Enter passphrase to decrypt your secret key", NULL, 1); + } + else { + passphrase = ucmalloc(strlen(passwd)+1); + strncpy(passphrase, passwd, strlen(passwd)+1); + } + s = pcpkey_decrypt(s, passphrase); + if(s == NULL) + goto errrsk1; + } + pcp_key_t *tmp; + tmp = pcp_derive_pcpkey(s, recipient); + return tmp; + } - if(useid == 1) { + return s; + + errrsk1: + return NULL; +} + +/* + if id given, look if it is already a public and export this, + else we look for a secret key with that id. without a given + keyid we use the primary key. if we start with a secret key + and a recipient have been given, we use a derived secret key + and export the public component from that. without recipient + just export the public component of the found secret key. + */ +void pcp_exportpublic(char *keyid, char *recipient, char *passwd, char *outfile) { + pcp_pubkey_t *key = NULL; + + if(keyid != NULL) { // look if we've got that one HASH_FIND_STR(pcppubkey_hash, keyid, key); if(key == NULL) { @@ -222,7 +256,9 @@ void pcp_exportpublic(char *keyid, int useid, char *outfile) { free(s); } else { - key = pcpkey_pub_from_secret(s); + s = pcp_getrsk(s, recipient, passwd); + if(s != NULL) + key = pcpkey_pub_from_secret(s); } } } @@ -235,7 +271,10 @@ void pcp_exportpublic(char *keyid, int useid, char *outfile) { free(s); } else { - key = pcpkey_pub_from_secret(s); + pcp_key_t *t = NULL; + t = pcp_getrsk(s, recipient, passwd); + if(t != NULL) + key = pcpkey_pub_from_secret(t); } } diff --git a/src/keymgmt.h b/src/keymgmt.h index 132a9c5..85ce3b5 100644 --- a/src/keymgmt.h +++ b/src/keymgmt.h @@ -22,7 +22,8 @@ int pcp_storekey (pcp_key_t *key); void pcp_keygen(); void pcp_listkeys(); void pcp_exportsecret(char *keyid, int useid, char *outfile); -void pcp_exportpublic(char *keyid, int useid, char *outfile); +pcp_key_t *pcp_getrsk(pcp_key_t *s, char *recipient, char *passwd); +void pcp_exportpublic(char *keyid, char *recipient, char *passwd, char *outfile); char *pcp_normalize_id(char *keyid); pcp_key_t *pcp_find_primary_secret(); int pcp_importpublic (vault_t *vault, FILE *in); diff --git a/src/pcp.c b/src/pcp.c index e55d324..cec9c1e 100644 --- a/src/pcp.c +++ b/src/pcp.c @@ -22,13 +22,14 @@ char *default_vault() { } int main (int argc, char **argv) { - int opt, mode, usevault, useid; + int opt, mode, usevault, useid, userec; char *vaultfile = default_vault(); char *outfile = NULL; char *infile = NULL; char *keyid = NULL; char *id = NULL; char *xpass = NULL; + char *recipient = NULL; FILE *in; PCP_EXIT = 0; @@ -37,6 +38,7 @@ int main (int argc, char **argv) { mode = 0; usevault = 0; useid = 0; + userec = 0; static struct option longopts[] = { // generics @@ -46,6 +48,7 @@ int main (int argc, char **argv) { { "keyid", required_argument, NULL, 'i' }, { "text", required_argument, NULL, 't' }, { "xpass", required_argument, NULL, 'x' }, + { "recipient", required_argument, NULL, 'R' }, // key management { "keygen", no_argument, NULL, 'k' }, @@ -72,7 +75,7 @@ int main (int argc, char **argv) { { NULL, 0, NULL, 0 } }; - while ((opt = getopt_long(argc, argv, "klV:vdehsO:i:I:pSPrtEx:DzZ", + while ((opt = getopt_long(argc, argv, "klV:vdehsO:i:I:pSPrtEx:DzZR:", longopts, NULL)) != -1) { switch (opt) { @@ -150,7 +153,11 @@ int main (int argc, char **argv) { xpass = ucmalloc(strlen(optarg)+1); strncpy(xpass, optarg, strlen(optarg)+1); break; - + case 'R': + recipient = ucmalloc(strlen(optarg)+1); + strncpy(recipient, optarg, strlen(optarg)+1); + userec = 1; + break; case 'D': debug = 1; @@ -204,14 +211,14 @@ int main (int argc, char **argv) { case PCP_MODE_EXPORT_PUBLIC: if(useid) { id = pcp_normalize_id(keyid); - if(id != NULL) { - pcp_exportpublic(id, useid, outfile); - free(id); - } - } - else { - pcp_exportpublic(NULL, useid, outfile); + if(id == NULL) + break; } + pcp_exportpublic(id, recipient, xpass, outfile); + if(xpass != NULL) + free(xpass); + if(recipient != NULL) + free(recipient); break; case PCP_MODE_IMPORT_PUBLIC: @@ -283,10 +290,12 @@ int main (int argc, char **argv) { if(useid) { id = pcp_normalize_id(keyid); if(id != NULL) { - pcpencrypt(id, infile, outfile, xpass); + pcpencrypt(id, infile, outfile, xpass, recipient); free(id); if(xpass != NULL) free(xpass); + if(recipient != NULL) + free(recipient); } } else { diff --git a/src/usage.h b/src/usage.h index 7f14262..31f1f8b 100644 --- a/src/usage.h +++ b/src/usage.h @@ -11,6 +11,8 @@ "-I --infile Input file. If not specified, stdin\n" \ " will be used.\n" \ "-i --keyid Specify a key id to import/export.\n" \ +"-R --recipient Specify a recpipient, used for public\n" \ +" key export and encryption.\n" \ "-t --text Print textual representation of some\n" \ " item. Either -V or -i must be specified\n" \ " as well.\n" \ diff --git a/src/usage.txt b/src/usage.txt index 48eef04..3193f3f 100644 --- a/src/usage.txt +++ b/src/usage.txt @@ -9,6 +9,8 @@ General Options: -I --infile Input file. If not specified, stdin will be used. -i --keyid Specify a key id to import/export. +-R --recipient Specify a recpipient, used for public + key export and encryption. -t --text Print textual representation of some item. Either -V or -i must be specified as well. diff --git a/tests/Makefile.am b/tests/Makefile.am index 4150e47..08084c7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,17 +1,23 @@ AM_CFLAGS = -I../libpcp -Wall -g -check_PROGRAMS = col invalidkeys +check_PROGRAMS = col invalidkeys pwhashes col_LDADD = ../libpcp/.libs/libpcp1.a col_SOURCES = collisions.c invalidkeys_LDADD = ../libpcp/.libs/libpcp1.a ../src/keyprint.o invalidkeys_SOURCES = invalidkeys.c + +pwhashes_LDADD = ../libpcp/.libs/libpcp1.a +pwhashes_SOURCES = pwhashes.c + AM_CPPFLAGS = -I$(top_builddir)/src test: check - ./unittests.pl unittests.cfg + rm -f test* v* stresstest/* + ./unittests.pl unittests.cfg $(CHECK) + @echo "To run a single test only, type: 'make test CHECK=testname'" stresstest: check ./unittests.pl stresstests.cfg diff --git a/tests/Makefile.in b/tests/Makefile.in index 50c7b49..a2e6caf 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -49,7 +49,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -check_PROGRAMS = col$(EXEEXT) invalidkeys$(EXEEXT) +check_PROGRAMS = col$(EXEEXT) invalidkeys$(EXEEXT) pwhashes$(EXEEXT) subdir = tests DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(top_srcdir)/config/depcomp @@ -71,6 +71,9 @@ col_DEPENDENCIES = ../libpcp/.libs/libpcp1.a am_invalidkeys_OBJECTS = invalidkeys.$(OBJEXT) invalidkeys_OBJECTS = $(am_invalidkeys_OBJECTS) invalidkeys_DEPENDENCIES = ../libpcp/.libs/libpcp1.a ../src/keyprint.o +am_pwhashes_OBJECTS = pwhashes.$(OBJEXT) +pwhashes_OBJECTS = $(am_pwhashes_OBJECTS) +pwhashes_DEPENDENCIES = ../libpcp/.libs/libpcp1.a DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/libpcp depcomp = $(SHELL) $(top_srcdir)/config/depcomp am__depfiles_maybe = depfiles @@ -84,8 +87,9 @@ CCLD = $(CC) LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ $(LDFLAGS) -o $@ -SOURCES = $(col_SOURCES) $(invalidkeys_SOURCES) -DIST_SOURCES = $(col_SOURCES) $(invalidkeys_SOURCES) +SOURCES = $(col_SOURCES) $(invalidkeys_SOURCES) $(pwhashes_SOURCES) +DIST_SOURCES = $(col_SOURCES) $(invalidkeys_SOURCES) \ + $(pwhashes_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -212,6 +216,8 @@ col_LDADD = ../libpcp/.libs/libpcp1.a col_SOURCES = collisions.c invalidkeys_LDADD = ../libpcp/.libs/libpcp1.a ../src/keyprint.o invalidkeys_SOURCES = invalidkeys.c +pwhashes_LDADD = ../libpcp/.libs/libpcp1.a +pwhashes_SOURCES = pwhashes.c AM_CPPFLAGS = -I$(top_builddir)/src all: all-am @@ -262,6 +268,9 @@ col$(EXEEXT): $(col_OBJECTS) $(col_DEPENDENCIES) $(EXTRA_col_DEPENDENCIES) invalidkeys$(EXEEXT): $(invalidkeys_OBJECTS) $(invalidkeys_DEPENDENCIES) $(EXTRA_invalidkeys_DEPENDENCIES) @rm -f invalidkeys$(EXEEXT) $(LINK) $(invalidkeys_OBJECTS) $(invalidkeys_LDADD) $(LIBS) +pwhashes$(EXEEXT): $(pwhashes_OBJECTS) $(pwhashes_DEPENDENCIES) $(EXTRA_pwhashes_DEPENDENCIES) + @rm -f pwhashes$(EXEEXT) + $(LINK) $(pwhashes_OBJECTS) $(pwhashes_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -271,6 +280,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/collisions.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/invalidkeys.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pwhashes.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -519,7 +529,9 @@ uninstall-am: test: check - ./unittests.pl unittests.cfg + rm -f test* v* stresstest/* + ./unittests.pl unittests.cfg $(CHECK) + @echo "To run a single test only, type: 'make test CHECK=testname'" stresstest: check ./unittests.pl stresstests.cfg diff --git a/tests/key-alicia-pub b/tests/key-alicia-pub index a01cccc..29a70e5 100644 --- a/tests/key-alicia-pub +++ b/tests/key-alicia-pub @@ -3,34 +3,34 @@ Cipher: CURVE25519-ED25519-SALSA20-POLY1305 Owner: Alicia Mail: alicia@local - Key-ID: 0xE2942C2B6C96F6CC - Public-Key: 1mZ?-e4^0JA&[}#=t1$/&aIs8fWoUI)[[l?@](l[bY3wzfJg8$ -+RsBj5+]c/(!ZwWu-lDPCkCGb.GJM$HLPU@np=ZQTh-1[#RaNGdOWb(]ZY=K]fSdMfU4q)Z -T7dmxE:Cmst2o73w4RJ*A%?1idZ2&a^:kXsxnrxCXc5zt>n{QOQY{99oj&^!WH%6b&8@r]o -OLEzsx9t]B1/vjj:SUBt3*enaKb?.>2eZdMKvFLQ?7DeedmCz-0FGzc!t#o)&Tg%:jV$8iH -Iq.#9vqGT/x<UF39qu9sT6xka@S9F&fyO%Vgo -AtD^cLtsGtT.DiNQ5&dSeOe2Oa:ETxg&Z[fB+I7uU-Z9OstL?nWLq@O&)a+:vtW1NUrt>4( -ZaW2D^?xt:CzJ=ARPhD2P6AW5t(E@MD?rpY5MlYFhYv*VU7%6bZ>#hU:kW2r9nA8y5>OCb!u.i3dQ8NK3.<>A62Jy[^p}rzi:f*R-]cll:p!D -hB:kv7pVUjpj*-.5Bg8NBT:HpC:nA*X3)]wxmJcC0*vL4OMj3sOZNR^3k}OXM!N<]}+!SFY>qoT%H6{tZb +WCdrzhvQK7Cc]Prn5yvZvyo*@3:xd-plZ92qy@XnqMuc#N7EdRWP30RnxhloN6ZMTNGKOaR +ETo@7vqGT/x<]?.C}AEPsc+IVii?J?Tl3 +dZ/BB=?og/UGl-AaP(aSG0VxQ9SQMbbnWW1IMzrX{}>aRm^KrTa#B5oo2uW)@BgRl6kE2fFLmGh8)t>BX6q?qucW% +00961016?#e^3NT/77sIVp)H[P%U=36VHc+)7i+Klv>OpXx.Cyv*-/qUB>>TOr/21J^s(4B +H0Z2d1[B(z6I[xE%-a -+sp@mrOlA&rK9gRP1pk=Hnr=sCxjb?Sj51ISMR.YA&:ZT23?J.Nx!{ZHobd9(QUR)FPmjti -gT//!hkQNum.a9NC[LW>UetZSh%D>rS]#v}/uK[e:!VVu[(jqvxj3QIzoGs8fWoUI)[[l?@](l[bY3wzfJg8$+RsBj5+]c/(! -ZwWu-lDPCkCGb.GJM$HLPU@np=ZQTh-1[#RaNGdOWb(]ZY=K]fSdMfU4q)ZT7dmxE:Cmst2 -o73w4RJ*A%?1idZ2&a^:kXsxnrxCXc5zt>n{QOQY{99oj&^!WH%6b&8@r]oOLEzsx9t]B1/ -vjj:SUBt3*enaKb?.>2eZdMKvFLQ?7DeedmCz-0FGzc!t#o)&Tg%:jV$8iHIq.#9vqGT/x< -UF39qu9sT6xka@S9F&fyO%VgoAtD^cLtsGtT. -DiNQ5&dSeOe2Oa:ETxg&Z[fB+I7uU-Z9OstL?nWLq@O&)a+:vtW1NUrt>4(ZaW2D^?xt:Cz -J=ARPhD2P6AW5t(E@MD?rpY5MlYFhYv*VU7%6bZ>#hU:kW2r9nA8y5>OCb!u.i3dQ8NK3.<>A62Jy[^p}rzi:f*R-]cll:p!DhB:kv7pVUjpj -*-.5Bg8NBT:HpC:nA*X3)]wxmJcC0*vL4OMj3sOZNR^3k}OXM!N<]}+!SFY>qoT%H6{tZbWCdrzhvQK7Cc +]Prn5yvZvyo*@3:xd-plZ92qy@XnqMuc#N7EdRWP30RnxhloN6ZMTNGKOaRETo@7vqGT/x< +]?.C}AEPsc+IVii?J?Tl3dZ/BB=?og/UG +l-AaP(aSG0VxQ9SQMbbnWW1IMzrX{}>a +Rm^KrTa#B5oo2uW)@BgRl6kE2fFLmGh8)t>/*@]1qucW%0096109W(/!D +7d$0ht*YE)tbE0seV900000000000000000000000000000000000000000eu+e0seV901Y +bg0f]#U:]zzw ------ END PCP SECRET KEY ------ diff --git a/tests/key-bobby-pub b/tests/key-bobby-pub index d2f6655..322c738 100644 --- a/tests/key-bobby-pub +++ b/tests/key-bobby-pub @@ -2,35 +2,35 @@ Generated by: Pretty Curved Privacy Version 0.0.1 Cipher: CURVE25519-ED25519-SALSA20-POLY1305 Owner: Bobby - Mail: bobby@Ålocal - Key-ID: 0x68832D215AFB2440 - Public-Key: 1m9SHw3}swsTc3J1e -nQjeJey}hI*S7Pl^8O:i#]wd4}WNR7UYw(=}pBKsHbm^XeFqg^(CtjZG!K4oMPT=bJU -df/X2F]5iq-bYp:EC82YBJ<[NP*BDW?r-L..!As*CWddicuvsp^AQ20O-$+a@K<}6OPd*Hb -jex#UvSbZ+C%Gt+z!0i(0j#I6?xftr.eqpicnf]DWfiqE:*?/%(slD9QQU[7t4{J>hyLRkC -s=uT0HwrFIz6f9C!&=Nf$(jE*(3RFhA>SM5MiFq&8TqUn:^2xzxa70=]T*J[g}vVl8:-Zqq -N%{=qe7rScb.M4{Ld4j[HDIV(YZZWZ4}At*x.NT5E[/5p/3{SbNK7wjj[1yA2d]ZlE[I4-Z -11m*e^vcdRz+(xlU=:cXwV2A+463^RQHyN77/ ->fdtrPLE^lGYGTc(=FosgPggLZmqU)FTG6g.][KFAi5&YHl]3FOk$jf@g=c(^t3E+tqucW% -009610m4wrvfsIuoY5m{QWy!7fuih0^e@NMCINT@TYUeV/h:L8WNE3YBh]kQ{UG3qf*4Ql9 -}&1i2de}$URN7GD6yTb/8L^J +18a+&]*cfaPvpGAs*rp=oWkCXnLGe^aUx%^:BtLfv)U9yvTd$l]THd!tuMEjzY(YpATNQ[= ++9O9^D(VP+S/a@hLz<>u{Y]esh$8duOcR0iu]e*D%*)/F/JBwGFEOY/Sy.dtBJ:a1C7003$ +APnZE=KcH[2z+=R]?R?[}M!t@g+p2.UI!HL$?7.5v.w>3}B>dB[l#p7e<7{i)Jl<){nb:RRPgWu/uw8la@FBi{i@3y8]O6/l:NF0P7nsx4xKueAjuVY1h5e*K+3RwcZdD +Gviumba.%%uk*Ve3k39UMAPWa70-7xS7[SeaoyYtQmkuLLi5%w@lnyCUk@g[elv3v/qucW% +009610m=p7zV.nxQrk[Mw!!mbV1F[Nd(efiPTr+pd=QNgCQ>-k?#=T)XM7A[ +jSQW]2+-gx<+-p(4+#H8#]%s ------ END PCP PUBLICKEY ------ diff --git a/tests/key-bobby-sec b/tests/key-bobby-sec index a9bbc31..7b5168a 100644 --- a/tests/key-bobby-sec +++ b/tests/key-bobby-sec @@ -1,23 +1,23 @@ ----- BEGIN PCP SECRET KEY ----- Generated by: Pretty Curved Privacy Version 0.0.1 Cipher: CURVE25519-ED25519-SALSA20-POLY1305 - Key-ID: 0x68832D215AFB2440 - Creation Time: 2013-10-28T18:48:11 - Serial Number: 0xECD29916 + Key-ID: 0xCE20289DFB268A3D + Creation Time: 2013-11-01T15:53:45 + Serial Number: 0x2467E86B Key Version: 0x00000001 -1m9SHw3}swd4K/JF>>JbqkC- -ENik9(Oa&k6L^6(cq5O?r}Yx2C5&kgv$qs(-bttGrEtiKwvSQhD6&VdwYg)Fg%dqgVLX#FK -+DcAIb@!A-ql$kqlYXd71ciD-Gs+p^P8fvTd%QWcl:NlJtTyRdZ>sTc3J1enQjeJey} -hI*S7Pl^8O:i#]wd4}WNR7UYw(=}pBKsHbm^XeFqg^(CtjZG!K4oMPT=bJUdf/X2F]5iq-b -Yp:EC82YBJ<[NP*BDW?r-L..!As*CWddicuvsp^AQ20O-$+a@K<}6OPd*Hbjex#UvSbZ+C% -Gt+z!0i(0j#I6?xftr.eqpicnf]DWfiqE:*?/%(slD9QQU[7t4{J>hyLRkCs=uT0HwrFIz6 -f9C!&=Nf$(jE*(3RFhA>SM5MiFq&8TqUn:^2xzxa70=]T*J[g}vVl8:-ZqqN%{=qe7rScb. -M4{Ld4j[HDIV(YZZWZ4}At*x.NT5E[/5p/3{SbNK7wjj[1yA2d]ZlE[I4-Z11m*e^vcdRz+ -(xlU=:cXwV2A+463^RQHyN77/>fdtrPLE^lGY -GTc(=FosgPggLZmqU)FTG6g.][KFAi5&YHl]3FOk$jf@g=c(^-9o0OqucW%0096102z0J(& -Aly(LQ/JMoWb{0seV900000000000000000000000000000000000000000evsu0seV901Y -bg08Qd7i@/lX +18a+&]*cfaPvpGAs*rp=oWkCXnLGe^aUx%^:BtLfv/OYAu{EkGzV6b}YAR}P{d}y@LR)QXx +Mrlpmmyv5L2*caymk:0@x*u8U=rjS(uW.b0D5R-Esfd23JQIuCz6)v< +]f{eDwrpMNMVSH-4zE57W$!jZ(odJy4L)vTd$l]THd!tuMEjzY(YpATNQ[=+9O9^D(VP+S/ +a@hLz<>u{Y]esh$8duOcR0iu]e*D%*)/F/JBwGFEOY/Sy.dtBJ:a1C7003$APnZE=KcH[2z ++=R]?R?[}M!t@g+p2.UI!HL$?7.5v.w>3}B>dB[l#p7e<7{i)Jl<){nb:RRPgWu/uw8la@FBi{i@3y8]O6/l:NF0P7nsx4xKueAjuVY1h5e*K+3RwcZdDGviumba.%%uk +*Ve3k39UMAPWa70-7xS7[SeaoyYtQmkuLLi5%w@lnyCUk@g[e?*91UqucW%009610bH!hbM +Q0z>Pa*6vN85b0seV900000000000000000000000000000000000000000eu+e0seV901Y +bg0a8w*x-Fbk ------ END PCP SECRET KEY ------ diff --git a/tests/unittests.cfg b/tests/unittests.cfg index 9d5e3ae..adf18ab 100644 --- a/tests/unittests.cfg +++ b/tests/unittests.cfg @@ -77,10 +77,13 @@ dxmorg@florida.cops.gov # # encryption tests -idbobby = 0x68832D215AFB2440 -idalicia = 0xE2942C2B6C96F6CC +idbobby = 0xCE20289DFB268A3D +idalicia = 0x44713DD4E010C582 +mailbobby = bobby@local +mailalicia = alicia@local md5msg = 66b8c4ca9e5d2a7e3c0559c3cdea3d50 + # alicias part prepare = echo ${md5msg} > testmessage cmd = $pcp -V va -S -I key-alicia-sec -x a @@ -104,6 +107,7 @@ md5msg = 66b8c4ca9e5d2a7e3c0559c3cdea3d50 + # bobbys part cmd = $pcp -V vb -S -I key-bobby-sec -x b expect = /${idbobby}/ @@ -125,6 +129,52 @@ md5msg = 66b8c4ca9e5d2a7e3c0559c3cdea3d50 +# +# same, now with derived keys, keypairs: +# alicia bobby +# secret: derived for bobby secret:primary +# bobby's public: primary alicia's public: derived for him +# +# derived by name + + + cmd = $pcp -V va -p -R Bobby -x a -O testpub-forbobby-name + expect-file = testpub-forbobby-name + + + cmd = $pcp -V vb -P -I testpub-forbobby-name + expect = /added/ + + + id = grep Key-ID testpub-forbobby-name | sed 's/^ //g' | cut -d' ' -f2 + cmd = $pcp -V vb -e -i %{id} -I testmessage -O testencrypted-name -x b + expect = /success/ + + + cmd = $pcp -V va -d -I testencrypted-name -x a + expect = /success/ + + + # repeat, but now use derived keys in both directions + + cmd = $pcp -V vb -p -R Alicia -x b -O testpub-foralicia-name + expect-file = testpub-foralicia-name + + + cmd = $pcp -V va -P -I testpub-foralicia-name + expect = /added/ + + + id = grep Key-ID testpub-forbobby-name | sed 's/^ //g' | cut -d' ' -f2 + cmd = $pcp -V vb -e -i %{id} -I testmessage -O testencrypted-name -x b -R Alicia + expect = /success/ + + + cmd = $pcp -V va -d -I testencrypted-name -x a + expect = /success/ + + + # # negative tests, check for error handling @@ -206,7 +256,7 @@ md5msg = 66b8c4ca9e5d2a7e3c0559c3cdea3d50 - prepare = jot 5000 | while read ignore; do echo -n X; done > testfile-toolong + prepare = ./jot 5000 | while read ignore; do echo -n X; done > testfile-toolong cmd = $pcp -V $vault -P -I testfile-toolong expect = /line is too long/ @@ -216,7 +266,7 @@ md5msg = 66b8c4ca9e5d2a7e3c0559c3cdea3d50 * catch invalid z85, it only checks the input length and not the actual * encoding. Re-enable, once that bug is fixed. - prepare = jot 30 | while read ignore; do \ + prepare = ./jot 30 | while read ignore; do \ echo XXXXXXXXXXXXXXXXXX; done > testfile-noz85 cmd = $pcp -V $vault -P -I testfile-noz85 expect = /could not decode input/ @@ -224,7 +274,7 @@ md5msg = 66b8c4ca9e5d2a7e3c0559c3cdea3d50 */ - prepare = jot 30 | while read ignore; do echo XXXXX; done \ + prepare = ./jot 30 | while read ignore; do echo XXXXX; done \ | $pcp -z > testfile-nokey cmd = $pcp -V $vault -P -I testfile-nokey expect = /result to a proper sized key/ @@ -306,12 +356,7 @@ md5msg = 66b8c4ca9e5d2a7e3c0559c3cdea3d50 cmd = $pcp -V testvault-invalidversion -l expect = /Unexpected vault file format/ -/* - - cmd = $pcp -V testvault-invaliditemsize -l - expect = /invalid key item header size/ - -*/ + cmd = $pcp -V testvault-invaliditemtype -l expect = /invalid key type/ @@ -321,3 +366,16 @@ md5msg = 66b8c4ca9e5d2a7e3c0559c3cdea3d50 cmd = $pcp -V testvault-invalidkeytype -l expect = /contain any keys so far./ + + + cmd = ./pwhashes + expect = /ok/ + + +# +# input handling tests + + cmd = (./jot 300 | while read m; do echo -n m; done; echo xxx) \ + | $pcp -V $vault -k -x $passwd + expect = /Generated new secret key/ + diff --git a/tests/unittests.pl b/tests/unittests.pl index a6997d4..dc5780f 100755 --- a/tests/unittests.pl +++ b/tests/unittests.pl @@ -10,7 +10,10 @@ use Data::Dumper; sub run; sub execute; -my $config = shift @ARGV || die "usage: $0 \n"; +my ($config, $check) = @ARGV; +if (! $config) { + die "usage: $0 \n"; +} my %cfg = ParseConfig(-ConfigFile => $config, -InterPolateVars => 1, @@ -22,11 +25,22 @@ if (exists $cfg{confirm}) { my $cont = ; } -foreach my $test (keys %{$cfg{test}}) { - my $name = "$test ($cfg{test}->{$test}->{cmd})"; - &runtest($cfg{test}->{$test}, $name); +if ($check) { + if (exists $cfg{test}->{$check}) { + &runtest($cfg{test}->{$check}, $check); + } +} +else { + my $continue = 1; + foreach my $test (keys %{$cfg{test}}) { + if ($continue) { + $continue = &runtest($cfg{test}->{$test}, $test); + if (!$continue) { + print "Last failed check: $test\n"; + } + } + } } - sub runtest { @@ -46,11 +60,24 @@ sub runtest { if (exists $cfg->{test}) { foreach my $test (keys %{$cfg->{test}}) { my $name = "$test ($cfg->{test}->{$test}->{cmd})"; - &runtest($cfg->{test}->{$test}, $name); + if (&runtest($cfg->{test}->{$test}, $name) == 0) { + return 0; + } } - return; + return 1; } + $cfg->{cmd} =~ s/%\{([^\}]*)\}/ + my $N = $1; my $o; + if (exists $cfg->{$N}) { + $o = `$cfg->{$N}`; + chomp $o; + } + $o; + /gex; + + print STDERR "\n$cfg->{cmd}\n "; + my $ret = run($cfg->{cmd}, $cfg->{input}, \$out, \$error, 5, 0, undef); @@ -63,10 +90,10 @@ sub runtest { if (exists $cfg->{expect}) { if ($cfg->{expect} =~ /^\//) { - like($output, $cfg->{expect}, "$name") or last; + like($output, $cfg->{expect}, "$name") or return 0; } else { - is($output, $cfg->{expect}, "$name") or last; + is($output, $cfg->{expect}, "$name") or return 0; } } @@ -75,7 +102,7 @@ sub runtest { if (-s $cfg->{"expect-file"}) { $e = 1; } - is($e, 1, "$name") or last; + is($e, 1, "$name") or return 0; } elsif (exists $cfg->{"expect-file-contains"}) { @@ -84,28 +111,30 @@ sub runtest { if (-s $file) { $e = 1; } - is($e, 1, "$name") or last; + is($e, 1, "$name") or return 0; if (open F, "<$file") { my $content = join '', ; close F; - like($content, qr/$expect/s, "$name") or last; + like($content, qr/$expect/s, "$name") or return 0; } else { fail($test); - last; + return 0; } } elsif (exists $cfg->{exit}) { - is($ret, $cfg->{exit}, "$name") or last; + is($ret, $cfg->{exit}, "$name") or return 0; } else { - diag("invalid test spec for $test") or last; + diag("invalid test spec for $test"); fail($test); + return 0; } -} + return 1; +} done_testing;