diff --git a/ChangeLog b/ChangeLog index 48c0e11..cfb4662 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,7 +19,35 @@ to work with binary data in various, flexible and error prone ways. Cribbed from the code in openssh/buffer.c. - + + Import and export of keys is now being done in the + lib and no more in src. Src only opens files and + asks for passwords and stuff like this. + + Changed public key export format to RFC4880, see + include/pcp/mgmt.h for details. Pcp uses only a + small subset of what the rfc provides, I left out + most of the bloat. Also our keys are incompatible + with OpenPGP of course, since our ciphers are + different. But it's a standardized format, easy + to work with and flexible. From this point on + it should be possible to import old public keys + even if the internal structure changed. This wasn't + possible in the past. + + The secret key export format changed as well. It + is proprietary but more flexible than the old one + as well. It now only contains static data, whatever + can be calculated later isn't stored. Everything + is being put into one stream and completely encrypted + symmetrically. As with the new pubkey export format + this one as well is independent of internal structs + in pcp and should therefore be future proof. + + Lots of refactoring have been done to clear things + out and make the system work with the changes + above. + 0.2.0 ED25519 and Curve25519 keys are now generated separately (previously they were generated from one random seed, the curve had been derived from diff --git a/TODO b/TODO index c15f801..377ee71 100644 --- a/TODO +++ b/TODO @@ -20,6 +20,13 @@ enable formats for secret key exports as well Unitttests: - sometimes "no matching pub key in vault, while it's there + Cause: + echo HALLO | ../src/pcp1 -V vcl -e -O testencrypted -i 0xA907B927849B39F9 + ok 28 - check-crypto-unencrypted-secret-message + public key exported. <=== ??? + + + - sometimes secret key is empty diff --git a/bindings/cpp/Makefile.am b/bindings/cpp/Makefile.am index fb6343d..5cd5beb 100644 --- a/bindings/cpp/Makefile.am +++ b/bindings/cpp/Makefile.am @@ -22,5 +22,5 @@ AM_CXXFLAGS = -I../../include -I../../libpcp/scrypt/crypto -I../../libpcp/scrypt lib_LTLIBRARIES = libpcp1++.la -libpcp1___la_SOURCES = pcp++.h key.cpp vault.cpp crypto.cpp sign.cpp +libpcp1___la_SOURCES = pcp++.h key.cpp vault.cpp crypto.cpp sign.cpp buffer.cpp include_HEADERS = pcp++.h diff --git a/bindings/cpp/buffer++.h b/bindings/cpp/buffer++.h new file mode 100644 index 0000000..049e232 --- /dev/null +++ b/bindings/cpp/buffer++.h @@ -0,0 +1,90 @@ +/* + This file is part of Pretty Curved Privacy (pcp1). + + Copyright (C) 2013-2014 T.v.Dein. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + You can contact me by mail: . +*/ + + +#ifndef _HAVE_BUFFERPP_H +#define _HAVE_BUFFERPP_H + +#include +#include +#include + + +namespace pcp { + class Buf { + private: + Buffer *B; + + public: + Buf(); + Buf(Buffer *b); + Buf(std::string name); + Buf(std::string name, size_t blocksize); + ~Buf(); + + Buf& operator = (const Buf &b); + + + void clear(); + void rewind(); + void add(const void *data, size_t len); + void add_buf(Buffer *src); + + void add_string(std::string data); + + void add_hex(void *data, size_t len); + void resize(size_t len); + int done(); + size_t get_chunk(void *buf, size_t len); + unsigned char *get(); + + void dump(); + void info(); + size_t size(); + size_t left(); + + std::string get_str(); + + unsigned char *get_remainder(); + size_t extract(void *buf, size_t offset, size_t len); + uint8_t get8(); + uint16_t get16(); + uint32_t get32(); + uint64_t get64(); + uint16_t get16na(); + uint32_t get32na(); + uint64_t get64na(); + uint8_t last8(); + uint16_t last16(); + uint32_t last32(); + uint64_t last64(); + size_t fd_read(FILE *in, size_t len); + void add8(uint8_t v); + void add16(uint16_t v); + void add32(uint32_t v); + void add64(uint64_t v); + void add16be(uint16_t v); + void add32be(uint32_t v); + void add64be(uint64_t v); + }; +}; + +#endif // HAVE_BUFFERPP_H diff --git a/bindings/cpp/buffer.cpp b/bindings/cpp/buffer.cpp new file mode 100644 index 0000000..0c43566 --- /dev/null +++ b/bindings/cpp/buffer.cpp @@ -0,0 +1,201 @@ +/* + This file is part of Pretty Curved Privacy (pcp1). + + Copyright (C) 2013-2014 T.v.Dein. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + You can contact me by mail: . +*/ + +#include "buffer++.h" + +using namespace std; +using namespace pcp; + +Buf::Buf() { + char name[] = "BUF"; + B = buffer_new(32, name); +} + +Buf::Buf(Buffer *b) { + B = b; +} + +Buf::Buf(string name) { + char *n = (char *)ucmalloc(name.length()+1); + memcpy(n, name.c_str(), name.length()); + B = buffer_new(32, n); + free(n); +} + +Buf::Buf(string name, size_t blocksize) { + char *n = (char *)ucmalloc(name.length()+1); + memcpy(n, name.c_str(), name.length()); + B = buffer_new(blocksize, n); + free(n); +} + +Buf::~Buf() { + buffer_free(B); +} + +Buf& Buf::operator = (const Buf &b) { + B = b.B; + return *this; +} + +void Buf::clear() { + buffer_clear(B); +} + +void Buf::rewind() { + buffer_rewind(B); +} + +void Buf::add(const void *data, size_t len) { + buffer_add(B, data, len); +} + +void Buf::add_buf(Buffer *src) { + buffer_add_buf(B, src); +} + +void Buf::add_string(string data) { + buffer_add_str(B, data.c_str()); +} + +void Buf::add_hex(void *data, size_t len) { + buffer_add_hex(B, data, len); +} + +void Buf::resize(size_t len) { + buffer_resize(B, len); +} + +int Buf::done() { + return buffer_done(B); +} + +size_t Buf::get_chunk(void *buf, size_t len) { + return buffer_get_chunk(B, buf, len); +} + +unsigned char *Buf::get() { + return buffer_get(B); +} + +string Buf::get_str() { + return string(buffer_get_str(B)); +} + +unsigned char *Buf::get_remainder() { + return buffer_get_remainder(B); +} + +size_t Buf::extract(void *buf, size_t offset, size_t len) { + return buffer_extract(B, buf, offset, len); +} + +uint8_t Buf::get8() { + return buffer_get8(B); +} + +uint16_t Buf::get16() { + return buffer_get16(B); +} + +uint32_t Buf::get32() { + return buffer_get32(B); +} + +uint64_t Buf::get64() { + return buffer_get64(B); +} + +uint16_t Buf::get16na() { + return buffer_get16na(B); +} + +uint32_t Buf::get32na() { + return buffer_get32na(B); +} + +uint64_t Buf::get64na() { + return buffer_get64na(B); +} + +uint8_t Buf::last8() { + return buffer_last8(B); +} + +uint16_t Buf::last16() { + return buffer_last16(B); +} + +uint32_t Buf::last32() { + return buffer_last32(B); +} + +uint64_t Buf::last64() { + return buffer_last64(B); +} + +size_t Buf::fd_read(FILE *in, size_t len) { + return buffer_fd_read(B, in, len); +} + +void Buf::add8(uint8_t v) { + buffer_add8(B, v); +} + +void Buf::add16(uint16_t v) { + buffer_add16(B, v); +} + +void Buf::add32(uint32_t v) { + buffer_add32(B, v); +} + +void Buf::add64(uint64_t v) { + buffer_add64(B, v); +} + +void Buf::add16be(uint16_t v) { + buffer_add16be(B, v); +} + +void Buf::add32be(uint32_t v) { + buffer_add32be(B, v); +} + +void Buf::add64be(uint64_t v) { + buffer_add64be(B, v); +} + +void Buf::dump() { + buffer_dump(B); +} + +void Buf::info() { + buffer_info(B); +} + +size_t Buf::size() { + return buffer_size(B); +} + +size_t Buf::left() { + return buffer_left(B); +} diff --git a/bindings/cpp/crypto++.h b/bindings/cpp/crypto++.h index 92b8f0a..1ad505a 100644 --- a/bindings/cpp/crypto++.h +++ b/bindings/cpp/crypto++.h @@ -48,12 +48,10 @@ namespace pcp { // PK encryption methods // sender pubkey is P - std::string encrypt(std::vector message); - std::string encrypt(std::string message); - std::string encrypt(unsigned char *message, size_t mlen); + bool encrypt(FILE *in, FILE *out, bool sign); // decrypt using P or use vault if defined - ResultSet decrypt(std::string cipher); + bool decrypt(FILE *in, FILE *out, bool verify); }; }; diff --git a/bindings/cpp/crypto.cpp b/bindings/cpp/crypto.cpp index 6791ce6..b92b760 100644 --- a/bindings/cpp/crypto.cpp +++ b/bindings/cpp/crypto.cpp @@ -29,6 +29,8 @@ Crypto::Crypto(Key &skey, PubKey &pkey) { P = pkey; S = skey; havevault = false; + pcphash_init(); + pcphash_add(P.K, PCP_KEY_TYPE_PUBLIC); } Crypto::Crypto(Vault &v, Key &skey, PubKey &pkey) { @@ -38,120 +40,19 @@ Crypto::Crypto(Vault &v, Key &skey, PubKey &pkey) { havevault = true; } -string Crypto::encrypt(string message) { - unsigned char *m = (unsigned char *)ucmalloc(message.size() + 1); - memcpy(m, message.c_str(), message.size()); - return Crypto::encrypt(m, message.size() + 1); +bool Crypto::encrypt(FILE *in, FILE *out, bool sign) { + pcp_pubkey_t *pubhash = NULL; + HASH_ADD_STR( pubhash, id, P.K); + size_t clen = pcp_encrypt_file(in, out, S.K, pubhash, sign); + if(clen <= 0) + throw exception(); + return true; } -string Crypto::encrypt(vector message) { - unsigned char *m = (unsigned char *)ucmalloc(message.size()); - for(size_t i=0; iid, 16); - memcpy(combined, hash, crypto_hash_BYTES); - memcpy(&combined[crypto_hash_BYTES], cipher, clen); - - // combined consists of: - // keyid|nonce|cipher - char *encoded = pcp_z85_encode(combined, rlen, &zlen); - - if(encoded == NULL) - throw exception(); - - return string((char *)encoded); -} - -ResultSet Crypto::decrypt(string cipher) { - if(S.is_encrypted()) - throw exception("Error: cannot decrypt with an encrypted secret key, decrypt it before using."); - - size_t clen; - unsigned char *combined = pcp_z85_decode((char *)cipher.c_str(), &clen); - - if(combined == NULL) - throw exception(); - - unsigned char *encrypted = (unsigned char*)ucmalloc(clen - crypto_hash_BYTES); - unsigned char *hash = (unsigned char*)ucmalloc(crypto_hash_BYTES); - unsigned char *check = (unsigned char*)ucmalloc(crypto_hash_BYTES); - - memcpy(hash, combined, crypto_hash_BYTES); - memcpy(encrypted, &combined[crypto_hash_BYTES], clen - crypto_hash_BYTES); - - PubKey sender; - crypto_hash(check, (unsigned char*)P.K->id, 16); - - if(memcmp(check, hash, crypto_hash_BYTES) != 0) { - if(havevault) { - PubKeyMap pmap = vault.pubkeys(); - for(PubKeyIterator it=pmap.begin(); it != pmap.end(); ++it) { - crypto_hash(check, (unsigned char*)it->first.c_str(), 16); - if(memcmp(check, hash, crypto_hash_BYTES) == 0) { - sender = it->second; - break; - } - } - } - } - else { - sender = P; - } - - if(!sender) { - free(combined); - free(hash); - free(check); - free(encrypted); - throw exception("No public key usable for decryption found!"); - } - - size_t dlen; - unsigned char *decrypted = (unsigned char*)pcp_box_decrypt(S.K, sender.K, - encrypted, - clen - crypto_hash_BYTES, &dlen); - - if(decrypted == NULL) { - free(combined); - free(hash); - free(check); - free(encrypted); - throw exception(); - } - - ResultSet r; - r.Uchar = decrypted; - r.String = string((char *)decrypted); - r.Size = dlen; - - for(size_t i=0; ip; - // all good now, import the blob - pcp_pubkey_t *key = (pcp_pubkey_t *)ucmalloc(sizeof(pcp_pubkey_t)); - memcpy(key, z85decoded, PCP_RAW_PUBKEYSIZE); - pubkey2native(key); - - if(pcp_sanitycheck_pub(key) != 0) { - free(key); - free(z85decoded); + if(pcp_sanitycheck_pub(pub) != 0) { + free(KS->p); + free(KS->s); + free(KS); + buffer_free(blob); throw pcp::exception(); } - K = key; + K = pub; } PubKey::~PubKey() { diff --git a/bindings/cpp/pcp++.h b/bindings/cpp/pcp++.h index 4e4df68..5463602 100644 --- a/bindings/cpp/pcp++.h +++ b/bindings/cpp/pcp++.h @@ -36,5 +36,6 @@ #include "crypto++.h" #include "sign++.h" #include "helpers++.h" +#include "buffer++.h" #endif // _HAVE_PCPPP_H diff --git a/include/pcp.h b/include/pcp.h index 9d51a9d..b6611bf 100644 --- a/include/pcp.h +++ b/include/pcp.h @@ -8,6 +8,7 @@ extern "C" { #include "pcp/config.h" #include "pcp/base85.h" #include "pcp/buffer.h" +#include "pcp/config.h" #include "pcp/crypto.h" #include "pcp/defines.h" #include "pcp/digital_crc32.h" diff --git a/man/pcp1.pod b/man/pcp1.pod index 41cea71..3e7e4f4 100644 --- a/man/pcp1.pod +++ b/man/pcp1.pod @@ -113,8 +113,9 @@ Pretty Curved Privacy - File encryption using eliptic curve cryptography. -y --export-yaml Export all keys stored in your vault as YAML formatted text. Use -O to put the export into a file. - -b --pbpcompat Enable PBP compatibility for public key - exports and imports. + -F --format Export the key in a particular format. + Currently supported: pcp, pbp, yaml, + perl and C. Encryption Options: -e --encrypt Asym-Encrypt a message. Read from stdin or diff --git a/src/pcp.c b/src/pcp.c index 7d61210..99c5206 100644 --- a/src/pcp.c +++ b/src/pcp.c @@ -244,6 +244,8 @@ int main (int argc, char **argv) { case 'x': xpass = ucmalloc(strlen(optarg)+1); strncpy(xpass, optarg, strlen(optarg)+1); + if(strncmp(xpass, "n/a", 3) == 0) + xpass[0] = '\0'; break; case 'r': p_add(&recipient, optarg); diff --git a/tests/cpptest.cpp b/tests/cpptest.cpp index a580ae2..6082156 100644 --- a/tests/cpptest.cpp +++ b/tests/cpptest.cpp @@ -14,8 +14,25 @@ void pr(string name, unsigned char *data, size_t len) { cout << endl; } +FILE *_openwr(string file) { + FILE *fd; + if((fd = fopen(file.c_str(), "wb+")) == NULL) { + throw pcp::exception("Could not open output file " + file + "\n"); + } + return fd; +} + +FILE *_openrd(string file) { + FILE *fd; + if((fd = fopen(file.c_str(), "rb")) == NULL) { + throw pcp::exception("Could not open input file " + file + "\n"); + } + return fd; +} + void test0() { // test keygen and crypto + FILE *CLEAR, *CIPHER, *DECRYPTED; Key A = Key("a", "alicia", "alicia@local"); Key B = Key("b", "bobby", "bobby@local"); PubKey PA = A.get_public(); @@ -26,14 +43,35 @@ void test0() { Crypto A2B(A, PB); Crypto B2A(B, PA); - - string cipher = A2B.encrypt("Hallo"); - ResultSet res = B2A.decrypt(cipher); - if(res.String == "Hallo") - cout << "0 ok" << endl; + CLEAR = _openwr("testcppclear"); + fprintf(CLEAR, "HALLO\n"); + fclose(CLEAR); + + CIPHER = _openwr("testcpcipher"); + CLEAR = _openrd("testcppclear"); + + if(A2B.encrypt(CLEAR, CIPHER, false)) { + + CIPHER = _openrd("testcpcipher"); + DECRYPTED = _openwr("testcppdecrypted"); + + if(B2A.decrypt(CIPHER, DECRYPTED, false)) { + + DECRYPTED = _openrd("testcppdecrypted"); + char *got = (char *)ucmalloc(10); + fread(got, 1, 6, DECRYPTED); + if(strncmp(got, "HALLO", 5) != 0) { + throw pcp::exception(); + } + } + else + throw pcp::exception("failed to decrypt"); + } else - throw pcp::exception("wtf - decryption failed (uncatched as well)"); + throw pcp::exception("failed to encrypt"); + + cout << "0 ok" << endl; } void test1() { @@ -102,6 +140,22 @@ void test3() { cout << "3 ok" << endl; } +void test4() { + unsigned char *r = (unsigned char*)ucmalloc(32); + int i; + Buf b; + + for(i=0; i<10; i++) { + arc4random_buf(r, 32); + b.add(r, 32); + } + + if(b.size() == 32 * 10) + cout << "3 ok" << endl; + else + cout << "3 failed" << endl; +} + int main(int argc, char **argv) { sodium_init(); @@ -125,6 +179,10 @@ int main(int argc, char **argv) { test3(); break; + case '4': + test3(); + break; + default: cerr << "usage: cpptest N" << endl; break; diff --git a/tests/unittests.cfg b/tests/unittests.cfg index c49a53d..6bd6a42 100644 --- a/tests/unittests.cfg +++ b/tests/unittests.cfg @@ -187,11 +187,10 @@ temporarily disabled expect = /HELLO/ - # # check usage of unencrypted secret key - cmd = (echo dau; echo foo; echo yes) | $pcp -V vcl -k -x "" + cmd = (echo dau; echo foo; echo yes) | $pcp -V vcl -k -x "n/a" expect = /added to/ @@ -489,3 +488,8 @@ disabled, need to re-design invalidkeys.c in order to catch up with new format cmd = ./cpptest 3 expect = /ok/ + + + cmd = ./cpptest 4 + expect = /ok/ +