added c++ signature support

This commit is contained in:
TLINDEN
2013-12-07 13:24:44 +01:00
parent 14bead5499
commit 212bd71ac8
13 changed files with 339 additions and 8 deletions

View File

@@ -43,6 +43,9 @@
platform.h, now we just use the random functions platform.h, now we just use the random functions
of libsodium if they're not available. 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 0.1.4 Changed key format (again), now the main secret
is the ED25519 secret key, which will be encrypted. is the ED25519 secret key, which will be encrypted.
Everything else will be derived from that. Thanks Everything else will be derived from that. Thanks

4
TODO
View File

@@ -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() segfaults at z85.c:83 if input consists of "-----" only.
Bug: pcp_z85_decode() fails if after end marker follows something, even whitespaces Bug: pcp_z85_decode() fails if after end marker follows something, even whitespaces
key++: normalize id and lc()

View File

@@ -22,5 +22,5 @@ AM_CXXFLAGS = -I../../include -Wall -g
lib_LTLIBRARIES = libpcp1++.la 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 include_HEADERS = pcp++.h

View File

@@ -96,7 +96,7 @@ am__uninstall_files_from_dir = { \
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)" am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
LTLIBRARIES = $(lib_LTLIBRARIES) LTLIBRARIES = $(lib_LTLIBRARIES)
libpcp1___la_LIBADD = 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) libpcp1___la_OBJECTS = $(am_libpcp1___la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/pcp DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/pcp
depcomp = $(SHELL) $(top_srcdir)/config/depcomp depcomp = $(SHELL) $(top_srcdir)/config/depcomp
@@ -272,7 +272,7 @@ top_srcdir = @top_srcdir@
# #
AM_CXXFLAGS = -I../../include -Wall -g AM_CXXFLAGS = -I../../include -Wall -g
lib_LTLIBRARIES = libpcp1++.la 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 include_HEADERS = pcp++.h
all: all-am 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)/crypto.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/key.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vault.Plo@am__quote@
.cpp.o: .cpp.o:

View File

@@ -52,6 +52,9 @@ string Crypto::encrypt(vector<unsigned char> message) {
} }
string Crypto::encrypt(unsigned char *message, size_t mlen) { 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; size_t clen, zlen, rlen;
unsigned char *cipher; unsigned char *cipher;
@@ -79,6 +82,9 @@ string Crypto::encrypt(unsigned char *message, size_t mlen) {
} }
ResultSet Crypto::decrypt(string cipher) { 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; size_t clen;
unsigned char *combined = pcp_z85_decode((char *)cipher.c_str(), &clen); unsigned char *combined = pcp_z85_decode((char *)cipher.c_str(), &clen);

View File

@@ -34,6 +34,7 @@
#include "key++.h" #include "key++.h"
#include "vault++.h" #include "vault++.h"
#include "crypto++.h" #include "crypto++.h"
#include "sign++.h"
#include "helpers++.h" #include "helpers++.h"
#endif // _HAVE_PCPPP_H #endif // _HAVE_PCPPP_H

69
bindings/cpp/sign++.h Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
You can contact me by mail: <tlinden AT cpan DOT org>.
*/
#ifndef _HAVE_PCPPP_SIGN_H
#define _HAVE_PCPPP_SIGN_H
#include <pcp.h>
#include <string>
#include <iostream>
#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<unsigned char> 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<unsigned char> message);
bool verify(std::string signature, unsigned char *message, size_t mlen);
};
};
#endif // _HAVE_PCPPP_SIGN_H

158
bindings/cpp/sign.cpp Normal file
View File

@@ -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 <http://www.gnu.org/licenses/>.
You can contact me by mail: <tlinden AT cpan DOT org>.
*/
#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<unsigned char> message) {
unsigned char *m = (unsigned char *)ucmalloc(message.size());
for(size_t i=0; i<message.size(); ++i)
m[i] = message[i];
string _s = Signature::sign(m, message.size());
free(m);
return _s;
}
std::string Signature::sign(std::string message) {
unsigned char *m = (unsigned char *)ucmalloc(message.size() + 1);
memcpy(m, message.c_str(), message.size());
string _s = Signature::sign(m, message.size() + 1);
free(m);
return _s;
}
std::string Signature::sign(unsigned char *message, size_t mlen) {
if(! S)
throw exception("Error: cannot sign without a secret key, use another constructor.");
if(S.is_encrypted())
throw exception("Error: cannot sign with an encrypted secret key, decrypt it before using.");
size_t zlen;
sig = pcp_ed_sign(message, mlen, S.K);
if(sig == NULL)
throw exception();
sig2be(sig);
char *encoded = pcp_z85_encode((unsigned char *)sig, sizeof(pcp_sig_t), &zlen);
sig2native(sig);
if(encoded == NULL)
throw exception();
// FIXME: who free()s encoced?
return string((char *)encoded);
}
bool Signature::verify(string signature, 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];
bool _b = Signature::verify(signature, m, message.size());
free(m);
return _b;
}
bool Signature::verify(string signature, string message) {
unsigned char *m = (unsigned char *)ucmalloc(message.size() + 1);
memcpy(m, message.c_str(), message.size());
bool _b = Signature::verify(signature, m, message.size() + 1);
free(m);
return _b;
}
bool Signature::verify(string signature, unsigned char *message, size_t mlen) {
size_t clen;
unsigned char *decoded = pcp_z85_decode((char *)signature.c_str(), &clen);
if(decoded == NULL)
throw exception();
if(clen != sizeof(pcp_sig_t)) {
free(decoded);
throw exception("Error: decoded signature didn't result to a proper sized sig!");
}
sig = (pcp_sig_t *)decoded;
sig2native(sig);
string sigid = string((char *)sig->id);
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();
}
}

View File

@@ -69,6 +69,10 @@ namespace pcp {
void pubkey_add(PubKey &key); void pubkey_add(PubKey &key);
void key_delete(std::string &id); void key_delete(std::string &id);
Key get_primary();
Key get_secret(std::string &id);
PubKey get_public(std::string &id);
}; };

View File

@@ -86,6 +86,22 @@ void Vault::pubkey_add(PubKey &key) {
key.is_stored(true); 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) { void Vault::key_delete(std::string &id) {
pcp_pubkey_t *p = pcphash_pubkeyexists((char *)id.c_str()); 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.");
}

View File

@@ -41,7 +41,8 @@ struct _pcp_sig_t {
typedef struct _pcp_sig_t 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, pcp_sig_t *pcp_ed_sign(unsigned char *message,
size_t messagesize, pcp_key_t *s); 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); pcp_sig_t *pcp_ed_newsig(unsigned char *hash, char *id);
void pcp_dumpsig(pcp_sig_t *sig);
#endif // _HAVE_PCP_ED_H #endif // _HAVE_PCP_ED_H

View File

@@ -83,8 +83,28 @@ void test2() {
cout << "2 ok" << endl; 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) { int main(int argc, char **argv) {
try { try {
if(argc < 2)
throw pcp::exception("usage: cpptest N");
switch(argv[1][0]) { switch(argv[1][0]) {
case '0': case '0':
test0(); test0();
@@ -97,6 +117,14 @@ int main(int argc, char **argv) {
case '2': case '2':
test2(); test2();
break; break;
case '3':
test3();
break;
default:
cerr << "usage: cpptest N" << endl;
break;
}; };
} }
catch (pcp::exception &E) { catch (pcp::exception &E) {

View File

@@ -499,6 +499,11 @@ dxmorg@florida.cops.gov
</test> </test>
<test check-cpp-import-pub> <test check-cpp-import-pub>
cmd = ./cpptest 1 cmd = ./cpptest 2
expect = /ok/
</test>
<test check-cpp-signature>
cmd = ./cpptest 3
expect = /ok/ expect = /ok/
</test> </test>