mirror of
https://codeberg.org/scip/pcp.git
synced 2025-12-17 12:00:56 +01:00
Merge branch 'master' of github.com:TLINDEN/pcp
Conflicts: TODO
This commit is contained in:
25
ChangeLog
25
ChangeLog
@@ -12,17 +12,22 @@
|
|||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Also I'm no more using the primary secret (or any
|
Changed signature scheme completely. Binary signature
|
||||||
other secret in the vault) for encryption. Instead
|
follow the pbp scheme: calculate blake2 hash of the
|
||||||
every time a user encrypts a file, a new keypair
|
content, sign the hash, write out original content,
|
||||||
will be generated. That way the file can only be
|
add "\nnacl-", add the signature, add the hash.
|
||||||
decrypted by the recipient (which public key have
|
Armored signatures are calculated the same way but
|
||||||
been used) and no one else, not even the sender.
|
output follows the pgp scheme instead.
|
||||||
|
|
||||||
|
Detached signatures are still supported as before,
|
||||||
|
for the user everything with them is as known, but
|
||||||
|
the commandline option -a (--detach) have to be
|
||||||
|
applied. Internally, however, inputs will be read in
|
||||||
|
32k blockwise as well. Detached signatures are now
|
||||||
|
z85 encoded always.
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
5
TODO
5
TODO
@@ -13,8 +13,3 @@ allow signing using an alternate secret key, like in pcpdecrypt()
|
|||||||
|
|
||||||
support export/import from/to pbp
|
support export/import from/to pbp
|
||||||
|
|
||||||
add support for armored signature using -z
|
|
||||||
|
|
||||||
add support for buffered_signature (which has to be the default from pcp commandline)
|
|
||||||
|
|
||||||
remove z85 mode (-z without -e -d -c -g)
|
|
||||||
@@ -40,9 +40,10 @@ typedef unsigned int qbyte; // Quad byte = 32 bits
|
|||||||
#define PCP_ZFILE_HEADER "----- BEGIN Z85 ENCODED FILE -----"
|
#define PCP_ZFILE_HEADER "----- BEGIN Z85 ENCODED FILE -----"
|
||||||
#define PCP_ZFILE_FOOTER "------ END Z85 ENCODED FILE ------"
|
#define PCP_ZFILE_FOOTER "------ END Z85 ENCODED FILE ------"
|
||||||
|
|
||||||
#define PCP_SIG_HEADER "----- BEGIN PCP SIGNED MESSAGE -----"
|
#define PCP_SIG_HEADER "----- BEGIN ED25519 SIGNED MESSAGE -----"
|
||||||
#define PCP_SIG_START "----- BEGIN PCP SIGNATURE -----"
|
#define PCP_SIG_START "----- BEGIN ED25519 SIGNATURE -----"
|
||||||
#define PCP_SIG_END "------ END PCP SIGNATURE ------"
|
#define PCP_SIG_END "------ END ED25519 SIGNATURE ------"
|
||||||
|
#define PCP_SIGPREFIX "\nnacl-"
|
||||||
|
|
||||||
#define PCP_ME "Pretty Curved Privacy"
|
#define PCP_ME "Pretty Curved Privacy"
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
#include "keyhash.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
/* sign a message of messagesize using s->edsecret, if it works
|
/* sign a message of messagesize using s->edsecret, if it works
|
||||||
return message+signature (size: messagesize + crypto_sign_BYTES),
|
return message+signature (size: messagesize + crypto_sign_BYTES),
|
||||||
@@ -51,4 +53,9 @@ unsigned char * pcp_ed_verify(unsigned char *signature, size_t siglen, pcp_pubke
|
|||||||
sig only to the output */
|
sig only to the output */
|
||||||
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);
|
||||||
|
|
||||||
|
pcp_pubkey_t *pcp_ed_verify_buffered(FILE *in, pcp_pubkey_t *p);
|
||||||
|
|
||||||
|
size_t pcp_ed_detachsign_buffered(FILE *in, FILE *out, pcp_key_t *s);
|
||||||
|
pcp_pubkey_t *pcp_ed_detachverify_buffered(FILE *in, FILE *sigfd, pcp_pubkey_t *p);
|
||||||
|
|
||||||
#endif // _HAVE_PCP_ED_H
|
#endif // _HAVE_PCP_ED_H
|
||||||
|
|||||||
@@ -26,13 +26,36 @@
|
|||||||
#define _HAVE_PCP_UTIL_H
|
#define _HAVE_PCP_UTIL_H
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
|
// lowercase a string
|
||||||
static inline char *_lc(char *in) {
|
static inline char *_lc(char *in) {
|
||||||
size_t len = strlen(in);
|
size_t len = strlen(in);
|
||||||
int i;
|
size_t i;
|
||||||
for(i=0; i<len; ++i)
|
for(i=0; i<len; ++i)
|
||||||
in[i] = towlower(in[i]);
|
in[i] = towlower(in[i]);
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find the offset of the beginning of a certain string within binary data
|
||||||
|
static inline size_t _findoffset(unsigned char *bin, size_t binlen, char *sigstart, size_t hlen) {
|
||||||
|
size_t i;
|
||||||
|
size_t offset = 0;
|
||||||
|
int m = 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // _HAVE_PCP_UTIL_H
|
#endif // _HAVE_PCP_UTIL_H
|
||||||
|
|||||||
@@ -456,6 +456,4 @@ size_t pcp_decrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey) {
|
|||||||
fclose(out);
|
fclose(out);
|
||||||
|
|
||||||
return out_size;
|
return out_size;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
333
libpcp/ed.c
333
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,20 +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) {
|
||||||
if(in_buf[cur_bufsize] != '\n')
|
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);
|
||||||
fprintf(out, "\n");
|
|
||||||
fprintf(out, "%s\nVersion: 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)
|
||||||
@@ -97,5 +96,321 @@ size_t pcp_ed_sign_buffered(FILE *in, FILE *out, pcp_key_t *s, int z85) {
|
|||||||
|
|
||||||
free(st);
|
free(st);
|
||||||
|
|
||||||
return mlen; // ???
|
return outsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcp_pubkey_t *pcp_ed_verify_buffered(FILE *in, pcp_pubkey_t *p) {
|
||||||
|
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;
|
||||||
|
int gotsig = 0;
|
||||||
|
|
||||||
|
unsigned char hash[crypto_generichash_BYTES_MAX];
|
||||||
|
char zhead[] = PCP_SIG_HEADER;
|
||||||
|
size_t hlen = strlen(PCP_SIG_HEADER);
|
||||||
|
size_t hlen2 = 15; // hash: blake2\n\n
|
||||||
|
size_t mlen = + crypto_sign_BYTES + crypto_generichash_BYTES_MAX;
|
||||||
|
size_t zlen = 262; // FIXME: calculate
|
||||||
|
unsigned char z85encoded[zlen];
|
||||||
|
unsigned char sighash[mlen];
|
||||||
|
char z85sigstart[] = PCP_SIG_START;
|
||||||
|
char binsigstart[] = PCP_SIGPREFIX;
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* use two half blocks, to overcome sigs spanning block boundaries */
|
||||||
|
cur_bufsize = fread(&in_buf, 1, PCP_BLOCK_SIZE/2, in);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if(z85) {
|
||||||
|
char *z85block = pcp_readz85string(z85encoded, zlen);
|
||||||
|
if(z85block == NULL)
|
||||||
|
goto errvb1;
|
||||||
|
|
||||||
|
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(got: %ld, expected: %ld)\n", dstlen, mlen);
|
||||||
|
goto errvb1;
|
||||||
|
}
|
||||||
|
memcpy(sighash, z85decoded, mlen);
|
||||||
|
}
|
||||||
|
// else: if unarmored, sighash is already filled
|
||||||
|
|
||||||
|
|
||||||
|
// huh, how did we made it til here?
|
||||||
|
unsigned char *verifiedhash = NULL;
|
||||||
|
if(p == NULL) {
|
||||||
|
pcphash_iteratepub(p) {
|
||||||
|
verifiedhash = pcp_ed_verify(sighash, mlen, p);
|
||||||
|
if(verifiedhash != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
verifiedhash = pcp_ed_verify(sighash, mlen, 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 actual hash of signed file content\n");
|
||||||
|
free(verifiedhash);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
|
||||||
|
|
||||||
|
errvb1:
|
||||||
|
free(st);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t pcp_ed_detachsign_buffered(FILE *in, FILE *out, pcp_key_t *s) {
|
||||||
|
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];
|
||||||
|
|
||||||
|
crypto_generichash_init(st, NULL, 0, 0);
|
||||||
|
|
||||||
|
while(!feof(in)) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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, mlen, &zlen);
|
||||||
|
fprintf(out, "%s\n%s\n", z85encoded, PCP_SIG_END);
|
||||||
|
|
||||||
|
if(fileno(in) != 0)
|
||||||
|
fclose(in);
|
||||||
|
if(fileno(out) != 1)
|
||||||
|
fclose(out);
|
||||||
|
|
||||||
|
free(st);
|
||||||
|
|
||||||
|
return outsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcp_pubkey_t *pcp_ed_detachverify_buffered(FILE *in, FILE *sigfd, pcp_pubkey_t *p) {
|
||||||
|
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];
|
||||||
|
size_t mlen = + crypto_sign_BYTES + crypto_generichash_BYTES_MAX;
|
||||||
|
|
||||||
|
crypto_generichash_init(st, NULL, 0, 0);
|
||||||
|
|
||||||
|
while(!feof(in)) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
crypto_generichash_final(st, hash, crypto_generichash_BYTES_MAX);
|
||||||
|
|
||||||
|
// read the sig
|
||||||
|
unsigned char *sig = NULL;
|
||||||
|
size_t inputBufSize = 0;
|
||||||
|
unsigned char byte[1];
|
||||||
|
|
||||||
|
while(!feof(sigfd)) {
|
||||||
|
if(!fread(&byte, 1, 1, sigfd))
|
||||||
|
break;
|
||||||
|
unsigned char *tmp = realloc(sig, inputBufSize + 1);
|
||||||
|
sig = tmp;
|
||||||
|
memmove(&sig[inputBufSize], byte, 1);
|
||||||
|
inputBufSize ++;
|
||||||
|
}
|
||||||
|
fclose(sigfd);
|
||||||
|
|
||||||
|
if(sig == NULL) {
|
||||||
|
fatal("Invalid detached signature\n");
|
||||||
|
goto errdea1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *z85block = pcp_readz85string(sig, inputBufSize);
|
||||||
|
if(z85block == NULL)
|
||||||
|
goto errdea2;
|
||||||
|
|
||||||
|
size_t clen;
|
||||||
|
unsigned char *sighash = pcp_z85_decode(z85block, &clen);
|
||||||
|
if(sighash == NULL)
|
||||||
|
goto errdea3;
|
||||||
|
|
||||||
|
if(clen != mlen) {
|
||||||
|
fatal("z85 decoded signature didn't result in a proper signed hash(got: %ld, expected: %ld)\n", clen, mlen);
|
||||||
|
goto errdea4;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *verifiedhash = NULL;
|
||||||
|
if(p == NULL) {
|
||||||
|
pcphash_iteratepub(p) {
|
||||||
|
verifiedhash = pcp_ed_verify(sighash, mlen, p);
|
||||||
|
if(verifiedhash != NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
verifiedhash = pcp_ed_verify(sighash, mlen, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(verifiedhash == NULL)
|
||||||
|
goto errdea4;
|
||||||
|
|
||||||
|
if(memcmp(verifiedhash, hash, crypto_generichash_BYTES_MAX) != 0) {
|
||||||
|
// sig verified, but the hash doesn't
|
||||||
|
fatal("signed hash doesn't match actual hash of signed file content\n");
|
||||||
|
goto errdea5;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(verifiedhash);
|
||||||
|
free(sighash);
|
||||||
|
free(z85block);
|
||||||
|
free(sig);
|
||||||
|
return p;
|
||||||
|
|
||||||
|
|
||||||
|
errdea5:
|
||||||
|
free(verifiedhash);
|
||||||
|
|
||||||
|
errdea4:
|
||||||
|
free(sighash);
|
||||||
|
|
||||||
|
errdea3:
|
||||||
|
free(z85block);
|
||||||
|
|
||||||
|
errdea2:
|
||||||
|
free(sig);
|
||||||
|
|
||||||
|
errdea1:
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, plist_t *rec
|
|||||||
size_t clen = 0;
|
size_t clen = 0;
|
||||||
|
|
||||||
if(self == 1)
|
if(self == 1)
|
||||||
pcp_encrypt_file_sym(in, out, symkey, 0);
|
clen = pcp_encrypt_file_sym(in, out, symkey, 0);
|
||||||
else
|
else
|
||||||
clen = pcp_encrypt_file(in, out, secret, pubhash);
|
clen = pcp_encrypt_file(in, out, secret, pubhash);
|
||||||
|
|
||||||
|
|||||||
20
src/pcp.c
20
src/pcp.c
@@ -44,10 +44,11 @@ char *default_vault() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char **argv) {
|
int main (int argc, char **argv) {
|
||||||
int opt, mode, usevault, useid, userec, lo, armor;
|
int opt, mode, usevault, useid, userec, lo, armor, detach;
|
||||||
char *vaultfile = default_vault();
|
char *vaultfile = default_vault();
|
||||||
char *outfile = NULL;
|
char *outfile = NULL;
|
||||||
char *infile = NULL;
|
char *infile = NULL;
|
||||||
|
char *sigfile = NULL;
|
||||||
char *keyid = NULL;
|
char *keyid = NULL;
|
||||||
char *id = NULL;
|
char *id = NULL;
|
||||||
char *xpass = NULL;
|
char *xpass = NULL;
|
||||||
@@ -63,6 +64,7 @@ int main (int argc, char **argv) {
|
|||||||
userec = 0;
|
userec = 0;
|
||||||
lo = 0;
|
lo = 0;
|
||||||
armor = 0;
|
armor = 0;
|
||||||
|
detach = 0;
|
||||||
|
|
||||||
static struct option longopts[] = {
|
static struct option longopts[] = {
|
||||||
// generics
|
// generics
|
||||||
@@ -101,11 +103,12 @@ int main (int argc, char **argv) {
|
|||||||
|
|
||||||
// signing
|
// signing
|
||||||
{ "sign", no_argument, NULL, 'g' },
|
{ "sign", no_argument, NULL, 'g' },
|
||||||
{ "check-signature", no_argument, NULL, 'c' },
|
{ "check-signature", required_argument, NULL, 'c' },
|
||||||
|
{ "detach", no_argument, NULL, 'a' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
while ((opt = getopt_long(argc, argv, "klV:vdehsO:i:I:pSPRtEx:DzZr:gcym",
|
while ((opt = getopt_long(argc, argv, "klV:vdehsO:i:I:pSPRtEx:DzZr:gc:yma",
|
||||||
longopts, NULL)) != -1) {
|
longopts, NULL)) != -1) {
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
@@ -171,12 +174,17 @@ int main (int argc, char **argv) {
|
|||||||
case 'Z':
|
case 'Z':
|
||||||
armor = 1;
|
armor = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'a':
|
||||||
|
detach = 1;
|
||||||
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
mode += PCP_MODE_SIGN;
|
mode += PCP_MODE_SIGN;
|
||||||
usevault = 1;
|
usevault = 1;
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
mode += PCP_MODE_VERIFY;
|
mode += PCP_MODE_VERIFY;
|
||||||
|
sigfile = ucmalloc(strlen(optarg)+1);
|
||||||
|
strncpy(sigfile, optarg, strlen(optarg)+1);
|
||||||
usevault = 1;
|
usevault = 1;
|
||||||
break;
|
break;
|
||||||
case 'y':
|
case 'y':
|
||||||
@@ -372,19 +380,19 @@ int main (int argc, char **argv) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PCP_MODE_SIGN:
|
case PCP_MODE_SIGN:
|
||||||
pcpsign(infile, outfile, xpass, armor);
|
pcpsign(infile, outfile, xpass, armor, detach);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCP_MODE_VERIFY:
|
case PCP_MODE_VERIFY:
|
||||||
if(useid) {
|
if(useid) {
|
||||||
id = pcp_normalize_id(keyid);
|
id = pcp_normalize_id(keyid);
|
||||||
if(id != NULL) {
|
if(id != NULL) {
|
||||||
pcpverify(infile, id);
|
pcpverify(infile, sigfile, id, detach);
|
||||||
free(id);
|
free(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pcpverify(infile, NULL);
|
pcpverify(infile, sigfile, NULL, detach);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,14 @@
|
|||||||
#include "signature.h"
|
#include "signature.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
int pcpsign(char *infile, char *outfile, char *passwd, int z85) {
|
|
||||||
|
int pcpsign(char *infile, char *outfile, char *passwd, int z85, int detach) {
|
||||||
FILE *in = NULL;
|
FILE *in = NULL;
|
||||||
FILE *out = NULL;
|
FILE *out = NULL;
|
||||||
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;
|
||||||
@@ -69,7 +71,11 @@ int pcpsign(char *infile, char *outfile, char *passwd, int z85) {
|
|||||||
goto errs1;
|
goto errs1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t sigsize = pcp_ed_sign_buffered(in, out, secret, z85);
|
size_t sigsize;
|
||||||
|
if(detach == 1)
|
||||||
|
sigsize = pcp_ed_detachsign_buffered(in, out, secret);
|
||||||
|
else
|
||||||
|
sigsize = pcp_ed_sign_buffered(in, out, secret, z85);
|
||||||
|
|
||||||
if(sigsize == 0)
|
if(sigsize == 0)
|
||||||
goto errs1;
|
goto errs1;
|
||||||
@@ -82,10 +88,10 @@ int pcpsign(char *infile, char *outfile, char *passwd, int z85) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pcpverify(char *infile, char *id) {
|
int pcpverify(char *infile, char *sigfile, char *id, int detach) {
|
||||||
FILE *in = NULL;
|
FILE *in = NULL;
|
||||||
|
FILE *sigfd = NULL;
|
||||||
pcp_pubkey_t *pub = NULL;
|
pcp_pubkey_t *pub = NULL;
|
||||||
unsigned char *message = NULL;
|
|
||||||
|
|
||||||
if(infile == NULL)
|
if(infile == NULL)
|
||||||
in = stdin;
|
in = stdin;
|
||||||
@@ -96,63 +102,26 @@ int pcpverify(char *infile, char *id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(sigfile != NULL) {
|
||||||
|
if((sigfd = fopen(sigfile, "rb")) == NULL) {
|
||||||
|
fatal("Could not open signature file %s\n", sigfile);
|
||||||
|
goto errv1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(id != NULL)
|
if(id != NULL)
|
||||||
HASH_FIND_STR(pcppubkey_hash, id, pub);
|
HASH_FIND_STR(pcppubkey_hash, id, pub);
|
||||||
|
|
||||||
/*
|
if(detach)
|
||||||
if(pub == NULL) {
|
pub = pcp_ed_detachverify_buffered(in, sigfd, pub);
|
||||||
fatal("Could not find a usable public key in vault %s!\n",
|
|
||||||
vault->filename);
|
|
||||||
goto errv3;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsigned char *input = NULL;
|
|
||||||
size_t inputBufSize = 0;
|
|
||||||
unsigned char byte[1];
|
|
||||||
|
|
||||||
while(!feof(in)) {
|
|
||||||
if(!fread(&byte, 1, 1, in))
|
|
||||||
break;
|
|
||||||
unsigned char *tmp = realloc(input, inputBufSize + 1);
|
|
||||||
input = tmp;
|
|
||||||
memmove(&input[inputBufSize], byte, 1);
|
|
||||||
inputBufSize ++;
|
|
||||||
}
|
|
||||||
fclose(in);
|
|
||||||
|
|
||||||
if(inputBufSize == 0) {
|
|
||||||
fatal("Input file is empty!\n");
|
|
||||||
goto errv4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pub != NULL) {
|
|
||||||
message = pcp_ed_verify(input, inputBufSize, pub);
|
|
||||||
if(message != NULL) {
|
|
||||||
fprintf(stderr, "Signature verified (signed by %s <%s>).\n", pub->owner, pub->mail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pcphash_iteratepub(pub) {
|
|
||||||
message = pcp_ed_verify(input, inputBufSize, pub);
|
|
||||||
if(message != NULL) {
|
|
||||||
fprintf(stderr, "Signature verified (signed by %s <%s>).\n", pub->owner, pub->mail);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(message == NULL) {
|
|
||||||
fprintf(stderr, "Could not verify ignature\n");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
free(message);
|
pub = pcp_ed_verify_buffered(sigfd, pub);
|
||||||
|
|
||||||
free(input);
|
if(pub != NULL)
|
||||||
return 0;
|
fprintf(stderr, "Signature verified (signed by %s <%s>).\n", pub->owner, pub->mail);
|
||||||
|
|
||||||
|
|
||||||
errv4:
|
errv4:
|
||||||
free(input);
|
|
||||||
|
|
||||||
errv1:
|
errv1:
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -32,8 +32,8 @@
|
|||||||
#include "uthash.h"
|
#include "uthash.h"
|
||||||
#include "z85.h"
|
#include "z85.h"
|
||||||
|
|
||||||
int pcpsign(char *infile, char *outfile, char *passwd, int z85);
|
int pcpsign(char *infile, char *outfile, char *passwd, int z85, int detach);
|
||||||
int pcpverify(char *infile, char *id);
|
int pcpverify(char *infile, char *sigfile, char *id, int detach);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -92,11 +92,15 @@ Signature Options:
|
|||||||
-I (or from stdin) using your primary
|
-I (or from stdin) using your primary
|
||||||
secret key. If -r has been given, a derived
|
secret key. If -r has been given, a derived
|
||||||
secret key will be used for signing.
|
secret key will be used for signing.
|
||||||
|
|
||||||
-c --check-signature <file> Verify a signature in file <file> against
|
-c --check-signature <file> Verify a signature in file <file> against
|
||||||
the file specified with -I (or stdin).
|
the file specified with -I (or stdin).
|
||||||
The public key required for this must
|
The public key required for this must
|
||||||
exist in your vault file.
|
exist in your vault file.
|
||||||
|
-a --detach Write a detached signature file, which doesn't
|
||||||
|
contain the original content. Output will be
|
||||||
|
z85 encoded always. To verify, you need to
|
||||||
|
specify the original file to be verified
|
||||||
|
against using -I as well (plus -a).
|
||||||
|
|
||||||
Encoding Options:
|
Encoding Options:
|
||||||
-z --z85-encode Encode something to Z85 encoding. Use
|
-z --z85-encode Encode something to Z85 encoding. Use
|
||||||
|
|||||||
@@ -210,13 +210,31 @@ dxmorg@florida.cops.gov
|
|||||||
</test>
|
</test>
|
||||||
|
|
||||||
#
|
#
|
||||||
# signature test
|
# signature tests
|
||||||
<test check-sign-to-bobby>
|
<test check-sign-detached-to-bobby>
|
||||||
|
cmd = $pcp -V va -g -I README -O testsig -x a -a
|
||||||
|
expect-file testsig
|
||||||
|
</test>
|
||||||
|
<test check-verify-detached-signature>
|
||||||
|
cmd = $pcp -V vb -c testsig -I README -i $idalicia -a
|
||||||
|
expect = /verified/
|
||||||
|
</test>
|
||||||
|
<test check-sign-armored-to-bobby>
|
||||||
|
prepare = rm -f testsig
|
||||||
|
cmd = $pcp -V va -g -I README -O testsig -x a -z
|
||||||
|
expect-file testsig
|
||||||
|
</test>
|
||||||
|
<test check-verify-armored-signature>
|
||||||
|
cmd = $pcp -V vb -c testsig -i $idalicia -z
|
||||||
|
expect = /verified/
|
||||||
|
</test>
|
||||||
|
<test check-sign-bin-to-bobby>
|
||||||
|
prepare = rm -f testsig
|
||||||
cmd = $pcp -V va -g -I README -O testsig -x a
|
cmd = $pcp -V va -g -I README -O testsig -x a
|
||||||
expect-file testsig
|
expect-file testsig
|
||||||
</test>
|
</test>
|
||||||
<test check-verify-signature>
|
<test check-verify-bin-signature>
|
||||||
cmd = $pcp -V vb -c -I testsig -i $idalicia
|
cmd = $pcp -V vb -c testsig -i $idalicia
|
||||||
expect = /verified/
|
expect = /verified/
|
||||||
</test>
|
</test>
|
||||||
|
|
||||||
@@ -332,12 +350,15 @@ dxmorg@florida.cops.gov
|
|||||||
</test>
|
</test>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disabled, since z85 standalone mode currently disabled
|
||||||
<test check-if-catch-nokey-behind-z85>
|
<test check-if-catch-nokey-behind-z85>
|
||||||
prepare = ./jot 30 | while read ignore; do echo XXXXX; done \
|
prepare = ./jot 30 | while read ignore; do echo XXXXX; done \
|
||||||
| $pcp -z > testfile-nokey
|
| $pcp -z > testfile-nokey
|
||||||
cmd = $pcp -V $vault -P -I testfile-nokey
|
cmd = $pcp -V $vault -P -I testfile-nokey
|
||||||
expect = /result to a proper sized key/
|
expect = /result to a proper sized key/
|
||||||
</test>
|
</test>
|
||||||
|
*/
|
||||||
|
|
||||||
<test check-if-sanity-catch-nosecret>
|
<test check-if-sanity-catch-nosecret>
|
||||||
cmd = $pcp -V $vault -S -I bart.pub
|
cmd = $pcp -V $vault -S -I bart.pub
|
||||||
|
|||||||
Reference in New Issue
Block a user