Skip to content

Instantly share code, notes, and snippets.

@anidean
Created June 10, 2020 22:20
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 anidean/aaf803fdb68a2bc22994762d74a879d2 to your computer and use it in GitHub Desktop.
Save anidean/aaf803fdb68a2bc22994762d74a879d2 to your computer and use it in GitHub Desktop.
C++ Wrapper functions for gpgme - barebones, works but doesn't use async functionality. Slower than sequoia version by a lot.
// this file handles the gpg and cryptography functions
#include "Api.hpp"
#include "Crypto.hpp"
#include "run-support.h"
int import_json_key(std::string imported_key){ // this requires an armored key with \n
////DEBUG_LOG(__func__, "import key attempt 1:\n%s", key);
//rap::Document document;
//document
std::string modified_string;
size_t index = 0;
while (true) {
/* Locate the substring to replace. */
index = imported_key.find("\\n", index);
if (index == std::string::npos) break;
/* Make the replacement. */
imported_key.replace(index, 2, "\n");
/* Advance index forward so the next iteration doesn't pick it up as well. */
index += 1;
}
////DEBUG_LOG(__func__, "import key attempt 2:\n%s, %d", imported_key.c_str(), imported_key.length());
std::string result = gpg::Import(imported_key);
////DEBUG_LOG(__func__, "import key attemp 3:\n%s", key);
if (result.size() == 0){
////DEBUG_LOG(__func__, "import key failed:\n%s", imported_key.c_str());
return -1;
}
////DEBUG_LOG(__func__, "import key succeeded:\n%s", imported_key.c_str());
return 0;
}
namespace gpg{
void write_data(gpgme_data_t dh, std::string& buffer){
int ret = 0;
buffer.resize(gpgme_data_seek(dh, 0, SEEK_END));
gpgme_data_seek(dh, 0, SEEK_SET);
ret = gpgme_data_seek(dh, 0, SEEK_SET);
if (ret){
//std::cout << "Can't write data" << std::endl;
buffer.resize(0);
return;
}
ret = gpgme_data_read(dh, &buffer[0] , buffer.size());
if (ret != buffer.size()){
//std::cout << "buffer size and ret size aren't the same" << std::endl;
//std::cout << ret << " : " << buffer.size() << std::endl;
}
}
static void
print_sign_result (gpgme_sign_result_t result, gpgme_sig_mode_t type)
{
gpgme_invalid_key_t invkey;
gpgme_new_signature_t sig;
(void)type;
for (invkey = result->invalid_signers; invkey; invkey = invkey->next)
fprintf (stdout, "Signing key `%s' not used: %s <%s>\n",
nonnull (invkey->fpr),
gpg_strerror (invkey->reason), gpg_strsource (invkey->reason));
for (sig = result->signatures; sig; sig = sig->next)
{
fprintf (stdout, "Key fingerprint: %s\n", nonnull (sig->fpr));
fprintf (stdout, "Signature type : %d\n", sig->type);
fprintf (stdout, "Public key algo: %d\n", sig->pubkey_algo);
fprintf (stdout, "Hash algo .....: %d\n", sig->hash_algo);
fprintf (stdout, "Creation time .: %ld\n", sig->timestamp);
fprintf (stdout, "Sig class .....: 0x%u\n", sig->sig_class);
}
}
static void
print_encrypt_result (gpgme_encrypt_result_t result)
{
gpgme_invalid_key_t invkey;
for (invkey = result->invalid_recipients; invkey; invkey = invkey->next)
fprintf (stdout, "Encryption key `%s' not used: %s <%s>\n",
nonnull (invkey->fpr),
gpg_strerror (invkey->reason), gpg_strsource (invkey->reason));
}
static gpg_error_t signature_getpassphrase(void *hook, const char *uid_hint, const char *info, int prev_was_bad, int fd) {
std::string msg = "bastion";
ssize_t thesize = write(fd, msg.c_str(), msg.length());
thesize += write(fd, "\n", 1);
return GPG_ERR_NO_ERROR;
}
static void
print_decrypt_result (gpgme_decrypt_result_t result)
{
gpgme_recipient_t recp;
int count = 0;
fprintf (stdout, "Original file name .: %s\n", nonnull(result->file_name));
fprintf (stdout, "Wrong key usage ....: %s\n", result->wrong_key_usage? "yes":"no");
fprintf (stdout, "Compliance de-vs ...: %s\n", result->is_de_vs? "yes":"no");
//fprintf (stdout, "MIME flag ..........: %s\n", result->is_mime? "yes":"no");
fprintf (stdout, "Unsupported algo ...: %s\n", nonnull(result->unsupported_algorithm));
fprintf (stdout, "Session key ........: %s\n", nonnull (result->session_key));
// fprintf (stdout, "Symmetric algorithm : %s\n", result->symkey_algo);
for (recp = result->recipients; recp && recp->next; recp = recp->next)
{
fprintf (stdout, "Recipient ...: %d\n", count++);
fprintf (stdout, " status ....: %s\n", gpgme_strerror (recp->status));
fprintf (stdout, " keyid .....: %s\n", nonnull (recp->keyid));
fprintf (stdout, " algo ......: %s\n",
gpgme_pubkey_algo_name (recp->pubkey_algo));
}
}
gpgme_ctx_t CreateContext(){
gpgme_ctx_t ctx = nullptr;
gpgme_error_t err;
gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
init_gpgme(protocol);
err = gpgme_new(&ctx);
if (err){
goto finish;
}
gpgme_set_protocol(ctx, protocol);
finish:
return ctx;
}
void ReleaseContext(gpgme_ctx_t ctx){
gpgme_release(ctx);
}
std::string Verify(const std::string& signature, const std::string& item){
gpgme_error_t err;
gpgme_ctx_t ctx;
gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
gpgme_data_t sig = NULL;
gpgme_data_t msg = NULL;
gpgme_verify_result_t result;
std::string fingerprint = "";
init_gpgme(protocol);
err = gpgme_new(&ctx);
fail_if_err(err);
gpgme_set_protocol(ctx, protocol);
//bool print_status = true;
//if (print_status){
// //std::cout << 3 << std::endl;
// gpgme_set_status_cb(ctx, status_cb, NULL);
// gpgme_set_ctx_flag(ctx, "full-status", "1");
//}
err = gpgme_data_new_from_mem(&sig, signature.c_str(), signature.size(), 0); // may require some work, size
if (err){
//std::cout << "error allocating data object" << std::endl;
goto finish;
}
err = gpgme_data_new_from_mem(&msg, item.c_str(), item.size(), 0); // requires size
if (err){
//std::cout << "error allocating msg object" << std::endl;
goto finish;
}
err = gpgme_op_verify(ctx, sig, msg, NULL);
result = gpgme_op_verify_result(ctx);
if (result){
gpgme_signature_t sigi = result->signatures;
if (sigi->status == 0){
fingerprint = sigi->fpr?sigi->fpr:"";
}
//std::cout << gpgme_strerror (sigi->status) << std::endl;
goto finish;
////std::cout << nonnull(sigi->fpr) << std::endl;
}
if (err){
//std::cout << "verify failed" << std::endl;
goto finish;
}
//TODO NEED TO ASSIGN key_id
finish:
gpgme_data_release(msg);
gpgme_data_release(sig);
gpgme_release(ctx);
fprintf(stdout, "%s", fingerprint.c_str());
return fingerprint;
}
bool ImportAsync(PostBlob* postBlob, const std::string& newKey, void(&callBack)(PostBlob*)) {
postBlob->err = gpgme_data_new_from_mem(&postBlob->data, newKey.c_str(), newKey.length(), 1);
if (postBlob->err) return false;
gpgme_op_import_start(postBlob->ctx, postBlob->data);
postBlob->loop->defer([postBlob, &callBack](){
ImportAsyncHandler(postBlob, callBack);
});
return true;
}
void ImportAsyncHandler(PostBlob* postBlob, void (&callBack)(PostBlob*)) {
gpgme_ctx_t returnedContext = gpgme_wait(postBlob->ctx, &postBlob->err, 0);
DEBUG("in asyncwaiter, status == {}", postBlob->err);
if (postBlob->err == 0){
DEBUG("deferring ImportAsyncHandler from ImportAsyncHandler");
postBlob->loop->defer([postBlob, &callBack](){
ImportAsyncHandler(postBlob, callBack);
});
return;
}
gpgme_import_result_t importResult = gpgme_op_import_result(postBlob->ctx);
postBlob->gpgResults[postBlob->outputIndex] = importResult->imports->fpr ? importResult->imports->fpr : ""; // fingerprint
//std::unique_ptr<std::string> fingerprint = std::make_unique<std::string>(importResult->imports->fpr? importResult->imports->fpr:"");
gpgme_data_release(postBlob->data);
callBack(postBlob);
}
std::string Import(const std::string& new_key){
gpgme_error_t err;
gpgme_ctx_t ctx;
gpgme_import_result_t impres;
gpgme_data_t data;
std::string fingerprint = "";
//DEBUG_LOG(__func__, "1\n%s\n", new_key.c_str());
init_gpgme(GPGME_PROTOCOL_OpenPGP);
//DEBUG_LOG(__func__, "2\n");
err = gpgme_new(&ctx);
//DEBUG_LOG(__func__, "3\n");
if(err) goto finish;
//DEBUG_LOG(__func__, "4\n");
gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
//DEBUG_LOG(__func__, "5\n");
err = gpgme_data_new_from_mem(&data, new_key.c_str(), new_key.size(), 1);
//DEBUG_LOG(__func__, "6\n");
if(err) goto finish;
//DEBUG_LOG(__func__, "7:\n");
err = gpgme_op_import(ctx, data);
//DEBUG_LOG(__func__, "8\n");
if(err) goto finish;
//DEBUG_LOG(__func__, "9\n");
impres = gpgme_op_import_result(ctx);
//DEBUG_LOG(__func__, "10\n");
if (!impres){
fprintf(stdout, "no import result returned");
goto finish;
}
//DEBUG_LOG(__func__, "11\n");
print_import_result(impres);
fingerprint = impres->imports->fpr? impres->imports->fpr:"";
//DEBUG_LOG(__func__, "12\n");
goto finish;
//print_import_result(impres);
//gpgme_data_release(data);
finish:
gpgme_data_release(data);
gpgme_release(ctx);
fprintf(stdout, "%s", fingerprint.c_str());
return fingerprint;
}
std::string Export(const std::string& fingerprint){
std::string exported_key = "";
gpgme_error_t err;
gpgme_ctx_t ctx;
gpgme_key_t key;
gpgme_keylist_result_t result;
gpgme_data_t out;
gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
gpgme_export_mode_t mode =0;
init_gpgme(protocol);
err = gpgme_new(&ctx);
if (err){
//std::cout << "Export: error getting context." << std::endl;
goto finish;
}
gpgme_set_protocol(ctx, protocol);
gpgme_set_armor(ctx, 1);
err = gpgme_data_new(&out);
if (err){
//std::cout << "Export: error initializing output data" << std::endl;
goto finish;
}
err = gpgme_op_export(ctx, fingerprint.c_str(), mode, out);
if (err){
//std::cout << "Export: error exporting key data" << std::endl;
goto finish;
}
write_data(out, exported_key);
finish:
gpgme_data_release(out);
gpgme_release(ctx);
return exported_key;
}
bool DeleteKey(const std::string& fingerprint){
bool deleted = false;
gpgme_key_t subject[1] = {NULL};
gpgme_error_t err;
gpgme_ctx_t ctx;
gpgme_key_t key;
gpgme_keylist_result_t result;
gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
uint flags = GPGME_DELETE_ALLOW_SECRET | GPGME_DELETE_FORCE;
init_gpgme(protocol);
err = gpgme_new(&ctx);
if (err){
//std::cout << "DeleteKey: error getting context." << std::endl;
goto finish;
}
gpgme_set_protocol(ctx, protocol);
err = gpgme_get_key(ctx, fingerprint.c_str(), &subject[0], 0);
if (err){
//std::cout << "DeleteKey: error getting subject's key." << std::endl;
goto finish;
}
err = gpgme_op_delete_ext(ctx, subject[0], flags);
if (err){
//std::cout << "DeleteKey: error deleting key." << std::endl;
goto finish;
}
deleted = true;
finish:
gpgme_key_unref(subject[0]);
gpgme_release(ctx);
return deleted;
}
std::string Sign(const std::string& input_string){
std::string detached_signature;
gpgme_error_t err;
gpgme_ctx_t ctx;
gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
gpgme_sig_mode_t sigmode = GPGME_SIG_MODE_DETACH;
gpgme_data_t in, out;
gpgme_sign_result_t result;
gpgme_key_t akey;
std::string fingerprint = "534B90B5A8ECE452D18F6018D624EE1B4C1A2F77"; // bastion host
init_gpgme(protocol);
err = gpgme_new (&ctx);
if (err){
//std::cout << "Sign: error getting context." << std::endl;
goto finish;
}
gpgme_set_protocol(ctx,protocol);
gpgme_set_armor(ctx, 1);
gpgme_set_pinentry_mode(ctx, GPGME_PINENTRY_MODE_LOOPBACK);
err = gpgme_get_key(ctx, fingerprint.c_str(), &akey, 1);
if (err){
//std::cout << "Sign: error getting context." << std::endl;
goto finish;
}
err = gpgme_signers_add(ctx, akey);
if (err){
//std::cout << "Sign: error adding signer." << std::endl;
goto finish;
}
gpgme_key_unref(akey);
err = gpgme_data_new_from_mem(&in, input_string.c_str(), input_string.size(), 0);
if (err){
//std::cout << "Sign: error getting data from memory." << std::endl;
goto finish;
}
err = gpgme_data_new(&out);
if (err){
//std::cout << "Sign: error initializing out data." << std::endl;
goto finish;
}
gpgme_set_passphrase_cb(ctx, signature_getpassphrase, NULL);
err = gpgme_op_sign(ctx, in, out, sigmode);
result = gpgme_op_sign_result(ctx);
if (result){
//print_sign_result(result, sigmode);
}
if (err){
//std::cout << "Sign: signing failed - " << gpg_strerror(err) << std::endl;
goto finish;
}
//std::cout << "Begin output: \n" << std::endl;
write_data(out, detached_signature);
//std::cout << detached_signature << std::endl;
//std::cout << "End output: \n" << std::endl;
finish:
gpgme_data_release(in);
gpgme_data_release(out);
gpgme_release(ctx);
return detached_signature;
}
std::string Encrypt(const std::string& fingerprint, const std::string& input_string){
std::string encrypted_string;
gpgme_error_t err;
gpgme_ctx_t ctx;
gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
gpgme_data_t in, out;
gpgme_encrypt_result_t result;
gpgme_key_t recipient[2] = {NULL, NULL};
//fingerprint = "9C347F0768397A396107959D9782AB5580D9B0A0"; // newmember default
gpgme_encrypt_flags_t flags = GPGME_ENCRYPT_ALWAYS_TRUST;
gpgme_off_t offset;
////DEBUG_LOG(__func__, "inside");
init_gpgme(protocol);
err = gpgme_new(&ctx);
////DEBUG_LOG(__func__, "after gpgme_new");
if (err){
//std::cout << "Encrypt: error getting context." << std::endl;
goto finish;
}
gpgme_set_protocol(ctx, protocol);
gpgme_set_armor(ctx, 1);
err = gpgme_get_key(ctx, fingerprint.c_str(), &recipient[0], 0);
if (err){
//std::cout << "Encrypt: error getting recipient key." << std::endl;
goto finish;
}
////DEBUG_LOG(__func__, "after get get key");
err = gpgme_data_new_from_mem(&in, input_string.c_str(), input_string.size(), 0);
if (err){
//std::cout << "Encrypt: error getting data from mem." << std::endl;
goto finish;
}
////DEBUG_LOG(__func__, "after data new from mem");
err = gpgme_data_new(&out);
if (err){
//std::cout << "Encrypt: error initializing output." << std::endl;
goto finish;
}
////DEBUG_LOG(__func__, "before encrypt- recipient: %s, in: %s", fingerprint.c_str(), input_string.c_str());
err = gpgme_op_encrypt(ctx, recipient, flags, in, out);
////DEBUG_LOG(__func__, "after encrypt");
//std::cout << "here" << std::endl;
result = gpgme_op_encrypt_result (ctx);
//std::cout << "here" << std::endl;
//if (result)
// print_encrypt_result (result);
if (err){
//std::cout << "Encrypt: error getting recipient key." << std::endl;
//std::cout << gpg_strerror (err) << std::endl;
goto finish;
}
//std::cout << "Begin output" << std::endl;
write_data(out, encrypted_string);
//std::cout << "End output" << std::endl;
finish:
gpgme_data_release(out);
gpgme_data_release(in);
gpgme_key_unref(recipient[0]);
gpgme_release(ctx);
return encrypted_string;
}
std::string Decrypt(const std::string& input_string){
std::string fingerprint = "534B90B5A8ECE452D18F6018D624EE1B4C1A2F77"; // bastion host soon
std::string decrypted_string;
gpgme_error_t err;
gpgme_ctx_t ctx;
gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
gpgme_decrypt_flags_t flags = GPGME_DECRYPT_UNWRAP;
gpgme_data_t in = NULL;
gpgme_data_t out = NULL;
gpgme_decrypt_result_t result;
init_gpgme(protocol);
err = gpgme_new(&ctx);
if (err){
//std::cout << "Decrypt: error initializing context." << std::endl;
goto finish;
}
gpgme_set_protocol(ctx, protocol);
err = gpgme_data_new_from_mem(&in, input_string.c_str(), input_string.length(), 0);
if (err){
//std::cout << "Decrypt: error getting input data" << std::endl;
goto finish;
}
err = gpgme_data_new(&out);
if (err){
//std::cout << "Decrypt: error initializing output." << std::endl;
goto finish;
}
err = gpgme_op_decrypt(ctx, in, out);
gpgme_set_passphrase_cb(ctx, signature_getpassphrase, NULL);
result = gpgme_op_decrypt_result(ctx);
if (err){
//std::cout << "Decrypt: error decrypting data" << std::endl;
//std::cout << gpgme_strerror (err) << std::endl;
goto finish;
}
if (result)
{
//print_decrypt_result (result);
//std::cout << "Begin Output:\n" << std::endl;
write_data (out, decrypted_string);
//std::cout << decrypted_string << std::endl;
//std::cout << "\nEnd Output.\n" << std::endl;
}
finish:
gpgme_data_release (out);
gpgme_data_release (in);
gpgme_release (ctx);
return decrypted_string;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment