diff --git a/ChangeLog b/ChangeLog index 669de9c..32e0bc8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +0.2.3 Z85 block encoding changed. 4 bytes are appended + to each input block to denote if and how many + zeroes have been used for padding, necessary + since z85 doesn't have any native padding scheme, + and only padding with zeroes is insuffucient. This + change breaks - currently - compatibility to pbp. + + Added new option --anonymous (-A) which uses a + generated keypair for encryption and puts the + public part into the encrypted message. + + Fixed lots of memory leaks. + 0.2.2 Enhanded --edit-key a little, it's now possible to make a secret the primary one. diff --git a/bindings/cpp/crypto.cpp b/bindings/cpp/crypto.cpp index 5cdc58e..0d8cbb5 100644 --- a/bindings/cpp/crypto.cpp +++ b/bindings/cpp/crypto.cpp @@ -54,7 +54,7 @@ bool Crypto::encrypt(FILE *in, FILE *out, bool sign) { Pcpstream *pin = ps_new_file(in); Pcpstream *pout = ps_new_file(out); - size_t clen = pcp_encrypt_stream(PTX->ptx, pin, pout, S.K, pubhash, sign); + size_t clen = pcp_encrypt_stream(PTX->ptx, pin, pout, S.K, pubhash, sign, 0); // FIXME: add anon support if(clen <= 0) throw exception(PTX); ps_close(pin); @@ -66,7 +66,7 @@ bool Crypto::decrypt(FILE *in, FILE *out, bool verify) { Pcpstream *pin = ps_new_file(in); Pcpstream *pout = ps_new_file(out); - if(pcp_decrypt_stream(PTX->ptx, pin, pout, S.K, NULL, verify) <= 0) + if(pcp_decrypt_stream(PTX->ptx, pin, pout, S.K, NULL, verify, 0) <= 0) throw exception(PTX); ps_close(pin); ps_close(pout); diff --git a/include/pcp/crypto.h b/include/pcp/crypto.h index 07a6938..3ab2575 100644 --- a/include/pcp/crypto.h +++ b/include/pcp/crypto.h @@ -195,11 +195,13 @@ byte *pcp_box_decrypt(PCPCTX *ptx, pcp_key_t *secret, pcp_pubkey_t *pub, \param[in] p Public key hash containing a list of the recipients. - \param signcrypt Flag to indicate sign+crypt. If 1 it adds a signature, otherwise not. + \param[in] signcrypt Flag to indicate sign+crypt. If 1 it adds a signature, otherwise not. + + \param[in] anon Flag to indicate if using anonymous sender key. 0 retains std behaviour, not anon. \return Returns the size of the output written to the output stream or 0 in case of errors. */ -size_t pcp_encrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, pcp_key_t *s, pcp_pubkey_t *p, int signcrypt); +size_t pcp_encrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, pcp_key_t *s, pcp_pubkey_t *p, int signcrypt, int anon); /** Symmetrically encrypt a file or a buffer stream. @@ -248,9 +250,11 @@ size_t pcp_encrypt_stream_sym(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, byte * \param verify Flag to indicate sign+crypt. If 1 it tries to verify a signature, otherwise not. + \param[in] anon Flag to indicate if using anonymous sender key. 0 retains std behaviour, not anon. + \return Returns the size of the output written to the output stream or 0 in case of errors. */ -size_t pcp_decrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, pcp_key_t *s, byte *symkey, int verify); +size_t pcp_decrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, pcp_key_t *s, byte *symkey, int verify, int anon); /** Symmetrically decrypt a file or a buffer stream. diff --git a/include/pcp/defines.h b/include/pcp/defines.h index a3bc158..89583b0 100644 --- a/include/pcp/defines.h +++ b/include/pcp/defines.h @@ -117,12 +117,14 @@ typedef enum _PCP_KEY_TYPES { /* enabled via config.h (configure --enable-cbc) */ #ifndef PCP_CBC #define PCP_ASYM_CIPHER 5 + #define PCP_ASYM_CIPHER_ANON 6 #define PCP_SYM_CIPHER 23 #define PCP_ASYM_CIPHER_SIG 24 #define PCP_BLOCK_SIZE 32 * 1024 #else /* CBC mode, use smaller blocks */ #define PCP_ASYM_CIPHER 7 + #define PCP_ASYM_CIPHER_ANON 9 #define PCP_ASYM_CIPHER_SIG 8 #define PCP_SYM_CIPHER 25 #define PCP_BLOCK_SIZE 1 * 1024 diff --git a/include/pcp/version.h b/include/pcp/version.h index b3a672d..b570027 100644 --- a/include/pcp/version.h +++ b/include/pcp/version.h @@ -25,7 +25,7 @@ #define PCP_VERSION_MAJOR 0 #define PCP_VERSION_MINOR 2 -#define PCP_VERSION_PATCH 2 +#define PCP_VERSION_PATCH 3 #define PCP_MAKE_VERSION(major, minor, patch) \ ((major) * 10000 + (minor) * 100 + (patch)) diff --git a/libpcp/crypto.c b/libpcp/crypto.c index 9460064..9032887 100644 --- a/libpcp/crypto.c +++ b/libpcp/crypto.c @@ -161,19 +161,15 @@ byte *pcp_box_decrypt(PCPCTX *ptx, pcp_key_t *secret, pcp_pubkey_t *pub, return NULL; } -size_t pcp_decrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, pcp_key_t *s, byte *symkey, int verify) { +size_t pcp_decrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, pcp_key_t *s, byte *symkey, int verify, int anon) { pcp_pubkey_t *cur = NULL; byte *reccipher = NULL; int recmatch, self; uint32_t lenrec; byte head[1]; size_t cur_bufsize, rec_size, nrec; - byte *rec_buf = NULL; - -#ifdef PCP_ASYM_ADD_SENDER_PUB - byte *senderpub; -#endif + pcp_pubkey_t *senderpub = NULL; /* anon only */ nrec = recmatch = self = 0; @@ -194,6 +190,10 @@ size_t pcp_decrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, pcp_key_t goto errdef1; } } + else if(head[0] == PCP_ASYM_CIPHER_ANON) { + self = 0; + anon = 1; + } else if(head[0] == PCP_ASYM_CIPHER) { self = 0; } @@ -213,14 +213,15 @@ size_t pcp_decrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, pcp_key_t return pcp_decrypt_stream_sym(ptx, in, out, symkey, NULL); } -#ifdef PCP_ASYM_ADD_SENDER_PUB - /* step 2, sender's pubkey */ - cur_bufsize = ps_read(in, &in_buf, crypto_box_PUBLICKEYBYTES); - if(cur_bufsize != crypto_box_PUBLICKEYBYTES && !ps_end(in) && !ps_err(in)) { - fatal(ptx, "Error: input file doesn't contain senders public key\n"); - goto errdef1; + if(anon) { + /* step 2, sender's pubkey */ + senderpub = ucmalloc(sizeof(pcp_pubkey_t)); + cur_bufsize = ps_read(in, senderpub->pub, crypto_box_PUBLICKEYBYTES); + if(cur_bufsize != crypto_box_PUBLICKEYBYTES && !ps_end(in) && !ps_err(in)) { + fatal(ptx, "Error: input file doesn't contain senders public key\n"); + goto errdef1; + } } -#endif /* step 3, check len recipients */ cur_bufsize = ps_read(in, &lenrec, 4); /* fread(&lenrec, 1, 4, in); */ @@ -247,17 +248,36 @@ size_t pcp_decrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, pcp_key_t } recmatch = 0; - pcphash_iteratepub(ptx, cur) { + if(anon) { + /* anonymous sender */ byte *recipient; - recipient = pcp_box_decrypt(ptx, s, cur, rec_buf, PCP_ASYM_RECIPIENT_SIZE, &rec_size); + recipient = pcp_box_decrypt(ptx, s, senderpub, rec_buf, PCP_ASYM_RECIPIENT_SIZE, &rec_size); if(recipient != NULL && rec_size == crypto_secretbox_KEYBYTES) { /* found a match */ recmatch = 1; symkey = ucmalloc(crypto_secretbox_KEYBYTES); memcpy(symkey, recipient, crypto_secretbox_KEYBYTES); free(recipient); + ucfree(senderpub, sizeof(pcp_pubkey_t)); break; } + free(recipient); + } + else { + /* dig through our list of known public keys for a match */ + pcphash_iteratepub(ptx, cur) { + byte *recipient; + recipient = pcp_box_decrypt(ptx, s, cur, rec_buf, PCP_ASYM_RECIPIENT_SIZE, &rec_size); + if(recipient != NULL && rec_size == crypto_secretbox_KEYBYTES) { + /* found a match */ + recmatch = 1; + symkey = ucmalloc(crypto_secretbox_KEYBYTES); + memcpy(symkey, recipient, crypto_secretbox_KEYBYTES); + free(recipient); + break; + } + free(recipient); + } } if(verify) { size_t R = nrec * (PCP_ASYM_RECIPIENT_SIZE); @@ -290,7 +310,7 @@ size_t pcp_decrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream* out, pcp_key_t return 0; } -size_t pcp_encrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream *out, pcp_key_t *s, pcp_pubkey_t *p, int sign) { +size_t pcp_encrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream *out, pcp_key_t *s, pcp_pubkey_t *p, int sign, int anon) { byte *symkey; int recipient_count; byte *recipients_cipher; @@ -336,24 +356,25 @@ size_t pcp_encrypt_stream(PCPCTX *ptx, Pcpstream *in, Pcpstream *out, pcp_key_t /* step 1, file header */ if(sign) head[0] = PCP_ASYM_CIPHER_SIG; + else if(anon) + head[0] = PCP_ASYM_CIPHER_ANON; else head[0] = PCP_ASYM_CIPHER; ps_write(out, head, 1); - /* fwrite(head, 1, 1, out); */ - /* fprintf(stderr, "D: header - 1\n"); */ + if(ps_err(out) != 0) { fatal(ptx, "Failed to write encrypted output!\n"); goto errec1; } -#ifdef PCP_ASYM_ADD_SENDER_PUB - /* step 2, sender's pubkey */ - ps_write(out, s->pub, crypto_box_PUBLICKEYBYTES); - /*fwrite(s->pub, crypto_box_PUBLICKEYBYTES, 1, out); */ - /* fprintf(stderr, "D: sender pub - %d\n", crypto_box_PUBLICKEYBYTES); */ - if(ps_err(out) != 0) - goto errec1; -#endif + if(anon) { + /* step 2, sender's pubkey */ + ps_write(out, s->pub, crypto_box_PUBLICKEYBYTES); + /*fwrite(s->pub, crypto_box_PUBLICKEYBYTES, 1, out); */ + /* fprintf(stderr, "D: sender pub - %d\n", crypto_box_PUBLICKEYBYTES); */ + if(ps_err(out) != 0) + goto errec1; + } /* step 3, len recipients, big endian */ lenrec = recipient_count; diff --git a/src/encryption.c b/src/encryption.c index 82535c2..3a16d24 100644 --- a/src/encryption.c +++ b/src/encryption.c @@ -29,6 +29,7 @@ int pcpdecrypt(char *id, int useid, char *infile, char *outfile, char *passwd, i byte *symkey = NULL; size_t dlen; uint8_t head; + int anon = 0; if(infile == NULL) in = stdin; @@ -77,7 +78,7 @@ int pcpdecrypt(char *id, int useid, char *infile, char *outfile, char *passwd, i ucfree(passphrase, strlen(passwd)+1); free(salt); } - else if(head == PCP_ASYM_CIPHER || head == PCP_ASYM_CIPHER_SIG) { + else if(head == PCP_ASYM_CIPHER || head == PCP_ASYM_CIPHER_SIG || head == PCP_ASYM_CIPHER_ANON) { /* asymetric mode */ if(useid) { secret = pcphash_keyexists(ptx, id); @@ -111,6 +112,9 @@ int pcpdecrypt(char *id, int useid, char *infile, char *outfile, char *passwd, i if(secret == NULL) goto errde3; + if(head == PCP_ASYM_CIPHER_ANON) + anon = 1; + if(head == PCP_ASYM_CIPHER_SIG) verify = 1; } @@ -126,10 +130,10 @@ int pcpdecrypt(char *id, int useid, char *infile, char *outfile, char *passwd, i } if(symkey == NULL) { - dlen = pcp_decrypt_stream(ptx, pin, pout, secret, NULL, verify); + dlen = pcp_decrypt_stream(ptx, pin, pout, secret, NULL, verify, anon); } else { - dlen = pcp_decrypt_stream(ptx, pin, pout, NULL, symkey, verify); + dlen = pcp_decrypt_stream(ptx, pin, pout, NULL, symkey, verify, 0); ucfree(symkey, 64); } @@ -154,7 +158,7 @@ int pcpdecrypt(char *id, int useid, char *infile, char *outfile, char *passwd, i -int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, plist_t *recipient, int signcrypt, int armor) { +int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, plist_t *recipient, int signcrypt, int armor, int anon) { FILE *in = NULL; FILE *out = NULL; pcp_pubkey_t *pubhash = NULL; /* FIXME: add free() */ @@ -234,32 +238,33 @@ int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, plist_t *rec if(self != 1) { /* we're using a random secret keypair on our side */ -#ifdef PCP_ASYM_ADD_SENDER_PUB - secret = pcpkey_new(); -#else - secret = pcp_find_primary_secret(); - if(secret == NULL) { - fatal(ptx, "Could not find a secret key in vault %s!\n", id, vault->filename); - goto erren2; + if(anon) { + secret = pcpkey_new(); } - - if(secret->secret[0] == 0) { - /* encrypted, decrypt it */ - char *passphrase; - if(passwd == NULL) { - pcp_readpass(&passphrase, - "Enter passphrase to decrypt your secret key", NULL, 1); - } - else { - passphrase = ucmalloc(strlen(passwd)+1); - strncpy(passphrase, passwd, strlen(passwd)+1); - } - secret = pcpkey_decrypt(ptx, secret, passphrase); - ucfree(passphrase, strlen(passwd)+1); - if(secret == NULL) + else { + secret = pcp_find_primary_secret(); + if(secret == NULL) { + fatal(ptx, "Could not find a secret key in vault %s!\n", id, vault->filename); goto erren2; + } + + if(secret->secret[0] == 0) { + /* encrypted, decrypt it */ + char *passphrase; + if(passwd == NULL) { + pcp_readpass(&passphrase, + "Enter passphrase to decrypt your secret key", NULL, 1); + } + else { + passphrase = ucmalloc(strlen(passwd)+1); + strncpy(passphrase, passwd, strlen(passwd)+1); + } + secret = pcpkey_decrypt(ptx, secret, passphrase); + ucfree(passphrase, strlen(passwd)+1); + if(secret == NULL) + goto erren2; + } } -#endif } if(infile == NULL) @@ -295,7 +300,7 @@ int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, plist_t *rec ucfree(symkey, 64); } else { - clen = pcp_encrypt_stream(ptx, pin, pout, secret, pubhash, signcrypt); + clen = pcp_encrypt_stream(ptx, pin, pout, secret, pubhash, signcrypt, anon); } if(armor == 1) { diff --git a/src/encryption.h b/src/encryption.h index 7856269..d1377cc 100644 --- a/src/encryption.h +++ b/src/encryption.h @@ -39,6 +39,6 @@ #include "context.h" int pcpdecrypt(char *id, int useid, char *infile, char *outfile, char *passwd, int verify); -int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, plist_t *recipient, int signcrypt, int armor); +int pcpencrypt(char *id, char *infile, char *outfile, char *passwd, plist_t *recipient, int signcrypt, int armor, int anon); #endif /* _HAVE_ENCRYPTION_H */ diff --git a/src/pcp.c b/src/pcp.c index 6f05205..37d16cc 100644 --- a/src/pcp.c +++ b/src/pcp.c @@ -46,7 +46,7 @@ char *default_vault() { } int main (int argc, char **argv) { - int opt, mode, usevault, useid, userec, lo, armor, detach, signcrypt, exportformat; + int opt, mode, usevault, useid, userec, lo, armor, detach, signcrypt, exportformat, anon; char *vaultfile = default_vault(); char *outfile = NULL; char *infile = NULL; @@ -68,6 +68,7 @@ int main (int argc, char **argv) { armor = 0; detach = 0; signcrypt = 0; + anon = 0; exportformat = EXP_FORMAT_NATIVE; ptx = ptx_new(); @@ -100,6 +101,7 @@ int main (int argc, char **argv) { { "encrypt", no_argument, NULL, 'e' }, { "encrypt-me", no_argument, NULL, 'm' }, { "decrypt", no_argument, NULL, 'd' }, + { "anonymous", no_argument, NULL, 'A' }, /* encoding */ { "z85-encode", no_argument, NULL, 'z' }, @@ -120,7 +122,7 @@ int main (int argc, char **argv) { { NULL, 0, NULL, 0 } }; - while ((opt = getopt_long(argc, argv, "klLV:vdehsO:i:I:pSPRtEx:DzaZr:gcymf:b1F:0K", + while ((opt = getopt_long(argc, argv, "klLV:vdehsO:i:I:pSPRtEx:DzaZr:gcymf:b1F:0KA", longopts, NULL)) != -1) { switch (opt) { @@ -185,6 +187,9 @@ int main (int argc, char **argv) { case 'Z': armor = 2; break; + case 'A': + anon = 1; + break; case 'F': if(strncmp(optarg, "pbp", 3) == 0) { exportformat = EXP_FORMAT_PBP; @@ -475,11 +480,11 @@ int main (int argc, char **argv) { if(useid == 1 && userec == 0) { /* one dst, FIXME: make id a list as well */ id = pcp_normalize_id(keyid); - pcpencrypt(id, infile, outfile, xpass, NULL, signcrypt, armor); + pcpencrypt(id, infile, outfile, xpass, NULL, signcrypt, armor, anon); } else if(useid == 0 && userec == 1) { /* multiple dst */ - pcpencrypt(NULL, infile, outfile, xpass, recipient, signcrypt, armor); + pcpencrypt(NULL, infile, outfile, xpass, recipient, signcrypt, armor, anon); } else { /* -i and -r specified */ @@ -547,7 +552,7 @@ int main (int argc, char **argv) { break; case PCP_MODE_ENCRYPT_ME: - pcpencrypt(NULL, infile, outfile, xpass, NULL, 0, armor); + pcpencrypt(NULL, infile, outfile, xpass, NULL, 0, armor, 0); break; case PCP_MODE_TEXT: diff --git a/tests/sample.c b/tests/sample.c index 0ccdb60..db42b3d 100644 --- a/tests/sample.c +++ b/tests/sample.c @@ -34,7 +34,7 @@ int main() { /* actually encrypt the message, don't sign it Alice is the sender, Bob is the recipient */ - pcp_encrypt_stream(ptx, clear_in, crypt_out, alice, pubhash, 0); + pcp_encrypt_stream(ptx, clear_in, crypt_out, alice, pubhash, 0, 0); /* now, print the encrypted result */ fprintf(stderr, "Alice encrypted %"FMT_SIZE_T" bytes for Bob:\n", (SIZE_T_CAST)strlen(message)); @@ -51,7 +51,7 @@ int main() { pcphash_add(ptx, alicepub, alicepub->type); /* try to decrypt the message */ - if(pcp_decrypt_stream(ptx, crypt_out, clear_out, bob, NULL, 0) == 0) + if(pcp_decrypt_stream(ptx, crypt_out, clear_out, bob, NULL, 0, 0) == 0) fatals_ifany(ptx); else { /* and finally print out the decrypted message */ diff --git a/tests/unittests.cfg b/tests/unittests.cfg index 3e03a95..913c96d 100644 --- a/tests/unittests.cfg +++ b/tests/unittests.cfg @@ -182,6 +182,7 @@ temporarily disabled expect = /encrypted/ */ + # # encryption tests @@ -202,12 +203,23 @@ temporarily disabled expect = /${idbobby} - Bobby/ + + cmd = $pcp -V va -e -A -i ${idbobby} -I testmessage -O testencryptedanon -x a + expect = /${idbobby} - Bobby/ + + # bobbys part cmd = $pcp -V vb -K -I key-bobby-sec -x b expect = /${idbobby}/ + + # decrypt anon, without knowing alicias key + cmd = $pcp -V vb -d -O testdecryptedanon -I testencryptedanon -x b + expect = /successfully/ + + cmd = $pcp -V vb -K -I key-alicia-pub expect = /${idalicia}/ @@ -272,7 +284,7 @@ temporarily disabled cmd = echo HALLO | $pcp -V vcl -e -O testencrypted -i ${idbobby} - expect = /success/ + expect = /Bobby/