catch up with api and system changes in libpcp. added c++ buffer class as well

This commit is contained in:
TLINDEN
2014-02-14 16:40:09 +01:00
parent ec192131af
commit 347f155341
14 changed files with 434 additions and 150 deletions

View File

@@ -20,6 +20,34 @@
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

7
TODO
View File

@@ -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

View File

@@ -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

90
bindings/cpp/buffer++.h Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
You can contact me by mail: <tom AT vondein DOT org>.
*/
#ifndef _HAVE_BUFFERPP_H
#define _HAVE_BUFFERPP_H
#include <pcp.h>
#include <string>
#include <iostream>
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

201
bindings/cpp/buffer.cpp Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
You can contact me by mail: <tom AT vondein DOT org>.
*/
#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);
}

View File

@@ -48,12 +48,10 @@ namespace pcp {
// PK encryption methods
// sender pubkey is P
std::string encrypt(std::vector<unsigned char> 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);
};
};

View File

@@ -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<unsigned char> message) {
unsigned char *m = (unsigned char *)ucmalloc(message.size());
for(size_t i=0; i<message.size(); ++i)
m[i] = message[i];
return Crypto::encrypt(m, message.size());
}
string Crypto::encrypt(unsigned char *message, size_t mlen) {
if(S.is_encrypted())
throw exception("Error: cannot encrypt with an encrypted secret key, decrypt it before using.");
size_t clen, zlen, rlen;
unsigned char *cipher;
cipher = pcp_box_encrypt(S.K, P.K, message, mlen, &clen);
if(cipher == NULL)
bool Crypto::decrypt(FILE *in, FILE *out, bool verify) {
if(pcp_decrypt_file(in, out, S.K, NULL, verify) <= 0)
throw exception();
rlen = clen + crypto_hash_BYTES;
unsigned char *combined = (unsigned char *)ucmalloc(rlen);
unsigned char *hash = (unsigned char *)ucmalloc(crypto_hash_BYTES);
crypto_hash(hash, (unsigned char*)S.K->id, 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; i<dlen; ++i)
r.Vector.push_back(decrypted[i]);
free(combined);
free(hash);
free(check);
free(encrypted);
return r;
return true;
}

View File

@@ -254,42 +254,34 @@ PubKey::PubKey(pcp_pubkey_t *k, bool store) {
K = k;
}
// FIXME: use Buffer class for stuff like this
PubKey::PubKey(string &z85encoded) {
stored = false;
if(z85encoded.length() == 0)
throw pcp::exception("Error: zero length input");
Buffer *blob = buffer_new(256, "pub");
buffer_add(blob, z85encoded.c_str(), z85encoded.length());
size_t clen;
unsigned char *z85decoded =
pcp_z85_decode(
pcp_readz85string((unsigned char *)z85encoded.c_str(),
z85encoded.length()),
&clen); // FIXME: too complicated, must be more wrapperish
pcp_ks_bundle_t *KS = pcp_import_pub(buffer_get(blob), buffer_size(blob));
if(z85decoded == NULL)
throw pcp::exception("Error: could not decode input - it's probably not Z85.\n");
if(clen != PCP_RAW_PUBKEYSIZE) {
free(z85decoded);
char m[256];
sprintf(m, "Error: decoded input didn't result to a proper sized key (got %ld bytes)!\n", clen);
throw pcp::exception(string(m));
if(KS == NULL) {
buffer_free(blob);
throw pcp::exception();
}
pcp_pubkey_t *pub = KS->p;
// 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() {

View File

@@ -36,5 +36,6 @@
#include "crypto++.h"
#include "sign++.h"
#include "helpers++.h"
#include "buffer++.h"
#endif // _HAVE_PCPPP_H

View File

@@ -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"

View File

@@ -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

View File

@@ -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);

View File

@@ -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();
@@ -27,13 +44,34 @@ void test0() {
Crypto A2B(A, PB);
Crypto B2A(B, PA);
string cipher = A2B.encrypt("Hallo");
ResultSet res = B2A.decrypt(cipher);
CLEAR = _openwr("testcppclear");
fprintf(CLEAR, "HALLO\n");
fclose(CLEAR);
if(res.String == "Hallo")
cout << "0 ok" << endl;
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;

View File

@@ -187,11 +187,10 @@ temporarily disabled
expect = /HELLO/
</test>
#
# check usage of unencrypted secret key
<test check-crypto-unencrypted-secret>
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/
</test>
@@ -489,3 +488,8 @@ disabled, need to re-design invalidkeys.c in order to catch up with new format
cmd = ./cpptest 3
expect = /ok/
</test>
<test check-buffer>
cmd = ./cpptest 4
expect = /ok/
</test>