From 212bd71ac881d7f71906d67f9ca4e4f05221c8fa Mon Sep 17 00:00:00 2001 From: TLINDEN Date: Sat, 7 Dec 2013 13:24:44 +0100 Subject: [PATCH] added c++ signature support --- ChangeLog | 3 + TODO | 4 +- bindings/cpp/Makefile.am | 2 +- bindings/cpp/Makefile.in | 5 +- bindings/cpp/crypto.cpp | 6 ++ bindings/cpp/pcp++.h | 1 + bindings/cpp/sign++.h | 69 +++++++++++++++++ bindings/cpp/sign.cpp | 158 +++++++++++++++++++++++++++++++++++++++ bindings/cpp/vault++.h | 4 + bindings/cpp/vault.cpp | 55 ++++++++++++++ include/pcp/ed.h | 5 +- tests/cpptest.cpp | 28 +++++++ tests/unittests.cfg | 7 +- 13 files changed, 339 insertions(+), 8 deletions(-) create mode 100644 bindings/cpp/sign++.h create mode 100644 bindings/cpp/sign.cpp diff --git a/ChangeLog b/ChangeLog index 75de4a0..432475c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -43,6 +43,9 @@ platform.h, now we just use the random functions of libsodium if they're not available. + Added C++ language binding (bindings/cpp/), look + at tests/cpptest.cpp for usage examples. + 0.1.4 Changed key format (again), now the main secret is the ED25519 secret key, which will be encrypted. Everything else will be derived from that. Thanks diff --git a/TODO b/TODO index 198a7f8..468fc55 100644 --- a/TODO +++ b/TODO @@ -7,4 +7,6 @@ work with already en+de-coded in+out-put. Bug: pcp_z85_decode() segfaults at z85.c:83 if input consists of "-----" only. -Bug: pcp_z85_decode() fails if after end marker follows something, even whitespaces \ No newline at end of file +Bug: pcp_z85_decode() fails if after end marker follows something, even whitespaces + +key++: normalize id and lc() \ No newline at end of file diff --git a/bindings/cpp/Makefile.am b/bindings/cpp/Makefile.am index bcb9240..c13c4ea 100644 --- a/bindings/cpp/Makefile.am +++ b/bindings/cpp/Makefile.am @@ -22,5 +22,5 @@ AM_CXXFLAGS = -I../../include -Wall -g lib_LTLIBRARIES = libpcp1++.la -libpcp1___la_SOURCES = pcp++.h key.cpp vault.cpp crypto.cpp +libpcp1___la_SOURCES = pcp++.h key.cpp vault.cpp crypto.cpp sign.cpp include_HEADERS = pcp++.h diff --git a/bindings/cpp/Makefile.in b/bindings/cpp/Makefile.in index 5c2828b..03ca60f 100644 --- a/bindings/cpp/Makefile.in +++ b/bindings/cpp/Makefile.in @@ -96,7 +96,7 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" LTLIBRARIES = $(lib_LTLIBRARIES) libpcp1___la_LIBADD = -am_libpcp1___la_OBJECTS = key.lo vault.lo crypto.lo +am_libpcp1___la_OBJECTS = key.lo vault.lo crypto.lo sign.lo libpcp1___la_OBJECTS = $(am_libpcp1___la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/pcp depcomp = $(SHELL) $(top_srcdir)/config/depcomp @@ -272,7 +272,7 @@ top_srcdir = @top_srcdir@ # AM_CXXFLAGS = -I../../include -Wall -g lib_LTLIBRARIES = libpcp1++.la -libpcp1___la_SOURCES = pcp++.h key.cpp vault.cpp crypto.cpp +libpcp1___la_SOURCES = pcp++.h key.cpp vault.cpp crypto.cpp sign.cpp include_HEADERS = pcp++.h all: all-am @@ -353,6 +353,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypto.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/key.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sign.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vault.Plo@am__quote@ .cpp.o: diff --git a/bindings/cpp/crypto.cpp b/bindings/cpp/crypto.cpp index ab815d0..6791ce6 100644 --- a/bindings/cpp/crypto.cpp +++ b/bindings/cpp/crypto.cpp @@ -52,6 +52,9 @@ string Crypto::encrypt(vector message) { } 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; @@ -79,6 +82,9 @@ string Crypto::encrypt(unsigned char *message, size_t mlen) { } 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); diff --git a/bindings/cpp/pcp++.h b/bindings/cpp/pcp++.h index b263c4d..4e4df68 100644 --- a/bindings/cpp/pcp++.h +++ b/bindings/cpp/pcp++.h @@ -34,6 +34,7 @@ #include "key++.h" #include "vault++.h" #include "crypto++.h" +#include "sign++.h" #include "helpers++.h" #endif // _HAVE_PCPPP_H diff --git a/bindings/cpp/sign++.h b/bindings/cpp/sign++.h new file mode 100644 index 0000000..43220f3 --- /dev/null +++ b/bindings/cpp/sign++.h @@ -0,0 +1,69 @@ +/* + This file is part of Pretty Curved Privacy (pcp1). + + Copyright (C) 2013 T.Linden. + + 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_PCPPP_SIGN_H +#define _HAVE_PCPPP_SIGN_H + +#include +#include +#include + +#include "vault++.h" +#include "key++.h" +#include "sign++.h" +#include "helpers++.h" + +namespace pcp { + + class Signature { + private: + bool havevault; + + public: + PubKey P; + Key S; + Vault vault; + pcp_sig_t *sig; + + // constructors + Signature(Key &skey); // sign only + Signature(PubKey &pkey); // verify only + Signature(Key &skey, PubKey &pkey); // both/bulk + Signature(Vault &v); + + // destructor + ~Signature(); + + // PK signature methods + // sender pubkey is P + std::string sign(std::vector message); + std::string sign(std::string message); + std::string sign(unsigned char *message, size_t mlen); + + // verify using P or use vault if defined + bool verify(std::string signature, std::string message); + bool verify(std::string signature, std::vector message); + bool verify(std::string signature, unsigned char *message, size_t mlen); + }; +}; + +#endif // _HAVE_PCPPP_SIGN_H diff --git a/bindings/cpp/sign.cpp b/bindings/cpp/sign.cpp new file mode 100644 index 0000000..2db88a3 --- /dev/null +++ b/bindings/cpp/sign.cpp @@ -0,0 +1,158 @@ +/* + This file is part of Pretty Curved Privacy (pcp1). + + Copyright (C) 2013 T.Linden. + + 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 "sign++.h" + +using namespace std; +using namespace pcp; + +Signature::Signature(Key &skey) { + S = skey; + havevault = false; + sig = NULL; +} + +Signature::Signature(PubKey &pkey) { + P = pkey; + havevault = false; + sig = NULL; +} + +Signature::Signature(Key &skey, PubKey &pkey) { + P = pkey; + S = skey; + havevault = false; + sig = NULL; +} + +Signature::Signature(Vault &v) { + vault = v; + havevault = true; + sig = NULL; + S = vault.get_primary(); +} + +Signature::~Signature() { + if(sig != NULL) + free(sig); +} + +std::string Signature::sign(std::vector message) { + unsigned char *m = (unsigned char *)ucmalloc(message.size()); + for(size_t i=0; i message) { + unsigned char *m = (unsigned char *)ucmalloc(message.size()); + for(size_t i=0; iid); + + if(!P) { + if(havevault) { + if(vault.pubkey_exists(sigid)) { + P = vault.get_public(sigid); + } + else { + throw exception("Unable to verify, signed using an unknown key."); + } + } + else { + throw exception("No public key and no vault specified, unable to verify."); + } + } + else { + if(P.get_id() != sigid) { + throw exception("Specified public key doesn't match the signers key."); + } + } + + if(pcp_ed_verify(message, mlen, sig, P.K) == 0) { + return true; + } + else { + throw exception(); + } +} diff --git a/bindings/cpp/vault++.h b/bindings/cpp/vault++.h index 31b94d1..b7daf40 100644 --- a/bindings/cpp/vault++.h +++ b/bindings/cpp/vault++.h @@ -69,6 +69,10 @@ namespace pcp { void pubkey_add(PubKey &key); void key_delete(std::string &id); + + Key get_primary(); + Key get_secret(std::string &id); + PubKey get_public(std::string &id); }; diff --git a/bindings/cpp/vault.cpp b/bindings/cpp/vault.cpp index a5649e3..8ed2e2d 100644 --- a/bindings/cpp/vault.cpp +++ b/bindings/cpp/vault.cpp @@ -86,6 +86,22 @@ void Vault::pubkey_add(PubKey &key) { key.is_stored(true); } +bool Vault::key_exists(string &id) { + pcp_key_t *s = pcphash_keyexists((char *)id.c_str()); + if(s == NULL) + return false; + else + return true; +} + +bool Vault::pubkey_exists(string &id) { + pcp_pubkey_t *p = pcphash_pubkeyexists((char *)id.c_str()); + if(p == NULL) + return false; + else + return true; +} + void Vault::key_delete(std::string &id) { pcp_pubkey_t *p = pcphash_pubkeyexists((char *)id.c_str()); @@ -108,3 +124,42 @@ void Vault::key_delete(std::string &id) { } } } + +Key Vault::get_primary() { + pcp_key_t *k = NULL; + pcphash_iterate(k) { + if(k->type == PCP_KEY_TYPE_MAINSECRET) { + return Key(k); + } + } + + if(Vault::key_count() == 1) { + pcphash_iterate(k) { + return Key(k); + } + } + + // too bad + throw exception("No primary key found in vault."); +} + +Key Vault::get_secret(std::string &id) { + pcp_key_t *k = NULL; + pcphash_iterate(k) { + if(memcmp(k->id, id.c_str(), 16) == 0) { + return Key(k); + } + } + throw exception("Secret key doesn't exist in vault."); +} + + +PubKey Vault::get_public(std::string &id) { + pcp_pubkey_t *k = NULL; + pcphash_iteratepub(k) { + if(memcmp(k->id, id.c_str(), 16) == 0) { + return PubKey(k); + } + } + throw exception("Public key doesn't exist in vault."); +} diff --git a/include/pcp/ed.h b/include/pcp/ed.h index e57684f..c9f6377 100644 --- a/include/pcp/ed.h +++ b/include/pcp/ed.h @@ -41,7 +41,8 @@ struct _pcp_sig_t { typedef struct _pcp_sig_t pcp_sig_t; -int pcp_ed_verify(unsigned char *input, size_t inputlen, pcp_sig_t *sig, pcp_pubkey_t *p); +int pcp_ed_verify(unsigned char *input, size_t inputlen, + pcp_sig_t *sig, pcp_pubkey_t *p); pcp_sig_t *pcp_ed_sign(unsigned char *message, size_t messagesize, pcp_key_t *s); @@ -51,6 +52,4 @@ pcp_sig_t *sig2be(pcp_sig_t *k); pcp_sig_t *pcp_ed_newsig(unsigned char *hash, char *id); - void pcp_dumpsig(pcp_sig_t *sig); - #endif // _HAVE_PCP_ED_H diff --git a/tests/cpptest.cpp b/tests/cpptest.cpp index 051a9cf..da2d856 100644 --- a/tests/cpptest.cpp +++ b/tests/cpptest.cpp @@ -83,8 +83,28 @@ void test2() { cout << "2 ok" << endl; } + +void test3() { + // signature test + Key A = Key("a", "alicia", "alicia@local"); + A.decrypt("a"); + PubKey PA = A.get_public(); + + string message = "hallo baby"; + + Signature SigA(A); + Signature SigB(PA); + + string sig = SigA.sign(message); + + if(SigB.verify(sig, message) ) + cout << "3 ok" << endl; +} + int main(int argc, char **argv) { try { + if(argc < 2) + throw pcp::exception("usage: cpptest N"); switch(argv[1][0]) { case '0': test0(); @@ -97,6 +117,14 @@ int main(int argc, char **argv) { case '2': test2(); break; + + case '3': + test3(); + break; + + default: + cerr << "usage: cpptest N" << endl; + break; }; } catch (pcp::exception &E) { diff --git a/tests/unittests.cfg b/tests/unittests.cfg index 41e91dc..7ba7936 100644 --- a/tests/unittests.cfg +++ b/tests/unittests.cfg @@ -499,6 +499,11 @@ dxmorg@florida.cops.gov - cmd = ./cpptest 1 + cmd = ./cpptest 2 + expect = /ok/ + + + + cmd = ./cpptest 3 expect = /ok/