Commit 219f1e1d authored by Bernard van Gastel's avatar Bernard van Gastel
Browse files

Added new simplified API for pseudonimisation as unit tests for now.

parent fc764dfd
......@@ -46,6 +46,8 @@ struct Scalar {
Scalar operator-() const; // negate
bool zero() const;
bool valid() const;
std::string hex() const;
static Scalar FromHex(std::string_view view);
// returns a scalar != 0
static Scalar Random();
static Scalar FromHash(uint8_t (&value)[64]);
......@@ -72,6 +74,8 @@ struct GroupElement {
}
bool zero() const;
bool valid() const;
std::string hex() const;
static GroupElement FromHex(std::string_view view);
static GroupElement Random();
static GroupElement FromHash(uint8_t (&value)[64]);
};
......@@ -152,6 +156,13 @@ void KDFGenerateSeedKey(KDFSeedKey& seedKey);
void KDF(unsigned char *output, size_t outputLength, uint64_t subkey_id, const KDFContext& context, const KDFSeedKey& seedKey);
std::string ToHex(std::string_view in);
void FromHex(uint8_t* out, size_t out_len, std::string_view in);
template <size_t N>
void FromHex(uint8_t (&out)[N], std::string_view in) {
FromHex(out, N, in);
}
}
}
......@@ -15,6 +15,8 @@ struct ElGamal {
ElGamal(GroupElement _B, const GroupElement& _C, const GroupElement& _Y);
bool operator==(const ElGamal& rhs) const;
bool operator!=(const ElGamal& rhs) const;
std::string hex() const;
static ElGamal FromHex(std::string_view view);
};
// encrypt message M using public key Y
......
......@@ -4,6 +4,7 @@
#include <type_traits>
#include <random>
#include <sstream>
#include "sodium.h"
......@@ -64,6 +65,16 @@ bool Scalar::valid() const {
return (c != 0);
}
std::string Scalar::hex() const {
return ToHex(raw());
}
Scalar Scalar::FromHex(std::string_view view) {
if (view.size() != 64)
throw std::invalid_argument("Scalar::FromHex expected different size");
Scalar retval;
::FromHex(retval.value, view);
return retval;
}
Scalar Scalar::Random() {
Scalar r;
// does random bytes, and check if it is canonical and != zero
......@@ -81,6 +92,16 @@ Scalar Scalar::FromHash(uint8_t (&value)[64]) {
bool GroupElement::valid() const {
return crypto_core_ristretto255_is_valid_point(value);
}
std::string GroupElement::hex() const {
return ToHex(raw());
}
GroupElement GroupElement::FromHex(std::string_view view) {
if (view.size() != 64)
throw std::invalid_argument("GroupElement::FromHex expected different size");
GroupElement retval;
::FromHex(retval.value, view);
return retval;
}
GroupElement GroupElement::FromHash(uint8_t (&value)[64]) {
GroupElement r;
crypto_core_ristretto255_from_hash(r.value, value);
......@@ -173,6 +194,37 @@ void KDF(unsigned char *output, size_t outputLength, uint64_t subkey_id, const K
ENSURE(0 == crypto_kdf_derive_from_key(output, outputLength, subkey_id, context, seedKey));
}
std::string ToHex(std::string_view in) {
std::stringstream output;
output << std::hex;
for (auto sc : in) {
auto c = uint8_t(sc);
output << int(c >> 4) << int(c & 0xF);
}
return output.str();
}
uint8_t FromDigit(char _c) {
uint8_t c = static_cast<uint8_t>(_c);
if ((c >= '0') && (c <= '9')) {
return c - '0';
} else if ((c >= 'a') && (c <= 'f')) {
return c - 'a' + 10;
} else if ((c >= 'A') && (c <= 'F')) {
return c - 'A' + 10;
}
throw std::invalid_argument("char " + std::to_string(int(c)) + " is not a hex char.");
}
void FromHex(uint8_t* out, size_t out_len, std::string_view in) {
if (out_len*2 != in.length())
throw std::invalid_argument("FromHex expected different size");
for (const char* it = in.begin(); it < in.end(); it += 2) {
uint8_t l = FromDigit(*it);
uint8_t r = FromDigit(*(it+1));
*(out++) = uint8_t(l<<4) | r;
}
}
}
}
......@@ -7,6 +7,19 @@ using namespace radboud::pep;
radboud::pep::ElGamal::ElGamal(GroupElement _B, const GroupElement& _C, const GroupElement& _Y) : B(_B), C(_C), Y(_Y) {
}
std::string ElGamal::hex() const {
return B.hex() + C.hex() + Y.hex();
}
ElGamal ElGamal::FromHex(std::string_view view) {
if (view.size() != 192)
throw std::invalid_argument("ElGamal::FromHex expected different size");
ElGamal retval;
retval.B = GroupElement::FromHex(view.substr(0, 64));
retval.C = GroupElement::FromHex(view.substr(64, 64));
retval.Y = GroupElement::FromHex(view.substr(128, 64));
return retval;
}
bool radboud::pep::ElGamal::operator==(const ElGamal& rhs) const {
return B == rhs.B && C == rhs.C && Y == rhs.Y;
}
......
......@@ -4,6 +4,7 @@
#include <limits.h>
#include <optional>
#include <sstream>
IGNORE_WARNINGS_START
#include <catch2/catch.hpp>
......@@ -641,4 +642,78 @@ TEST_CASE("PEP.RistrettoExampleFromLibSodium", "[PEP]") {
CHECK(fx == k*px);
}
using GlobalPublicKey = GroupElement;
using GlobalSecretKey = Scalar;
using GlobalEncryptedPseudonym = ElGamal;
using LocalEncryptedPseudonym = ElGamal;
using LocalPseudonym = GroupElement;
using LocalDecryptionKey = Scalar;
std::tuple<GlobalPublicKey, GlobalSecretKey> GenerateGlobalKeys() {
auto secretKey = Scalar::Random();
auto publicKey = secretKey * G;
return {publicKey, secretKey};
}
GlobalEncryptedPseudonym GeneratePseudonym(std::string identity, const GlobalPublicKey& pk) {
HashSHA512 hash;
SHA512(hash, identity);
auto p = GroupElement::FromHash(hash);
return Encrypt(p, pk);
}
Scalar MakeFactor(const std::string& secret, const std::string& context) {
HashSHA512 uhash;
SHA512(uhash, secret, "|", context);
return Scalar::FromHash(uhash);
}
LocalEncryptedPseudonym MakeLocal(GlobalEncryptedPseudonym p, const std::string& secret, const std::string& decryptionContext, const std::string& pseudonimisationContext) {
Scalar u = MakeFactor(secret, pseudonimisationContext);
Scalar t = MakeFactor(secret, decryptionContext);
return RKS(p, t, u);
}
LocalDecryptionKey MakeLocalDecryptionKey(GlobalSecretKey k, std::string secret, std::string decryptionContext) {
Scalar t = MakeFactor(secret, decryptionContext);
return t * k;
}
LocalPseudonym DecryptLocalPseudonym(LocalEncryptedPseudonym p, LocalDecryptionKey k) {
return Decrypt(p, k);
}
GlobalEncryptedPseudonym RerandomizeGlobal(const GlobalEncryptedPseudonym& p) {
return Rerandomize(p, Scalar::Random());
}
LocalEncryptedPseudonym RerandomizeLocal(const LocalEncryptedPseudonym& p) {
return Rerandomize(p, Scalar::Random());
}
TEST_CASE("PEP.HighLevelAPI", "[PEP]") {
auto [publicKey, secretKey] = GenerateGlobalKeys();
std::cout << "global public key: " << publicKey.hex() << std::endl;
std::cout << "global secret key: " << secretKey.hex() << std::endl;
std::string id = "foobar";
auto gep = GeneratePseudonym(id, publicKey);
//gep = GlobalEncryptedPseudonym::FromHex(gep.hex());
std::cout << "global pseudonym for '" << id << "': " << gep.hex() << std::endl;
gep = RerandomizeGlobal(gep);
std::cout << "global pseudonym for '" << id << "': " << gep.hex() << " (after randomize)" << std::endl;
//gep = GlobalEncryptedPseudonym::FromHex(gep.hex());
auto lep = MakeLocal(gep, "very_secret_on_server", "decryption_context", "specific_pseudonimisation_context");
//lep = LocalEncryptedPseudonym::FromHex(lep.hex());
std::cout << "encrypted local pseudonym for '" << id << "': " << lep.hex() << std::endl;
lep = RerandomizeLocal(lep);
std::cout << "encrypted local pseudonym for '" << id << "': " << lep.hex() << " (after randomize)" << std::endl;
auto decryptionKey = MakeLocalDecryptionKey(secretKey, "very_secret_on_server", "decryption_context");
auto lp = DecryptLocalPseudonym(lep, decryptionKey);
auto expected = LocalPseudonym::FromHex("529c6099511d7d91aab86e4b3d2f6b529c76406da586d7aad5038df063997945");
CHECK(lp.hex() == expected.hex());
CHECK(lp == expected);
std::cout << "(decrypted local pseudonym) for '" << id << "': " << lp.hex() << std::endl;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment