From 52a7509fe2643335476e819ef8d86cc26447850a Mon Sep 17 00:00:00 2001 From: TLINDEN Date: Sun, 26 Jan 2014 11:57:23 +0100 Subject: [PATCH] sig calculation and output follows pbp scheme. unittests, doc and detached sigs still missing. --- ChangeLog | 19 ++--- TODO | 16 +--- include/pcp/util.h | 13 ++- libpcp/ed.c | 203 ++++++++++++++++++++++++++++----------------- src/signature.c | 10 +-- 5 files changed, 151 insertions(+), 110 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9e83b86..d8fc4dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,17 +12,16 @@ Encrypted file format/scheme changed. Previously I included the sender's key-id with the encrypted - cipher as a hash. Now the sender's public key will - be included directly. This way I don't have to reveal - key-ids (which is bad) and people can encrypt for - others without a full key exchange first. + cipher as a hash. So, encrypted message do no more + contain pk material. + + Changed signature scheme completely. Binary signature + follow the pbp scheme: calculate blake2 hash of the + content, sign the hash, write out original content, + add "\nnacl-", add the signature, add the hash. + Armored signatures are calculated the same way but + output follows the pgp scheme instead. - Also I'm no more using the primary secret (or any - other secret in the vault) for encryption. Instead - every time a user encrypts a file, a new keypair - will be generated. That way the file can only be - decrypted by the recipient (which public key have - been used) and no one else, not even the sender. 0.1.5 Fixed a segmentation fault when using pcp1 -t on a public key. I added a double free() there by purpose diff --git a/TODO b/TODO index e8b38bf..5fae59f 100644 --- a/TODO +++ b/TODO @@ -10,19 +10,7 @@ key++: normalize id and lc() allow signing using an alternate secret key, like in pcpdecrypt() -use recipient in encryption to lookup public key in the vault, if id not given - -change encrypted file format to the one of pbp, following it: - - support multiple recipients - - encrypt 32k blockwise using crypto_secretbox() using - a random key, encrypt that key for each recipient with - pk using crypto_box() - - base85 <=> z85? maybe make us base85 tolerant while still - preferring z85? I dunno... - support export/import from/to pbp -remove key-id from stored signatures, maybe add the file content again -(by default a signature consists of the file+sig, but I sometime decided -to detach the sig and only write this to the signature file, at least pbp -stores the full stuff, so I shall do it as well). \ No newline at end of file +re-add detached signatures, calculated with the pbp scheme but with +separate files (as I had it before). \ No newline at end of file diff --git a/include/pcp/util.h b/include/pcp/util.h index 9746006..5f1b60c 100644 --- a/include/pcp/util.h +++ b/include/pcp/util.h @@ -38,18 +38,23 @@ static inline char *_lc(char *in) { } // find the offset of the beginning of a certain string within binary data -static inline int _findoffset(unsigned char *bin, size_t binlen, char *sigstart, size_t hlen) { +static inline size_t _findoffset(unsigned char *bin, size_t binlen, char *sigstart, size_t hlen) { size_t i; - int sigfoot = 181; // yes, also bad. that's the armored sig footer - int offset = -1; + size_t offset = 0; + int m = 0; - for(i=0; iedsecret); if(z85) { - fprintf(out, "\n%s\nVersion: PCP v%d.%d.%d\n\n", PCP_SIG_START, PCP_VERSION_MAJOR, PCP_VERSION_MINOR, PCP_VERSION_PATCH); + fprintf(out, "\n%s\n Version: PCP v%d.%d.%d\n\n", PCP_SIG_START, PCP_VERSION_MAJOR, PCP_VERSION_MINOR, PCP_VERSION_PATCH); size_t zlen; - char *z85encoded = pcp_z85_encode((unsigned char*)signature, crypto_sign_BYTES, &zlen); + char *z85encoded = pcp_z85_encode((unsigned char*)signature, mlen, &zlen); fprintf(out, "%s\n%s\n", z85encoded, PCP_SIG_END); } else { - fwrite(signature, crypto_sign_BYTES, 1, out); + fprintf(out, "%s", PCP_SIGPREFIX); + fwrite(signature, mlen, 1, out); } if(fileno(in) != 0) @@ -95,107 +96,158 @@ size_t pcp_ed_sign_buffered(FILE *in, FILE *out, pcp_key_t *s, int z85) { free(st); - return mlen; // ??? + return outsize; } - unsigned char *pcp_ed_verify_buffered(FILE *in, pcp_pubkey_t *p) { - unsigned char in_buf[PCP_BLOCK_SIZE]; + unsigned char in_buf[PCP_BLOCK_SIZE/2]; + unsigned char in_next[PCP_BLOCK_SIZE/2]; + unsigned char in_full[PCP_BLOCK_SIZE]; + size_t cur_bufsize = 0; + size_t next_bufsize = 0; + size_t full_bufsize = 0; + int z85 = 0; - crypto_generichash_state *st = ucmalloc(sizeof(crypto_generichash_state)); + int gotsig = 0; + unsigned char hash[crypto_generichash_BYTES_MAX]; - char *zhead; + char zhead[] = PCP_SIG_HEADER; size_t hlen = strlen(PCP_SIG_HEADER); - size_t nextsize = 0; - size_t restsize = 0; + size_t hlen2 = 15; // hash: blake2\n\n size_t mlen = + crypto_sign_BYTES + crypto_generichash_BYTES_MAX; - unsigned char z85encoded[181]; + size_t zlen = 262; // FIXME: calculate + unsigned char z85encoded[zlen]; unsigned char sighash[mlen]; - unsigned char sig[crypto_sign_BYTES]; char z85sigstart[] = PCP_SIG_START; char binsigstart[] = PCP_SIGPREFIX; - int offset = -1; + char sigstart[] = PCP_SIG_START; + size_t siglen, startlen; + size_t offset = -1; + crypto_generichash_state *st = ucmalloc(sizeof(crypto_generichash_state)); crypto_generichash_init(st, NULL, 0, 0); - // determine sig type, clear or bin - cur_bufsize = hlen + 14; // header + hash name + 3x newline - fread(&in_buf, 1, cur_bufsize, in); - zhead = ucmalloc(cur_bufsize); - memcpy(zhead, in_buf, hlen); - memset(&zhead[hlen], 0, 1); + /* use two half blocks, to overcome sigs spanning block boundaries */ + cur_bufsize = fread(&in_buf, 1, PCP_BLOCK_SIZE/2, in); - if(strncmp(zhead, PCP_SIG_HEADER, hlen) == 0) + // look for z85 header and cut it out + if(_findoffset(in_buf, cur_bufsize, zhead, hlen) == 0) { + // it is armored + next_bufsize = cur_bufsize - (hlen+hlen2); // size - the header + memcpy(in_next, &in_buf[hlen+hlen2], next_bufsize); // tmp save + memcpy(in_buf, in_next, next_bufsize); // put into inbuf without header + if(cur_bufsize == PCP_BLOCK_SIZE/2) { + // more to come + cur_bufsize = fread(&in_buf[next_bufsize], 1, ((PCP_BLOCK_SIZE/2) - next_bufsize), in); + cur_bufsize += next_bufsize; + next_bufsize = 0; + // now we've got the 1st half block in in_buf + // unless the file was smaller than blocksize/2, + // in which case it contains all the rest til eof + } z85 = 1; - else - nextsize = cur_bufsize; - - while(!feof(in)) { - if(z85 == 0 && nextsize > 0) { - // bin sig, read blocksize - header and put zheader in front of it again - cur_bufsize = fread(&in_buf[hlen], 1, PCP_BLOCK_SIZE - hlen, in); - memcpy(in_buf, zhead, hlen); - cur_bufsize += hlen; - } - else - cur_bufsize = fread(&in_buf, 1, PCP_BLOCK_SIZE, in); - - if(cur_bufsize <= 0) - break; - - if(z85) { - // look if we need to cut something from the current block - offset = _findoffset(in_buf, cur_bufsize, z85sigstart, strlen(z85sigstart)); - if(offset > 0) { - // we need to cut - restsize = cur_bufsize - offset; // the start of the armor sig - cur_bufsize -= restsize; // bin stuff in front of it, if any - memcpy(z85encoded, &in_buf[offset], restsize); // save the armor sig chunk - } - } - else { - // do the same for the bin sig - offset = _findoffset(in_buf, cur_bufsize, binsigstart, strlen(binsigstart)); - if(offset > 0) { - // we need to cut - restsize = cur_bufsize - offset + strlen(binsigstart); // the start of the bin sig - cur_bufsize -= offset; // bin stuff in front of it, if any - memcpy(sighash, &in_buf[offset + strlen(binsigstart)], restsize); // save the armor sig chunk - } - } - - if(offset == -1) - crypto_generichash_update(st, in_buf, cur_bufsize); } - if(offset == -1) { + if(z85 == 1) { + siglen = zlen; + strcpy(sigstart, z85sigstart); + startlen = strlen(z85sigstart); + } + else { + siglen = mlen + strlen(binsigstart); + strcpy(sigstart, binsigstart); + startlen = strlen(binsigstart); + } + + + while (cur_bufsize > 0) { + if(cur_bufsize == PCP_BLOCK_SIZE/2) { + // probably not eof + next_bufsize = fread(&in_next, 1, PCP_BLOCK_SIZE/2, in); + } + else + next_bufsize = 0; // <= this is eof + + // concatenate previous and current buffer + if(next_bufsize == 0) + memcpy(in_full, in_buf, cur_bufsize); + else { + memcpy(in_full, in_buf, cur_bufsize); + memcpy(&in_full[cur_bufsize], in_next, next_bufsize); + } + full_bufsize = cur_bufsize+next_bufsize; + + // find signature offset + offset = _findoffset(in_full, full_bufsize, sigstart, startlen); + + //printf("offset: %ld, full: %ld, cur: %ld\n", offset, full_bufsize, cur_bufsize); + + if(offset >= 0 && offset <= PCP_BLOCK_SIZE/2) { + // sig begins within the first half, adjust in_buf size + //printf("1st half\n"); + next_bufsize = 0; + cur_bufsize = offset; + gotsig = 1; + if(z85) { + cur_bufsize -= 1; + memcpy(z85encoded, &in_full[offset], zlen); + } + else + memcpy(sighash, &in_full[offset + strlen(binsigstart)], mlen); + } + else if(full_bufsize - offset == siglen) { + // sig fits within the 2nd half + // offset: 28279, full: 28413, cur: 16384 + //printf("2nd half\n"); + next_bufsize -= siglen; + gotsig = 1; + if(z85) { + cur_bufsize -= 1; + memcpy(z85encoded, &in_full[full_bufsize - siglen], siglen); + } + else + memcpy(sighash, &in_full[full_bufsize - mlen], mlen); + } + else + offset = 0; + + // add previous half block to hash + crypto_generichash_update(st, in_buf, cur_bufsize); + + // next => in + if(next_bufsize > 0) { + memcpy(in_buf, in_next, next_bufsize); + cur_bufsize = next_bufsize; + } + else + break; + } // while + + if(gotsig == 0) { fatal("Error, the signature doesn't contain the ed25519 signed hash\n"); goto errvb1; } crypto_generichash_final(st, hash, crypto_generichash_BYTES_MAX); - // pull in the remainder - cur_bufsize = fread(&in_buf, 1, restsize, in); - - // put hashsig together if(z85) { - memcpy(&z85encoded[restsize], in_buf, cur_bufsize); - char *z85block = pcp_readz85string(z85encoded, restsize + cur_bufsize); + char *z85block = pcp_readz85string(z85encoded, zlen); if(z85block == NULL) goto errvb1; + + fprintf(stderr, "<%s>\n", z85block); + size_t dstlen; unsigned char *z85decoded = pcp_z85_decode(z85block, &dstlen); if(dstlen != mlen) { - fatal("z85 decoded signature didn't result in a proper signed hash\n"); + fatal("z85 decoded signature didn't result in a proper signed hash(got: %ld, expected: %ld)\n", dstlen, mlen); goto errvb1; } memcpy(sighash, z85decoded, mlen); } - else { - memcpy(&sighash[restsize], in_buf, cur_bufsize); // FIXME: check if cur_bufsize holds enough - } + // else: if unarmored, sighash is already filled + // huh, how did we made it til here? unsigned char *verifiedhash = NULL; @@ -213,11 +265,11 @@ unsigned char *pcp_ed_verify_buffered(FILE *in, pcp_pubkey_t *p) { if(verifiedhash == NULL) goto errvb1; - if(memcmp(verifiedhash, hash, crypto_generichash_BYTES_MAX) != 0) { // sig verified, but the hash doesn't - fatal("signed hash doesn't match with actual hash of signed file content\n"); + fatal("signed hash doesn't match actual hash of signed file content\n"); free(verifiedhash); + return NULL; } return verifiedhash; @@ -225,7 +277,6 @@ unsigned char *pcp_ed_verify_buffered(FILE *in, pcp_pubkey_t *p) { errvb1: free(st); - free(zhead); return NULL; } diff --git a/src/signature.c b/src/signature.c index ad99630..8b5febf 100644 --- a/src/signature.c +++ b/src/signature.c @@ -29,6 +29,7 @@ int pcpsign(char *infile, char *outfile, char *passwd, int z85) { pcp_key_t *secret = NULL; secret = pcp_find_primary_secret(); + if(secret == NULL) { fatal("Could not find a secret key in vault %s!\n", vault->filename); goto errs1; @@ -113,13 +114,10 @@ int pcpverify(char *infile, char *id) { } } - if(message == NULL) { - fprintf(stderr, "Could not verify signature\n"); - } - else + if(message != NULL) { free(message); - - return 0; + return 0; + } errv4: