From 3f1bfef5814b8fe870a8ea3b5e81c1782b68297e Mon Sep 17 00:00:00 2001 From: "git@daemon.de" Date: Tue, 28 Jan 2014 16:53:26 +0100 Subject: [PATCH] added PBP public key import/export compatibility mode (-b --pbpcompat) --- ChangeLog | 4 ++ include/pcp/key.h | 1 + libpcp/key.c | 10 +++ man/pcp1.1 | 3 + man/pcp1.pod | 3 + src/keymgmt.c | 109 +++++++++++++++++++++++------ src/keymgmt.h | 4 +- src/keyprint.c | 173 +++++++++++++++++++++++++++++++--------------- src/keyprint.h | 2 +- src/pcp.c | 15 ++-- src/usage.h | 3 + src/usage.txt | 3 + 12 files changed, 248 insertions(+), 82 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8317c87..f213897 100644 --- a/ChangeLog +++ b/ChangeLog @@ -48,6 +48,10 @@ compile time with ./configure --enable-cbc. CBC mode in PCP uses a blocksize of 1k. + Added PBP public key import and export compatibility + (untested against pbp yet), use -b when exporting a + public key, or when importing one. + 0.1.5 Fixed a segmentation fault when using pcp1 -t on a public key. I added a double free() there by purpose to test segfault catching I added in unittest.pl diff --git a/include/pcp/key.h b/include/pcp/key.h index 4bdbd25..55caab1 100644 --- a/include/pcp/key.h +++ b/include/pcp/key.h @@ -123,6 +123,7 @@ pcp_key_t *pcpkey_encrypt(pcp_key_t *key, char *passphrase); pcp_key_t *pcpkey_decrypt(pcp_key_t *key, char *passphrase); pcp_pubkey_t *pcpkey_pub_from_secret(pcp_key_t *key); char *pcp_getkeyid(pcp_key_t *k); +char *pcp_getpubkeyid(pcp_pubkey_t *k); unsigned char *pcppubkey_getchecksum(pcp_pubkey_t *k); unsigned char *pcpkey_getchecksum(pcp_key_t *k); void pcp_inithashes(); diff --git a/libpcp/key.c b/libpcp/key.c index 40cb946..bc95f04 100644 --- a/libpcp/key.c +++ b/libpcp/key.c @@ -93,6 +93,16 @@ char *pcp_getkeyid(pcp_key_t *k) { return id; } +// same as above but for imported pbp keys +char *pcp_getpubkeyid(pcp_pubkey_t *k) { + uint32_t s, p; + p = jen_hash(k->pub, 32, JEN_PSALT); + s = jen_hash(k->edpub, 32, JEN_SSALT); + char *id = ucmalloc(17); + snprintf(id, 17, "%08X%08X", p, s); + return id; +} + void pcp_keypairs(byte *csk, byte *cpk, byte *esk, byte *epk) { // generate ed25519 + curve25519 keypair from random seed byte *seed = urmalloc(32); diff --git a/man/pcp1.1 b/man/pcp1.1 index dfb3c4a..6cd7a14 100644 --- a/man/pcp1.1 +++ b/man/pcp1.1 @@ -192,6 +192,9 @@ Pretty Curved Privacy \- File encryption using eliptic curve cryptography. \& \-y \-\-export\-yaml Export all keys stored in your vault \& as YAML formatted text. Use \-O to put \& the export into a file. +\& \-b \-\-pbpcompat Enable PBP compatibility for public key +\& exports and imports. +\& \& Encryption Options: \& \-e \-\-encrypt Asym\-Encrypt a message. Read from stdin or \& specified via \-I. Output will be written diff --git a/man/pcp1.pod b/man/pcp1.pod index 6531c2a..fc74f3d 100644 --- a/man/pcp1.pod +++ b/man/pcp1.pod @@ -64,6 +64,9 @@ Pretty Curved Privacy - File encryption using eliptic curve cryptography. -y --export-yaml Export all keys stored in your vault as YAML formatted text. Use -O to put the export into a file. + -b --pbpcompat Enable PBP compatibility for public key + exports and imports. + Encryption Options: -e --encrypt Asym-Encrypt a message. Read from stdin or specified via -I. Output will be written diff --git a/src/keymgmt.c b/src/keymgmt.c index c72418f..0db6edd 100644 --- a/src/keymgmt.c +++ b/src/keymgmt.c @@ -259,7 +259,7 @@ void pcp_exportsecretkey(pcp_key_t *key, char *outfile) { keyid we use the primary key. if no keyid has been given but a recipient instead, we try to look up the vault for a match. */ -void pcp_exportpublic(char *keyid, char *recipient, char *passwd, char *outfile) { +void pcp_exportpublic(char *keyid, char *recipient, char *passwd, char *outfile, int pbpcompat) { pcp_pubkey_t *key = NULL; if(keyid != NULL) { @@ -307,8 +307,11 @@ void pcp_exportpublic(char *keyid, char *recipient, char *passwd, char *outfile) // scip //printf("EXPORT:\n"); //pcpprint_bin(stdout, key, PCP_RAW_PUBKEYSIZE); printf("\n"); - pcppubkey_print(key, out); - fprintf(stderr, "public key exported.\n"); + pcppubkey_print(key, out, pbpcompat); + if(pbpcompat) + fprintf(stderr, "public key exported in PBP format.\n"); + else + fprintf(stderr, "public key exported.\n"); } free(key); @@ -370,31 +373,97 @@ int pcp_importsecret (vault_t *vault, FILE *in) { } -int pcp_importpublic (vault_t *vault, FILE *in) { - size_t clen; - char *z85 = pcp_readz85file(in); +int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat) { + pcp_pubkey_t *pub = NULL; + if(pbpcompat == 1) { + size_t bufsize = 1024; + unsigned char in_buf[bufsize]; + pub = ucmalloc(sizeof(pcp_pubkey_t)); + char *date = ucmalloc(19); + char *tmp = ucmalloc(1024); - if(z85 == NULL) - return 1; + bufsize = fread(&in_buf, 1, crypto_sign_BYTES, in); + + fread(&in_buf, 1, crypto_box_PUBLICKEYBYTES, in); // ignored currently + fread(pub->edpub, 1, crypto_sign_PUBLICKEYBYTES, in); + fread(pub->pub, 1, crypto_box_PUBLICKEYBYTES, in); - unsigned char *z85decoded = pcp_z85_decode((char *)z85, &clen); - free(z85); + fread(date, 1, 19, in); + date[19] = '\0'; + fread(&in_buf, 1, 44, in); // ignore validity date - if(z85decoded == NULL) { - fatal("Error: could not decode input - it's probably not Z85 (got %d bytes)\n", clen); + bufsize = fread(tmp, 1, 1024, in); + tmp[bufsize] = '\0'; + + struct tm c; + if(strptime(date, "%Y-%m-%dT%H:%M:%S", &c) == NULL) { + fatal("Failed to parse creation time in PBP public key file (<%s>)\n", date); + goto errimp1; + } + + char *parts = strtok (tmp, "|"); + int pnum = 0; + while (parts != NULL) { + if(pnum == 0) + memcpy(pub->owner, parts, strlen(parts)); + else if (pnum == 1) + memcpy(pub->mail, parts, strlen(parts)); + parts = strtok(NULL, "|"); + pnum++; + } + free(parts); + + if(sscanf(tmp, "%s|%s", pub->owner, pub->mail) == 0) { + if(sscanf(tmp, "%s", pub->owner) == 0) { + fatal("Failed to parse owner in PBP public key file\n"); + goto errimp1; + } + } + + pub->ctime = (long)mktime(&c); + pub->type = PCP_KEY_TYPE_PUBLIC; + pub->version = PCP_KEY_VERSION; + pub->serial = arc4random(); + memcpy(pub->id, pcp_getpubkeyid(pub), 17); + + free(date); + free(tmp); + goto kimp; + + errimp1: + free(date); + free(tmp); + free(pub); return 1; } + else { + size_t clen; + char *z85 = pcp_readz85file(in); - if(clen != PCP_RAW_PUBKEYSIZE) { - fatal("Error: decoded input didn't result to a proper sized key (got %d, expected %d)!\n", clen, PCP_RAW_PUBKEYSIZE); - free(z85decoded); - return 1; + if(z85 == NULL) + return 1; + + unsigned char *z85decoded = pcp_z85_decode((char *)z85, &clen); + free(z85); + + if(z85decoded == NULL) { + fatal("Error: could not decode input - it's probably not Z85 (got %d bytes)\n", clen); + return 1; + } + + if(clen != PCP_RAW_PUBKEYSIZE) { + fatal("Error: decoded input didn't result to a proper sized key (got %d, expected %d)!\n", clen, PCP_RAW_PUBKEYSIZE); + free(z85decoded); + return 1; + } + + // all good now + pub = ucmalloc(sizeof(pcp_pubkey_t)); + memcpy(pub, z85decoded, PCP_RAW_PUBKEYSIZE); + pubkey2native(pub); } - // all good now - pcp_pubkey_t *pub = ucmalloc(sizeof(pcp_pubkey_t)); - memcpy(pub, z85decoded, PCP_RAW_PUBKEYSIZE); - pubkey2native(pub); + kimp: if(debug) pcp_dumppubkey(pub); diff --git a/src/keymgmt.h b/src/keymgmt.h index 0bfc6fb..5fcd65e 100644 --- a/src/keymgmt.h +++ b/src/keymgmt.h @@ -49,10 +49,10 @@ void pcp_listkeys(); void pcp_exportsecret(char *keyid, int useid, char *outfile); void pcp_exportsecretkey(pcp_key_t *key, 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); +void pcp_exportpublic(char *keyid, char *recipient, char *passwd, char *outfile, int pbpcompat); char *pcp_normalize_id(char *keyid); pcp_key_t *pcp_find_primary_secret(); -int pcp_importpublic (vault_t *vault, FILE *in); +int pcp_importpublic (vault_t *vault, FILE *in, int pbpcompat); int pcp_importsecret (vault_t *vault, FILE *in); void pcpdelete_key(char *keyid); char *pcp_find_id_byrec(char *recipient); diff --git a/src/keyprint.c b/src/keyprint.c index 227f6c5..62e5d45 100644 --- a/src/keyprint.c +++ b/src/keyprint.c @@ -91,7 +91,7 @@ int pcptext_infile(char *infile) { pubkey2native(key); if(pcp_sanitycheck_pub(key) == 0) { fprintf(stdout, "%s is a public key file:\n", infile); - pcppubkey_print(key, stdout); + pcppubkey_print(key, stdout, 0); free(key); goto tdone; } @@ -127,7 +127,7 @@ void pcptext_key(char *keyid) { if(p != NULL) { if(debug) pcp_dumppubkey(p); - pcppubkey_print(p, stdout); + pcppubkey_print(p, stdout, 0); } else { fatal("No key with id 0x%s found!\n", keyid); @@ -214,74 +214,139 @@ void pcpkey_print(pcp_key_t *key, FILE* out) { free(z85encoded); } -void pcppubkey_print(pcp_pubkey_t *key, FILE* out) { - size_t zlen; - - //printf("version: %08x\n", key->version); - - pubkey2be(key); - - void *blob = ucmalloc(PCP_RAW_PUBKEYSIZE); - pcp_pubkeyblob(blob, key); - char *z85encoded = pcp_z85_encode((unsigned char*)blob, PCP_RAW_PUBKEYSIZE, &zlen); - pubkey2native(key); - - free(blob); - +void pcppubkey_print(pcp_pubkey_t *key, FILE* out, int pbpcompat) { struct tm *c; time_t t = (time_t)key->ctime; c = localtime(&t); - fprintf(out, "%s\n", PCP_PUBKEY_HEADER); + if(pbpcompat == 1) { + // sign(mk, master public | cipher public | sign public | created[32] | valid[32] | name... ) + // dates='{:<32}{:<32}'.format(self.created.isoformat(), self.valid.isoformat()) + // fd.write(nacl.crypto_sign(self.mp+self.sp+self.cp+dates+self.name, self.ms)) + // >>> dates='{:<32}{:<32}'.format(c.isoformat(), c.isoformat()) + // >>> dates + // '2014-01-28T13:30:32.674394 2014-01-28T13:30:32.674394 ' + size_t namelen = strlen(key->owner) + 3 + strlen(key->mail); + size_t rawsize = (crypto_box_PUBLICKEYBYTES * 2) + crypto_sign_PUBLICKEYBYTES +\ + 64 + namelen; + size_t pos = 0; + unsigned char *raw = ucmalloc(rawsize); + char *dates = ucmalloc(65); + char *name = ucmalloc(strlen(key->owner) + 3 + strlen(key->mail)); - fprintf(out, " Generated by: %s Version %d.%d.%d\n", - PCP_ME, PCP_VERSION_MAJOR, PCP_VERSION_MINOR, PCP_VERSION_PATCH); + memcpy(raw, key->pub, crypto_box_PUBLICKEYBYTES); + pos += crypto_box_PUBLICKEYBYTES; - fprintf(out, " Cipher: %s\n", PCP_KEY_PRIMITIVE); + memcpy(&raw[pos], key->edpub, crypto_sign_PUBLICKEYBYTES); + pos += crypto_sign_PUBLICKEYBYTES; - fprintf(out, " Owner: %s\n", key->owner); - fprintf(out, " Mail: %s\n", key->mail); + memcpy(&raw[pos], key->pub, crypto_box_PUBLICKEYBYTES); + pos += crypto_box_PUBLICKEYBYTES; - fprintf(out, " Key-ID: 0x%s\n", key->id); - fprintf(out, " Public-Key: %s\n", pcp_z85_encode(key->pub, 32, &zlen)); + struct tm *v; + time_t vt = t + 31536000; + v = localtime(&vt); - //2004-06-14T23:34:30. - fprintf(out, " Creation Time: %04d-%02d-%02dT%02d:%02d:%02d\n", - c->tm_year+1900, c->tm_mon+1, c->tm_mday, - c->tm_hour, c->tm_min, c->tm_sec); + sprintf(dates, "%04d-%02d-%02dT%02d:%02d:%02d %04d-%02d-%02dT%02d:%02d:%02d ", + c->tm_year+1900-1, c->tm_mon+1, c->tm_mday, // wtf? why -1? + c->tm_hour, c->tm_min, c->tm_sec, + v->tm_year+1900-1, v->tm_mon+1, v->tm_mday, + v->tm_hour, v->tm_min, v->tm_sec); - unsigned char *hash = pcppubkey_getchecksum(key); - fprintf(out, " Checksum: "); + sprintf(name, "%s|%s", key->owner, key->mail); - int i; - for ( i = 0;i <15 ;++i) fprintf(out, "%02X:",(unsigned int) hash[i]); - fprintf(out, "%02X", hash[15]); - fprintf(out, "\n "); - for ( i = 16;i <31 ;++i) fprintf(out, "%02X:",(unsigned int) hash[i]); - fprintf(out, "%02X", hash[31]); - fprintf(out, "\n"); - fprintf(out, " Serial Number: 0x%08X\n", key->serial); - fprintf(out, " Key Version: 0x%08X\n", key->version); - - char *r = pcppubkey_get_art(key); - fprintf(out, " Random Art ID: "); - for (i=0; ifilename); } else { - fprintf(out, "%c", r[i]); + char *passphrase; + pcp_readpass(&passphrase, + "Enter passphrase to decrypt your secret key for signing the export", NULL, 1); + + secret = pcpkey_decrypt(secret, passphrase); + if(secret != NULL) { + size_t siglen = rawsize + crypto_sign_BYTES; + unsigned char *sig = pcp_ed_sign(raw, rawsize, secret); + if(sig != NULL) + fwrite(sig, 1, siglen, out); + } } } - fprintf(out, "\n"); + else { + size_t zlen; + + //printf("version: %08x\n", key->version); + + pubkey2be(key); + + void *blob = ucmalloc(PCP_RAW_PUBKEYSIZE); + pcp_pubkeyblob(blob, key); + char *z85encoded = pcp_z85_encode((unsigned char*)blob, PCP_RAW_PUBKEYSIZE, &zlen); + pubkey2native(key); + + free(blob); + + + + fprintf(out, "%s\n", PCP_PUBKEY_HEADER); + + fprintf(out, " Generated by: %s Version %d.%d.%d\n", + PCP_ME, PCP_VERSION_MAJOR, PCP_VERSION_MINOR, PCP_VERSION_PATCH); + + fprintf(out, " Cipher: %s\n", PCP_KEY_PRIMITIVE); + + fprintf(out, " Owner: %s\n", key->owner); + fprintf(out, " Mail: %s\n", key->mail); + + fprintf(out, " Key-ID: 0x%s\n", key->id); + fprintf(out, " Public-Key: %s\n", pcp_z85_encode(key->pub, 32, &zlen)); + + //2004-06-14T23:34:30. + fprintf(out, " Creation Time: %04d-%02d-%02dT%02d:%02d:%02d\n", + c->tm_year+1900, c->tm_mon+1, c->tm_mday, + c->tm_hour, c->tm_min, c->tm_sec); + + unsigned char *hash = pcppubkey_getchecksum(key); + fprintf(out, " Checksum: "); + + int i; + for ( i = 0;i <15 ;++i) fprintf(out, "%02X:",(unsigned int) hash[i]); + fprintf(out, "%02X", hash[15]); + fprintf(out, "\n "); + for ( i = 16;i <31 ;++i) fprintf(out, "%02X:",(unsigned int) hash[i]); + fprintf(out, "%02X", hash[31]); + fprintf(out, "\n"); + fprintf(out, " Serial Number: 0x%08X\n", key->serial); + fprintf(out, " Key Version: 0x%08X\n", key->version); - fprintf(out, "\n%s\n", z85encoded); - - fprintf(out, "%s\n", PCP_PUBKEY_FOOTER); - - free(hash); - free(r); - free(z85encoded); + char *r = pcppubkey_get_art(key); + fprintf(out, " Random Art ID: "); + for (i=0; ivalue, xpass, outfile); + pcp_exportpublic(id, recipient->value, xpass, outfile, pbpcompat); else - pcp_exportpublic(id, NULL, xpass, outfile); + pcp_exportpublic(id, NULL, xpass, outfile, pbpcompat); if(xpass != NULL) free(xpass); if(recipient != NULL) @@ -312,7 +317,7 @@ int main (int argc, char **argv) { break; } } - pcp_importpublic(vault, in); + pcp_importpublic(vault, in, pbpcompat); break; case PCP_MODE_IMPORT_SECRET: diff --git a/src/usage.h b/src/usage.h index d9a52f7..23ca23d 100644 --- a/src/usage.h +++ b/src/usage.h @@ -59,6 +59,9 @@ "-y --export-yaml Export all keys stored in your vault\n" \ " as YAML formatted text. Use -O to put\n" \ " the export into a file.\n" \ +"-b --pbpcompat Enable PBP compatibility for public key\n" \ +" exports and imports.\n" \ +"\n" \ "Encryption Options:\n" \ "-e --encrypt Asym-Encrypt a message. Read from stdin or\n" \ " specified via -I. Output will be written\n" \ diff --git a/src/usage.txt b/src/usage.txt index 97d3ab7..ee7bbaa 100644 --- a/src/usage.txt +++ b/src/usage.txt @@ -57,6 +57,9 @@ Keymanagement Options: -y --export-yaml Export all keys stored in your vault as YAML formatted text. Use -O to put the export into a file. +-b --pbpcompat Enable PBP compatibility for public key + exports and imports. + Encryption Options: -e --encrypt Asym-Encrypt a message. Read from stdin or specified via -I. Output will be written