Created
June 10, 2020 22:20
-
-
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 contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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