mirror of
https://codeberg.org/scip/pcp.git
synced 2025-12-17 12:00:56 +01:00
sig calculation and output follows pbp scheme. unittests, doc and
detached sigs still missing.
This commit is contained in:
19
ChangeLog
19
ChangeLog
@@ -12,17 +12,16 @@
|
|||||||
|
|
||||||
Encrypted file format/scheme changed. Previously
|
Encrypted file format/scheme changed. Previously
|
||||||
I included the sender's key-id with the encrypted
|
I included the sender's key-id with the encrypted
|
||||||
cipher as a hash. Now the sender's public key will
|
cipher as a hash. So, encrypted message do no more
|
||||||
be included directly. This way I don't have to reveal
|
contain pk material.
|
||||||
key-ids (which is bad) and people can encrypt for
|
|
||||||
others without a full key exchange first.
|
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
|
0.1.5 Fixed a segmentation fault when using pcp1 -t on a
|
||||||
public key. I added a double free() there by purpose
|
public key. I added a double free() there by purpose
|
||||||
|
|||||||
16
TODO
16
TODO
@@ -10,19 +10,7 @@ key++: normalize id and lc()
|
|||||||
|
|
||||||
allow signing using an alternate secret key, like in pcpdecrypt()
|
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
|
support export/import from/to pbp
|
||||||
|
|
||||||
remove key-id from stored signatures, maybe add the file content again
|
re-add detached signatures, calculated with the pbp scheme but with
|
||||||
(by default a signature consists of the file+sig, but I sometime decided
|
separate files (as I had it before).
|
||||||
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).
|
|
||||||
@@ -38,18 +38,23 @@ static inline char *_lc(char *in) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// find the offset of the beginning of a certain string within binary data
|
// 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;
|
size_t i;
|
||||||
int sigfoot = 181; // yes, also bad. that's the armored sig footer
|
size_t offset = 0;
|
||||||
int offset = -1;
|
int m = 0;
|
||||||
|
|
||||||
for(i=0; i<binlen-sigfoot; ++i) {
|
for(i=0; i<binlen-hlen; ++i) {
|
||||||
if(memcmp(&bin[i], sigstart, hlen) == 0) {
|
if(memcmp(&bin[i], sigstart, hlen) == 0) {
|
||||||
offset = i;
|
offset = i;
|
||||||
|
m = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(m == 0)
|
||||||
|
offset = -1;
|
||||||
|
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
191
libpcp/ed.c
191
libpcp/ed.c
@@ -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) {
|
size_t pcp_ed_sign_buffered(FILE *in, FILE *out, pcp_key_t *s, int z85) {
|
||||||
unsigned char in_buf[PCP_BLOCK_SIZE];
|
unsigned char in_buf[PCP_BLOCK_SIZE];
|
||||||
size_t cur_bufsize = 0;
|
size_t cur_bufsize = 0;
|
||||||
|
size_t outsize = 0;
|
||||||
crypto_generichash_state *st = ucmalloc(sizeof(crypto_generichash_state));
|
crypto_generichash_state *st = ucmalloc(sizeof(crypto_generichash_state));
|
||||||
unsigned char hash[crypto_generichash_BYTES_MAX];
|
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);
|
cur_bufsize = fread(&in_buf, 1, PCP_BLOCK_SIZE, in);
|
||||||
if(cur_bufsize <= 0)
|
if(cur_bufsize <= 0)
|
||||||
break;
|
break;
|
||||||
|
outsize += cur_bufsize;
|
||||||
crypto_generichash_update(st, in_buf, cur_bufsize);
|
crypto_generichash_update(st, in_buf, cur_bufsize);
|
||||||
fwrite(in_buf, cur_bufsize, 1, out);
|
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);
|
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;
|
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) {
|
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;
|
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);
|
fprintf(out, "%s\n%s\n", z85encoded, PCP_SIG_END);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fwrite(signature, crypto_sign_BYTES, 1, out);
|
fprintf(out, "%s", PCP_SIGPREFIX);
|
||||||
|
fwrite(signature, mlen, 1, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fileno(in) != 0)
|
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);
|
free(st);
|
||||||
|
|
||||||
return mlen; // ???
|
return outsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned char *pcp_ed_verify_buffered(FILE *in, pcp_pubkey_t *p) {
|
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 cur_bufsize = 0;
|
||||||
|
size_t next_bufsize = 0;
|
||||||
|
size_t full_bufsize = 0;
|
||||||
|
|
||||||
int z85 = 0;
|
int z85 = 0;
|
||||||
crypto_generichash_state *st = ucmalloc(sizeof(crypto_generichash_state));
|
int gotsig = 0;
|
||||||
|
|
||||||
unsigned char hash[crypto_generichash_BYTES_MAX];
|
unsigned char hash[crypto_generichash_BYTES_MAX];
|
||||||
char *zhead;
|
char zhead[] = PCP_SIG_HEADER;
|
||||||
size_t hlen = strlen(PCP_SIG_HEADER);
|
size_t hlen = strlen(PCP_SIG_HEADER);
|
||||||
size_t nextsize = 0;
|
size_t hlen2 = 15; // hash: blake2\n\n
|
||||||
size_t restsize = 0;
|
|
||||||
size_t mlen = + crypto_sign_BYTES + crypto_generichash_BYTES_MAX;
|
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 sighash[mlen];
|
||||||
unsigned char sig[crypto_sign_BYTES];
|
|
||||||
char z85sigstart[] = PCP_SIG_START;
|
char z85sigstart[] = PCP_SIG_START;
|
||||||
char binsigstart[] = PCP_SIGPREFIX;
|
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);
|
crypto_generichash_init(st, NULL, 0, 0);
|
||||||
|
|
||||||
// determine sig type, clear or bin
|
/* use two half blocks, to overcome sigs spanning block boundaries */
|
||||||
cur_bufsize = hlen + 14; // header + hash name + 3x newline
|
cur_bufsize = fread(&in_buf, 1, PCP_BLOCK_SIZE/2, in);
|
||||||
fread(&in_buf, 1, cur_bufsize, in);
|
|
||||||
zhead = ucmalloc(cur_bufsize);
|
|
||||||
memcpy(zhead, in_buf, hlen);
|
|
||||||
memset(&zhead[hlen], 0, 1);
|
|
||||||
|
|
||||||
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;
|
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)
|
if(z85 == 1) {
|
||||||
break;
|
siglen = zlen;
|
||||||
|
strcpy(sigstart, z85sigstart);
|
||||||
if(z85) {
|
startlen = strlen(z85sigstart);
|
||||||
// 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 {
|
else {
|
||||||
// do the same for the bin sig
|
siglen = mlen + strlen(binsigstart);
|
||||||
offset = _findoffset(in_buf, cur_bufsize, binsigstart, strlen(binsigstart));
|
strcpy(sigstart, binsigstart);
|
||||||
if(offset > 0) {
|
startlen = strlen(binsigstart);
|
||||||
// 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)
|
|
||||||
|
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);
|
crypto_generichash_update(st, in_buf, cur_bufsize);
|
||||||
}
|
|
||||||
|
|
||||||
if(offset == -1) {
|
// 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");
|
fatal("Error, the signature doesn't contain the ed25519 signed hash\n");
|
||||||
goto errvb1;
|
goto errvb1;
|
||||||
}
|
}
|
||||||
|
|
||||||
crypto_generichash_final(st, hash, crypto_generichash_BYTES_MAX);
|
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) {
|
if(z85) {
|
||||||
memcpy(&z85encoded[restsize], in_buf, cur_bufsize);
|
char *z85block = pcp_readz85string(z85encoded, zlen);
|
||||||
char *z85block = pcp_readz85string(z85encoded, restsize + cur_bufsize);
|
|
||||||
if(z85block == NULL)
|
if(z85block == NULL)
|
||||||
goto errvb1;
|
goto errvb1;
|
||||||
|
|
||||||
|
fprintf(stderr, "<%s>\n", z85block);
|
||||||
|
|
||||||
size_t dstlen;
|
size_t dstlen;
|
||||||
unsigned char *z85decoded = pcp_z85_decode(z85block, &dstlen);
|
unsigned char *z85decoded = pcp_z85_decode(z85block, &dstlen);
|
||||||
if(dstlen != mlen) {
|
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;
|
goto errvb1;
|
||||||
}
|
}
|
||||||
memcpy(sighash, z85decoded, mlen);
|
memcpy(sighash, z85decoded, mlen);
|
||||||
}
|
}
|
||||||
else {
|
// else: if unarmored, sighash is already filled
|
||||||
memcpy(&sighash[restsize], in_buf, cur_bufsize); // FIXME: check if cur_bufsize holds enough
|
|
||||||
}
|
|
||||||
|
|
||||||
// huh, how did we made it til here?
|
// huh, how did we made it til here?
|
||||||
unsigned char *verifiedhash = NULL;
|
unsigned char *verifiedhash = NULL;
|
||||||
@@ -213,11 +265,11 @@ unsigned char *pcp_ed_verify_buffered(FILE *in, pcp_pubkey_t *p) {
|
|||||||
if(verifiedhash == NULL)
|
if(verifiedhash == NULL)
|
||||||
goto errvb1;
|
goto errvb1;
|
||||||
|
|
||||||
|
|
||||||
if(memcmp(verifiedhash, hash, crypto_generichash_BYTES_MAX) != 0) {
|
if(memcmp(verifiedhash, hash, crypto_generichash_BYTES_MAX) != 0) {
|
||||||
// sig verified, but the hash doesn't
|
// 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);
|
free(verifiedhash);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return verifiedhash;
|
return verifiedhash;
|
||||||
@@ -225,7 +277,6 @@ unsigned char *pcp_ed_verify_buffered(FILE *in, pcp_pubkey_t *p) {
|
|||||||
|
|
||||||
errvb1:
|
errvb1:
|
||||||
free(st);
|
free(st);
|
||||||
free(zhead);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ int pcpsign(char *infile, char *outfile, char *passwd, int z85) {
|
|||||||
pcp_key_t *secret = NULL;
|
pcp_key_t *secret = NULL;
|
||||||
|
|
||||||
secret = pcp_find_primary_secret();
|
secret = pcp_find_primary_secret();
|
||||||
|
|
||||||
if(secret == NULL) {
|
if(secret == NULL) {
|
||||||
fatal("Could not find a secret key in vault %s!\n", vault->filename);
|
fatal("Could not find a secret key in vault %s!\n", vault->filename);
|
||||||
goto errs1;
|
goto errs1;
|
||||||
@@ -113,13 +114,10 @@ int pcpverify(char *infile, char *id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(message == NULL) {
|
if(message != NULL) {
|
||||||
fprintf(stderr, "Could not verify signature\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
free(message);
|
free(message);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
errv4:
|
errv4:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user