sig calculation and output follows pbp scheme. unittests, doc and

detached sigs still missing.
This commit is contained in:
TLINDEN
2014-01-26 11:57:23 +01:00
parent 7b7aa6d395
commit 52a7509fe2
5 changed files with 151 additions and 110 deletions

View File

@@ -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

16
TODO
View File

@@ -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).
re-add detached signatures, calculated with the pbp scheme but with
separate files (as I had it before).

View File

@@ -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; i<binlen-sigfoot; ++i) {
for(i=0; i<binlen-hlen; ++i) {
if(memcmp(&bin[i], sigstart, hlen) == 0) {
offset = i;
m = 1;
break;
}
}
if(m == 0)
offset = -1;
return offset;
}

View File

@@ -49,6 +49,7 @@ unsigned char *pcp_ed_sign(unsigned char *message, size_t messagesize, pcp_key_t
size_t pcp_ed_sign_buffered(FILE *in, FILE *out, pcp_key_t *s, int z85) {
unsigned char in_buf[PCP_BLOCK_SIZE];
size_t cur_bufsize = 0;
size_t outsize = 0;
crypto_generichash_state *st = ucmalloc(sizeof(crypto_generichash_state));
unsigned char hash[crypto_generichash_BYTES_MAX];
@@ -61,7 +62,7 @@ size_t pcp_ed_sign_buffered(FILE *in, FILE *out, pcp_key_t *s, int z85) {
cur_bufsize = fread(&in_buf, 1, PCP_BLOCK_SIZE, in);
if(cur_bufsize <= 0)
break;
outsize += cur_bufsize;
crypto_generichash_update(st, in_buf, cur_bufsize);
fwrite(in_buf, cur_bufsize, 1, out);
}
@@ -74,18 +75,18 @@ size_t pcp_ed_sign_buffered(FILE *in, FILE *out, pcp_key_t *s, int z85) {
crypto_generichash_final(st, hash, crypto_generichash_BYTES_MAX);
unsigned char *signature = pcp_ed_sign(hash, crypto_generichash_BYTES_MAX, s);
size_t mlen = + crypto_sign_BYTES + crypto_generichash_BYTES_MAX;
unsigned char *signature = ucmalloc(mlen);
crypto_sign(signature, &mlen, hash, crypto_generichash_BYTES_MAX, s->edsecret);
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;
}

View File

@@ -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: