Skip to content

Instantly share code, notes, and snippets.

@wiktor-k
Forked from anidean/Crypto.cpp
Created February 22, 2020 21:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wiktor-k/124a84513d5f31b50c89e22eda8a7bc1 to your computer and use it in GitHub Desktop.
Save wiktor-k/124a84513d5f31b50c89e22eda8a7bc1 to your computer and use it in GitHub Desktop.
C++ Wrapper functions for sequoia
// Crypto.hpp
//////////////////////////////
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/sinks/rotating_file_sink.h"
#define SPDLOG_STR_H(x) #x
#define SPDLOG_STR_HELPER(x) SPDLOG_STR_H(x)
#define DEBUG(...) spdlog::log(spdlog::level::debug, "[" + fmt::format(__FILE__) + "::" + SPDLOG_STR_HELPER(__LINE__) + "::" + std::string(__func__) + "] " + fmt::format(__VA_ARGS__))
#define INFO(...) spdlog::log(spdlog::level::info, "[" + fmt::format(__FILE__) + "::" + SPDLOG_STR_HELPER(__LINE__) + "::" + std::string(__func__) + "] " + fmt::format(__VA_ARGS__))
#define WARN(...) spdlog::log(spdlog::level::warn, "[" + fmt::format(__FILE__) + "::" + SPDLOG_STR_HELPER(__LINE__) + "::" + std::string(__func__) + "] " + fmt::format(__VA_ARGS__))
#define ERROR(...) spdlog::log( spdlog::level::err, "[" + fmt::format(__FILE__) + "::" + SPDLOG_STR_HELPER(__LINE__) + "::" + std::string(__func__) + "] " + fmt::format(__VA_ARGS__))
extern std::string privateKeyString;
extern std::string publicKeyString;
namespace gpg {
void Init();
bool GetFingerprint(char* fingerprint, std::string_view publicKeyStringView, bool checkLiving=false);
bool ValidateKey(char* fingerprint, std::string_view publicKeyStringView);
bool Verify(std::string_view publicKey, std::string_view signature, std::string_view data);
bool Sign(std::string& signature, std::string_view inpustString);
bool Encrypt(std::string_view publicKeyStringView, std::string_view inputString, std::string& encryptedData);
bool Decrypt(std::string& decryptedData, std::string_view inputString);
}
/////////////////////////////////////////////////////////////////////////////////////
// Crypto.cpp
// this file handles the gpg and cryptography functions
#include "Crypto.hpp"
#if defined (__cplusplus)
extern "C" {
#endif
#include <sequoia/openpgp.h>
#if defined (__cplusplus)
}
#endif
std::string privateKeyString = "";
std::string publicKeyString = "";
namespace gpg{
pgp_cert_t publicKey;
pgp_cert_t privateKey;
void Init(){
pgp_error_t err = NULL;
publicKey = pgp_cert_from_bytes(&err, (const uint8_t*)publicKeyString.data(), (size_t)publicKeyString.length());
if(err){
ERROR("problem getting cert from bytes: {}", pgp_error_to_string(err));
exit(1);
}
err = NULL;
privateKey = pgp_cert_from_bytes(&err, (const uint8_t*)privateKeyString.data(), (size_t)privateKeyString.length());
if(err){
ERROR("problem getting cert from bytes: {}", pgp_error_to_string(err));
exit(1);
}
}
bool GetFingerprint(char* fingerprintHex, std::string_view publicKeyStringView, bool checkLiving){
pgp_error_t err = NULL;
pgp_cert_t cert = pgp_cert_from_bytes(&err, (const uint8_t*)publicKeyStringView.data(), (size_t)publicKeyStringView.length());
if (!cert){
pgp_error_free(err);
return false;
}
//if (checkLiving){
// std::string certString = pgp_cert_to_string(cert);
// DEBUG("cert string:\n{}", certString);
// pgp_cert_valid_key_iter_next(iter_signer, NULL, NULL);
//}
pgp_fingerprint_t fingerprint = pgp_cert_fingerprint(cert);
if (!fingerprint){
pgp_cert_free(cert);
pgp_error_free(err);
return false;
}
fingerprintHex = pgp_fingerprint_to_hex(fingerprint);
DEBUG("finerpring hex{}", fingerprintHex);
pgp_fingerprint_free(fingerprint);
pgp_cert_free(cert);
pgp_error_free(err);
return true;
}
bool Sign(std::string& signature, std::string_view inputString){
//INFO("SIGNING");
pgp_error_t err = NULL;
pgp_policy_t policy = pgp_standard_policy();
//signing iterator
pgp_cert_valid_key_iter_t iter_signer = pgp_cert_valid_key_iter(privateKey, policy, 0);
if(!iter_signer){
ERROR("unable to get signer iterator");
pgp_policy_free(policy);
return false;
}
pgp_cert_valid_key_iter_for_certification(iter_signer);
if(!iter_signer){
ERROR("unable to get signer iterator for certification");
pgp_policy_free(policy);
return false;
}
pgp_cert_valid_key_iter_for_signing(iter_signer);
if(!iter_signer){
ERROR("unable to get signer iterator for signing");
pgp_policy_free(policy);
return false;
}
pgp_key_t key = pgp_cert_valid_key_iter_next(iter_signer, NULL, NULL);
if(!key){
ERROR("unable to get key from iter_signer");
pgp_cert_valid_key_iter_free(iter_signer);
pgp_policy_free(policy);
return false;
}
pgp_key_pair_t signing_key_pair = pgp_key_into_key_pair(&err, pgp_key_clone(key));
if (err){
ERROR("unable to get signing keypair, {}", pgp_error_to_string(err));
pgp_error_free(err);
pgp_cert_valid_key_iter_free(iter_signer);
pgp_policy_free(policy);
return false;
}
pgp_signer_t signer = pgp_key_pair_as_signer(signing_key_pair);
pgp_writer_t writer = pgp_writer_from_bytes((uint8_t*)signature.data(), signature.capacity());
writer = pgp_armor_writer_new(&err, writer, PGP_ARMOR_KIND_SIGNATURE,
NULL, 0);
if (err){
ERROR("unable to create writer, {}", pgp_error_to_string(err));
pgp_error_free(err);
pgp_cert_valid_key_iter_free(iter_signer);
pgp_policy_free(policy);
return false;
}
// pgp_armor_writer_finalize
pgp_writer_stack_t writer_stack = pgp_writer_stack_message(writer);
writer_stack = pgp_signer_new_detached(&err, writer_stack,
&signer, 1, 0);
if (err){
ERROR("unable to create writer, {}", pgp_error_to_string(err));
pgp_error_free(err);
pgp_cert_valid_key_iter_free(iter_signer);
pgp_policy_free(policy);
return false;
}
pgp_status_t write_status =
pgp_writer_stack_write_all(&err, writer_stack,
(uint8_t*)inputString.data(), (size_t)inputString.length());
if (write_status || err){
ERROR("pgp_writer_stack_write: {}", pgp_error_to_string (err));
pgp_error_free(err);
pgp_cert_valid_key_iter_free(iter_signer);
pgp_policy_free(policy);
return false;
}
pgp_writer_stack_finalize(&err, writer_stack);
if (err){
ERROR("unable to finalize writer, {}", pgp_error_to_string(err));
ERROR("response string, {}", signature);
pgp_error_free(err);
pgp_cert_valid_key_iter_free(iter_signer);
pgp_policy_free(policy);
return false;
}
//INFO("FINISHED SIGNING");
return true;
}
bool Encrypt(std::string_view publicKeyStringView, std::string_view inputString, std::string& encryptedData){
//INFO("ENCRYPTING");
pgp_status_t rc;
pgp_error_t err;
pgp_cert_t cert;
pgp_writer_t writer;
pgp_writer_stack_t writer_stack = NULL;
pgp_policy_t policy = pgp_standard_policy ();
//cert = pgp_cert_from_file (&err, argv[1]);
cert = pgp_cert_from_bytes(&err, (const uint8_t*)publicKeyStringView.data(), (size_t)publicKeyStringView.length());
if (!cert){
ERROR("pgp_cert_from_bytes, {}", pgp_error_to_string(err));
pgp_error_free(err);
pgp_policy_free(policy);
return false;
}
pgp_cert_valid_key_iter_t iter = pgp_cert_valid_key_iter (cert, policy, 0);
if (!iter){
ERROR("no iter from cert and policy");
pgp_cert_free(cert);
pgp_policy_free(policy);
return false;
}
//DEBUG("recipient cert: \n{}", pgp_cert_debug(cert));
pgp_cert_valid_key_iter_alive (iter);
pgp_cert_valid_key_iter_revoked (iter, false);
pgp_cert_valid_key_iter_for_storage_encryption (iter);
pgp_cert_valid_key_iter_for_transport_encryption (iter);
size_t recipients_len;
pgp_recipient_t *recipients =
pgp_recipients_from_valid_key_iter (iter, &recipients_len);
//DEBUG("recipient length: {}", recipients_len);
writer = pgp_writer_from_bytes((uint8_t *)encryptedData.data(), (size_t)encryptedData.capacity());
writer = pgp_armor_writer_new (&err, writer, PGP_ARMOR_KIND_MESSAGE,
NULL, 0);
writer_stack = pgp_writer_stack_message (writer);
writer_stack = pgp_encryptor_new (&err,
writer_stack,
NULL, 0, /* no passwords */
recipients, recipients_len,
9 /* AES256 */,
0 /* No AEAD */);
//INFO("written");
if (writer_stack == NULL){
ERROR("pgp_encryptor_new: {}", pgp_error_to_string (err));
pgp_error_free(err);
pgp_cert_free(cert);
pgp_cert_valid_key_iter_free(iter);
pgp_policy_free(policy);
return false;
}
writer_stack = pgp_literal_writer_new (&err, writer_stack);
ssize_t written;
//DEBUG("inputString crypto\n{}", inputString);
written = pgp_writer_stack_write_all(&err, writer_stack, (uint8_t*)inputString.data(), (size_t)inputString.length());
if (written < 0){
ERROR("pgp_writer_stack_write: {}", pgp_error_to_string (err));
pgp_error_free(err);
pgp_cert_free(cert);
pgp_cert_valid_key_iter_free(iter);
pgp_policy_free(policy);
return false;
}
//DEBUG("encryptedData crypto\n{}", encryptedData);
rc = pgp_writer_stack_finalize (&err, writer_stack);
writer_stack = NULL;
encryptedData.resize(strlen(encryptedData.c_str()));
if (rc){
ERROR("pgp_writer_stack_write: {}", pgp_error_to_string (err));
pgp_error_free(err);
pgp_cert_free(cert);
pgp_cert_valid_key_iter_free(iter);
pgp_policy_free(policy);
return false;
}
//for (size_t i = 0; i < recipients_len; i++)
// pgp_recipient_free (recipients[i]);
free (recipients);
pgp_cert_free (cert);
pgp_policy_free (policy);
//INFO("FINISHED ENCRYPTING");
return true;
}
struct decrypt_cookie {
pgp_cert_t key;
int decrypt_called;
};
static pgp_status_t
decrypt_get_public_keys_cb (void *cookie_raw,
pgp_keyid_t *keyids, size_t keyids_len,
pgp_cert_t **certs, size_t *cert_len,
void (**our_free)(void *))
{
/* Feed the Certs to the verifier here. */
*certs = NULL;
*cert_len = 0;
*our_free = free;
return PGP_STATUS_SUCCESS;
}
static pgp_status_t
decrypt_check_cb (void *cookie_opaque, pgp_message_structure_t structure)
{
pgp_message_structure_iter_t iter = pgp_message_structure_iter (structure);
for (pgp_message_layer_t layer = pgp_message_structure_iter_next (iter);
layer;
layer = pgp_message_structure_iter_next (iter)) {
uint8_t algo;
uint8_t aead_algo;
pgp_verification_result_iter_t results;
switch (pgp_message_layer_variant (layer)) {
case PGP_MESSAGE_LAYER_COMPRESSION:
pgp_message_layer_compression (layer, &algo);
//fprintf (stderr, "Compressed using %d\n", algo);
break;
case PGP_MESSAGE_LAYER_ENCRYPTION:
pgp_message_layer_encryption (layer, &algo, &aead_algo);
if (aead_algo) {
//fprintf (stderr, "Encrypted and protected using %d/%d\n",
// algo, aead_algo);
} else {
//fprintf (stderr, "Encrypted using %d\n", algo);
}
break;
case PGP_MESSAGE_LAYER_SIGNATURE_GROUP:
pgp_message_layer_signature_group (layer, &results);
for (pgp_verification_result_t result =
pgp_verification_result_iter_next (results);
result;
result = pgp_verification_result_iter_next (results)) {
pgp_signature_t sig = NULL;
pgp_key_t key = NULL;
pgp_keyid_t keyid;
char *keyid_str = NULL;
switch (pgp_verification_result_variant (result)) {
case PGP_VERIFICATION_RESULT_GOOD_CHECKSUM:
pgp_verification_result_good_checksum (result, NULL, NULL,
&key, NULL, NULL);
keyid = pgp_key_keyid (key);
keyid_str = pgp_keyid_to_string (keyid);
//fprintf (stderr, "Good signature from %s\n", keyid_str);
break;
case PGP_VERIFICATION_RESULT_NOT_ALIVE:
pgp_verification_result_not_alive (result, NULL, NULL,
&key, NULL, NULL);
keyid = pgp_key_keyid (key);
keyid_str = pgp_keyid_to_string (keyid);
//fprintf (stderr, "Good checksum, but not alive signature from %s\n",
// keyid_str);
break;
case PGP_VERIFICATION_RESULT_MISSING_KEY:
pgp_verification_result_missing_key (result, &sig);
keyid = pgp_signature_issuer (sig);
keyid_str = pgp_keyid_to_string (keyid);
//fprintf (stderr, "No key to check signature from %s\n", keyid_str);
break;
case PGP_VERIFICATION_RESULT_ERROR: {
pgp_error_t err;
pgp_verification_result_error (result, NULL, &err);
char *err_str = pgp_error_to_string (err);
//fprintf (stderr, "Bad signature: %s\n", err_str);
free (err_str);
pgp_error_free (err);
break;
}
default:
assert (! "reachable");
}
free (keyid_str);
pgp_signature_free (sig);
pgp_key_free (key);
pgp_verification_result_free (result);
}
pgp_verification_result_iter_free (results);
break;
default:
assert (! "reachable");
}
pgp_message_layer_free (layer);
}
pgp_message_structure_iter_free (iter);
pgp_message_structure_free (structure);
/* Implement your verification policy here. */
return PGP_STATUS_SUCCESS;
}
static pgp_status_t
decrypt_cb (void *cookie_opaque,
pgp_pkesk_t *pkesks, size_t pkesk_count,
pgp_skesk_t *skesks, size_t skesk_count,
uint8_t sym_algo_hint,
pgp_decryptor_do_decrypt_cb_t *decrypt,
void *decrypt_cookie,
pgp_fingerprint_t *identity_out)
{
pgp_status_t rc;
pgp_error_t err;
struct decrypt_cookie *cookie = (struct decrypt_cookie*)cookie_opaque;
/* Prevent iterations, we only have one key to offer. */
(!cookie->decrypt_called);
cookie->decrypt_called = 1;
for (int i = 0; i < pkesk_count; i++) {
pgp_pkesk_t pkesk = pkesks[i];
pgp_keyid_t keyid = pgp_pkesk_recipient (pkesk);
pgp_cert_key_iter_t key_iter = pgp_cert_key_iter (cookie->key);
pgp_key_t key;
while ((key = pgp_cert_key_iter_next (key_iter))) {
pgp_keyid_t this_keyid = pgp_key_keyid (key);
int match = pgp_keyid_equal (this_keyid, keyid);
pgp_keyid_free (this_keyid);
if (match)
break;
pgp_key_free (key);
}
pgp_cert_key_iter_free (key_iter);
pgp_keyid_free (keyid);
if (! key)
continue;
uint8_t algo;
uint8_t session_key[1024];
size_t session_key_len = sizeof session_key;
if (pgp_pkesk_decrypt (&err,
pkesk, key, &algo,
session_key, &session_key_len)) {
ERROR("Error - pgp_pkesk_decrypt: {}", pgp_error_to_string (err));
}
pgp_key_free (key);
pgp_session_key_t sk = pgp_session_key_from_bytes (session_key,
session_key_len);
rc = decrypt (decrypt_cookie, algo, sk);
pgp_session_key_free (sk);
*identity_out = pgp_cert_fingerprint (cookie->key);
return rc;
}
return PGP_STATUS_UNKNOWN_ERROR;
}
bool Decrypt(std::string& decryptedData, std::string_view inputString){
pgp_error_t err;
pgp_cert_t cert;
pgp_reader_t source;
pgp_reader_t plaintext;
ssize_t nread;
pgp_policy_t policy = pgp_standard_policy ();
///cert = pgp_cert_from_bytes (&err, argv[1]);
//publicKey = pgp_cert_from_bytes(&err, (const uint8_t*)publicKeyString.data(), (size_t)publicKeyString.length());
//privateKey = pgp_cert_from_bytes(&err, (const uint8_t*)privateKeyString.data(), (size_t)privateKeyString.length());
if (privateKey == NULL){
ERROR("publicKey is null:");
pgp_policy_free(policy);
return false;
}
source = pgp_reader_from_bytes ((const uint8_t*)inputString.data(), inputString.length());
if (!source){
ERROR("Could not create reader from bytes");
pgp_policy_free(policy);
return false;
}
struct decrypt_cookie cookie = {
.key = privateKey,
.decrypt_called = 0,
};
plaintext = pgp_decryptor_new (&err, policy, source,
decrypt_get_public_keys_cb, decrypt_cb,
decrypt_check_cb, NULL, &cookie, 0);
if (!plaintext){
ERROR("pgp_decryptor_new: {}", pgp_error_to_string (err));
pgp_reader_free(source);
pgp_policy_free(policy);
return false;
}
unsigned int offset = 0;
nread = pgp_reader_read(&err, plaintext, (uint8_t*)decryptedData.data(), decryptedData.capacity());
if (nread < 0){
ERROR("bad read to decrypted data: {}, pgp_reader_read: {}", pgp_error_to_string (err));
pgp_reader_free(source);
pgp_policy_free(policy);
pgp_reader_free (plaintext);
return false;
}
decryptedData.resize(nread);
pgp_reader_free (plaintext);
pgp_reader_free (source);
pgp_policy_free (policy);
return true;
}
struct verify_cookie {
pgp_cert_t public_key;
bool get_secret_keys_called;
bool good_checksum;
bool good_but_expired;
bool not_alive;
bool good_but_revoked;
bool missing_keys;
bool bad_checksums;
};
static pgp_status_t
verify_get_public_keys_cb (void *cookie_opaque,
pgp_keyid_t *keyids, size_t keyids_len,
pgp_cert_t **certs, size_t *certs_len,
void (**our_free)(void *))
{
/* Feed the Certs to the verifier here. */
struct verify_cookie *cookie = (struct verify_cookie*)cookie_opaque;
*certs = (pgp_cert_t*)malloc(sizeof(pgp_cert_t));
//assert (*certs);
if (!*certs)
return PGP_STATUS_UNKNOWN_ERROR;
*certs[0] = cookie->public_key;
*certs_len = 1;
*our_free = free;
return PGP_STATUS_SUCCESS;
}
static pgp_status_t
verify_check_cb (void *cookie_opaque, pgp_message_structure_t structure)
{
struct verify_cookie *cookie = (struct verify_cookie*)cookie_opaque;
pgp_message_structure_iter_t iter = pgp_message_structure_iter (structure);
pgp_message_layer_t layer = pgp_message_structure_iter_next (iter);
if (!layer){
pgp_message_structure_iter_free (iter);
pgp_message_structure_free (structure);
return PGP_STATUS_SUCCESS;
}
pgp_verification_result_iter_t results;
if (pgp_message_layer_signature_group (layer, &results)) {
pgp_verification_result_t result = pgp_verification_result_iter_next (results);
if (!result){
pgp_verification_result_iter_free (results);
pgp_message_layer_free (layer);
pgp_message_structure_iter_free (iter);
pgp_message_structure_free (structure);
return PGP_STATUS_SUCCESS;
}
switch (pgp_verification_result_variant (result)) {
case PGP_VERIFICATION_RESULT_GOOD_CHECKSUM:
cookie->good_checksum = true;
break;
case PGP_VERIFICATION_RESULT_NOT_ALIVE:
cookie->not_alive = true;
break;
case PGP_VERIFICATION_RESULT_MISSING_KEY:
cookie->missing_keys = true;
break;
case PGP_VERIFICATION_RESULT_ERROR:
cookie->bad_checksums = true;
break;
default:
assert (! "reachable");
}
pgp_verification_result_free (result);
} else {
assert (! "reachable");
}
pgp_verification_result_iter_free (results);
pgp_message_layer_free (layer);
pgp_message_structure_iter_free (iter);
pgp_message_structure_free (structure);
return PGP_STATUS_SUCCESS;
}
bool Verify(std::string_view publicKeyStringView, std::string_view signatureStringView, std::string_view sourceStringView){
pgp_error_t err;
pgp_reader_t signature;
pgp_reader_t source;
pgp_reader_t verifier;
pgp_policy_t policy = pgp_standard_policy ();
//publicKey = pgp_cert_from_bytes(&err, (const uint8_t*)publicKeyStringView.data(), (size_t)publicKeyStringView.length());
if (!publicKey){
ERROR("Could not create publicKey from bytes");
pgp_policy_free(policy);
return false;
}
signature = pgp_reader_from_bytes((const uint8_t*)signatureStringView.data(), (size_t)signatureStringView.length());
if (!signature){
ERROR("Could not create signature from bytes");
pgp_policy_free(policy);
return false;
}
source = pgp_reader_from_bytes((const uint8_t*)sourceStringView.data(), (size_t)sourceStringView.length());
if (!source){
ERROR("Could not create source from bytes");
pgp_reader_free(signature);
pgp_policy_free(policy);
return false;
}
struct verify_cookie cookie {
.public_key = pgp_cert_from_bytes(&err, (const uint8_t*)publicKeyStringView.data(), (size_t)publicKeyStringView.length()),
.get_secret_keys_called = false,
.good_checksum = false,
.good_but_expired = false,
.not_alive = false,
.good_but_revoked = false,
.missing_keys = false,
.bad_checksums = false
};
verifier = pgp_detached_verifier_new (NULL, policy, signature, source,
verify_get_public_keys_cb, verify_check_cb,
&cookie, 0);
if (!verifier){
ERROR("Could not create detached verifier");
pgp_policy_free(policy);
pgp_reader_free(signature);
pgp_reader_free(source);
return false;
}
pgp_reader_free (verifier);
pgp_reader_free (source);
pgp_reader_free (signature);
pgp_policy_free (policy);
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment