From a89b16a15c76c86168cfd45aff46b87ceedd18d2 Mon Sep 17 00:00:00 2001 From: "git@daemon.de" Date: Wed, 5 Feb 2014 13:09:20 +0100 Subject: [PATCH] fixed crypt+sign, now the sig contains the encrypted recipient list as well and is encrypted itself --- include/pcp/crypto.h | 7 +- include/pcp/defines.h | 2 +- include/pcp/key.h | 15 +++++ libpcp/crypto.c | 147 +++++++++++++++++++++++++++++++++--------- src/encryption.c | 5 +- 5 files changed, 138 insertions(+), 38 deletions(-) diff --git a/include/pcp/crypto.h b/include/pcp/crypto.h index 9a9ed1f..035910d 100644 --- a/include/pcp/crypto.h +++ b/include/pcp/crypto.h @@ -58,8 +58,11 @@ size_t pcp_encrypt_file(FILE *in, FILE* out, pcp_key_t *s, pcp_pubkey_t *p, int size_t pcp_decrypt_file(FILE *in, FILE* out, pcp_key_t *s, unsigned char *symkey, int verify); -size_t pcp_encrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, int havehead, pcp_key_t *signkey); +size_t pcp_encrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, int havehead, pcp_rec_t *recsign); -size_t pcp_decrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, pcp_pubkey_t *verifykey); +size_t pcp_decrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, pcp_rec_t *recverify); + +pcp_rec_t *pcp_rec_new(unsigned char *cipher, size_t clen, pcp_key_t *secret, pcp_pubkey_t *pub); +void pcp_rec_free(pcp_rec_t *r); #endif // _HAVE_PCP_CRYPTO_H diff --git a/include/pcp/defines.h b/include/pcp/defines.h index ff298bf..08b4530 100644 --- a/include/pcp/defines.h +++ b/include/pcp/defines.h @@ -81,7 +81,7 @@ typedef unsigned int qbyte; // Quad byte = 32 bits #define PCP_CRYPTO_ADD (crypto_box_ZEROBYTES - crypto_box_BOXZEROBYTES) #define PCP_BLOCK_SIZE_IN (PCP_BLOCK_SIZE) + PCP_CRYPTO_ADD + crypto_secretbox_NONCEBYTES -#define PCP_ASYM_RECIPIENT_SIZE crypto_secretbox_KEYBYTES + PCP_CRYPTO_ADD + crypto_secretbox_NONCEBYTES +#define PCP_ASYM_RECIPIENT_SIZE crypto_secretbox_KEYBYTES + PCP_CRYPTO_ADD + crypto_secretbox_NONCEBYTES //#define PCP_ASYM_ADD_SENDER_PUB // used for self encryption only diff --git a/include/pcp/key.h b/include/pcp/key.h index 7b9a04d..a1b7444 100644 --- a/include/pcp/key.h +++ b/include/pcp/key.h @@ -113,10 +113,25 @@ struct _pbp_pubkey_t { char name[1024]; }; + typedef struct _pcp_key_t pcp_key_t; typedef struct _pcp_pubkey_t pcp_pubkey_t; typedef struct _pbp_pubkey_t pbp_pubkey_t; +/* + encrypted recipient list, required for crypt+sign + contains the encrypted recipients and the secret + key required for signing the message+recipients. +*/ +struct _pcp_rec_t { + size_t ciphersize; + byte *cipher; + pcp_key_t *secret; + pcp_pubkey_t *pub; +}; + +typedef struct _pcp_rec_t pcp_rec_t; + #define PCP_RAW_KEYSIZE sizeof(pcp_key_t) - sizeof(UT_hash_handle) #define PCP_RAW_PUBKEYSIZE sizeof(pcp_pubkey_t) - sizeof(UT_hash_handle) diff --git a/libpcp/crypto.c b/libpcp/crypto.c index 21ec728..49d4a14 100644 --- a/libpcp/crypto.c +++ b/libpcp/crypto.c @@ -165,6 +165,7 @@ unsigned char *pcp_box_decrypt(pcp_key_t *secret, pcp_pubkey_t *pub, size_t pcp_decrypt_file(FILE *in, FILE* out, pcp_key_t *s, unsigned char *symkey, int verify) { pcp_pubkey_t *cur = NULL; pcp_pubkey_t *sender = NULL; + unsigned char *reccipher = NULL; int nrec, recmatch; uint32_t lenrec; byte head[1]; @@ -222,6 +223,10 @@ size_t pcp_decrypt_file(FILE *in, FILE* out, pcp_key_t *s, unsigned char *symkey } lenrec = be32toh(lenrec); + if(verify) { + reccipher = ucmalloc(lenrec * PCP_ASYM_RECIPIENT_SIZE); + } + // step 4, fetch recipient list and try to decrypt it for us for(nrec=0; nreccipher, recsign->ciphersize); crypto_generichash_final(st, hash, crypto_generichash_BYTES_MAX); - unsigned char *signature = pcp_ed_sign(hash, crypto_generichash_BYTES_MAX, signkey); + + /* generate the actual signature */ + unsigned char *signature = pcp_ed_sign(hash, crypto_generichash_BYTES_MAX, recsign->secret); size_t siglen = crypto_sign_BYTES + crypto_generichash_BYTES_MAX; - fwrite(signature, siglen, 1, out); + + /* encrypt it as well */ + buf_nonce = pcp_gennonce(); + es = pcp_sodium_mac(&buf_cipher, signature, siglen, buf_nonce, symkey); + fwrite(buf_nonce, crypto_secretbox_NONCEBYTES, 1, out); + fwrite(buf_cipher, es, 1, out); + free(st); free(signature); free(hash); @@ -461,7 +487,7 @@ size_t pcp_encrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, int have return 0; } -size_t pcp_decrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, pcp_pubkey_t *verifykey) { +size_t pcp_decrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, pcp_rec_t *recverify) { unsigned char *buf_nonce; unsigned char *buf_cipher; unsigned char *buf_clear; @@ -474,15 +500,17 @@ size_t pcp_decrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, pcp_pubk out_size = 0; unsigned char *signature = NULL; + unsigned char *signature_cr = NULL; size_t siglen = crypto_sign_BYTES + crypto_generichash_BYTES_MAX; + size_t siglen_cr = siglen + PCP_CRYPTO_ADD + crypto_secretbox_NONCEBYTES; crypto_generichash_state *st = NULL; unsigned char *hash = NULL; - if(verifykey != NULL) { + if(recverify != NULL) { st = ucmalloc(sizeof(crypto_generichash_state)); hash = ucmalloc(crypto_generichash_BYTES_MAX); crypto_generichash_init(st, NULL, 0, 0); - signature = ucmalloc(siglen); + signature_cr = ucmalloc(siglen_cr); } #ifdef PCP_CBC @@ -494,11 +522,11 @@ size_t pcp_decrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, pcp_pubk if(cur_bufsize <= PCP_CRYPTO_ADD) break; // no valid cipher block - if(verifykey != NULL) { + if(recverify != NULL) { if(cur_bufsize < PCP_BLOCK_SIZE_IN || feof(in)) { // pull out signature - memcpy(signature, &in_buf[cur_bufsize - siglen], siglen); - cur_bufsize -= siglen; + memcpy(signature_cr, &in_buf[cur_bufsize - siglen_cr], siglen_cr); + cur_bufsize -= siglen_cr; } } @@ -527,7 +555,7 @@ size_t pcp_decrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, pcp_pubk if(es == 0) { fwrite(buf_clear, ciphersize - PCP_CRYPTO_ADD, 1, out); - if(verifykey != NULL) + if(recverify != NULL) crypto_generichash_update(st, buf_clear, ciphersize - PCP_CRYPTO_ADD); free(buf_clear); @@ -553,23 +581,37 @@ size_t pcp_decrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, pcp_pubk free(buf_nonce); free(buf_cipher); - if(verifykey != NULL) { - crypto_generichash_final(st, hash, crypto_generichash_BYTES_MAX); - unsigned char *verifiedhash = NULL; - verifiedhash = pcp_ed_verify(signature, siglen, verifykey); - if(verifiedhash == NULL) - out_size = 0; - else { - if(memcmp(verifiedhash, hash, crypto_generichash_BYTES_MAX) != 0) { - // sig verified, but the hash doesn't match - fatal("signed hash doesn't match actual hash of signed decrypted file content\n"); + if(recverify != NULL) { + /* decrypt the signature */ + memcpy(buf_nonce, signature_cr, crypto_secretbox_NONCEBYTES); + es = pcp_sodium_verify_mac(&signature, &signature_cr[crypto_secretbox_NONCEBYTES], + siglen_cr - crypto_secretbox_NONCEBYTES, buf_nonce, symkey); + if(es == 0) { + /* add encrypted recipient list to the hash */ + crypto_generichash_update(st, recverify->cipher, recverify->ciphersize); + crypto_generichash_final(st, hash, crypto_generichash_BYTES_MAX); + + unsigned char *verifiedhash = NULL; + verifiedhash = pcp_ed_verify(signature, siglen, recverify->pub); + if(verifiedhash == NULL) out_size = 0; + else { + if(memcmp(verifiedhash, hash, crypto_generichash_BYTES_MAX) != 0) { + // sig verified, but the hash doesn't match + fatal("signed hash doesn't match actual hash of signed decrypted file content\n"); + out_size = 0; + } + free(verifiedhash); } - free(verifiedhash); + } + else { + fatal("Failed to decrypt signature!\n"); + out_size = 0; } free(st); free(hash); free(signature); + free(signature_cr); } if(fileno(in) != 0) @@ -580,3 +622,44 @@ size_t pcp_decrypt_file_sym(FILE *in, FILE* out, unsigned char *symkey, pcp_pubk return out_size; } + +pcp_rec_t *pcp_rec_new(unsigned char *cipher, size_t clen, pcp_key_t *secret, pcp_pubkey_t *pub) { + pcp_rec_t *r = ucmalloc(sizeof(pcp_rec_t)); + r->cipher = ucmalloc(clen); + memcpy(r->cipher, cipher, clen); + r->ciphersize = clen; + + if(secret != NULL) { + r->secret = ucmalloc(sizeof(pcp_key_t)); + memcpy(r->secret, secret, sizeof(pcp_key_t)); + } + else + r->secret = NULL; + + if(pub != NULL) { + r->pub = ucmalloc(sizeof(pcp_key_t)); + memcpy(r->pub, pub, sizeof(pcp_key_t)); + } + else + r->pub = NULL; + + + return r; +} + +void pcp_rec_free(pcp_rec_t *r) { + free(r->cipher); + + if(r->secret != NULL) { + memset(r->secret, 0, sizeof(pcp_key_t)); + free(r->secret); + } + + if(r->pub != NULL) { + memset(r->pub, 0, sizeof(pcp_pubkey_t)); + free(r->pub); + } + + free(r); +} + diff --git a/src/encryption.c b/src/encryption.c index 593bb5e..f825fe5 100644 --- a/src/encryption.c +++ b/src/encryption.c @@ -160,8 +160,7 @@ int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, plist_t *rec symkey = pcp_scrypt(passphrase, crypto_secretbox_KEYBYTES, salt, 90); free(salt); } - else if(id != NULL) { - // FIXME: mk id a plist_t with loop as well + else if(id != NULL && recipient == NULL) { // lookup by id HASH_FIND_STR(pcppubkey_hash, id, tmp); if(tmp == NULL) { @@ -193,7 +192,7 @@ int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, plist_t *rec plist_t *rec; pcphash_iteratepub(tmp) { rec = recipient->first; - while (rec->next != NULL) { + while (rec != NULL) { _lc(rec->value); if(strnstr(tmp->mail, rec->value, 255) != NULL || strnstr(tmp->owner, rec->value, 255) != NULL) { pub = ucmalloc(sizeof(pcp_pubkey_t));