/* Copy the data from the GPGME object DAT to a newly created file with name OUTFILE. Returns 0 on success. */ static gpgme_error_t data_to_file (gpgme_data_t *dat, const char *outfile) { FILE *out; char *buf; size_t n=0; out = fopen (outfile, "wb"); if (!out) return GPG_ERR_UNKNOWN_ERRNO; /* FIXME: We need to check why we can't use errno here. */ /* FIXME: Why at all are we using an in memory object wqhen we are later going to write to a file anyway. */ buf = gpgme_data_release_and_get_mem (*dat, &n); *dat = NULL; if (!n) { fclose (out); return GPG_ERR_EOF; /* FIXME: wrap this into a gpgme_error() */ } fwrite (buf, 1, n, out); fclose (out); /* FIXME: We have no error checking above. */ gpgme_free (buf); return 0; }
/* ------------------ * get ascii armored public key * FREE MEMORY AFTER USAGE OF RETURN VALUE! * ------------------ */ char* get_key_armored(const char* fpr) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_data_t key_data; gpgme_key_t key; gpgme_key_t key_arr[2]; key_arr[0] = key_arr[1] = NULL; size_t len = 0; char* key_str = NULL; char* key_str_dup = NULL; // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // get key by fingerprint error = gpgme_get_key(ctx,fpr,&key,0); if (error || !key) { purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } key_arr[0] = key; // create data containers gpgme_data_new(&key_data); // export key gpgme_set_armor(ctx,1); error = gpgme_op_export_keys (ctx, key_arr, 0, key_data); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_export_keys failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // release memory for data containers key_str = gpgme_data_release_and_get_mem(key_data,&len); if (key_str != NULL) { key_str[len] = 0; key_str_dup = g_strdup(key_str); } gpgme_free(key_str); // close gpgme connection gpgme_release (ctx); // we got the key, YEAH :) return key_str_dup; }
char *gpg_encrypt_msg(const char *msg, const char *fpr) { gpgme_ctx_t ctx; gpgme_data_t plain, cipher; gpgme_error_t err; char *temp, *str; char *ret = 0; gpgme_key_t key_arr[2] = {0, 0}; size_t n = 0; err = gpgme_new(&ctx); if (err) { return 0; } gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP); gpgme_set_armor(ctx, 1); err = gpgme_get_key(ctx, fpr, &key_arr[0], 0); if (err) { gpgme_release(ctx); return 0; } err = gpgme_data_new_from_mem(&plain, msg, strlen(msg), 0); if (err) { goto end; } gpgme_data_new(&cipher); err = gpgme_op_encrypt(ctx, key_arr, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); gpgme_data_release(plain); if (err) { gpgme_data_release(cipher); goto end; } temp = gpgme_data_release_and_get_mem(cipher, &n); if (!temp) { goto end; } str = strndup(temp, n); gpgme_free(temp); if (!str) { goto end; } ret = drop_gpg_headers(str); free(str); end: gpgme_key_unref(key_arr[0]); gpgme_release(ctx); return ret; }
/* ------------------ * decrypt a plain string with the key found with fingerprint fpr * FREE MEMORY AFTER USAGE OF RETURN VALUE * ------------------ */ static char* decrypt(char* cipher_str) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_data_t plain,cipher; size_t len = 0; char* plain_str = NULL; char* plain_str_dup = NULL; char* armored_buffer; // add header and footer: armored_buffer = str_armor(cipher_str); // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // create data containers gpgme_data_new_from_mem (&cipher, armored_buffer,strlen(armored_buffer),1); gpgme_data_new(&plain); // decrypt error = gpgme_op_decrypt(ctx,cipher,plain); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_decrypt failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // release memory for data containers gpgme_data_release(cipher); plain_str = gpgme_data_release_and_get_mem(plain,&len); if (plain_str != NULL) { plain_str[len] = 0; plain_str_dup = g_strdup(plain_str); } gpgme_free(plain_str); // close gpgme connection gpgme_release (ctx); return plain_str_dup; }
/* The main GPG decryption routine for libfko. */ int gpgme_decrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const char *pw, unsigned char **out, size_t *out_len) { char *tmp_buf; int res; gpgme_ctx_t gpg_ctx = NULL; gpgme_data_t cipher = NULL; gpgme_data_t plaintext = NULL; gpgme_error_t err; gpgme_decrypt_result_t decrypt_res; gpgme_verify_result_t verify_res; /* Initialize gpgme */ res = init_gpgme(fko_ctx); if(res != FKO_SUCCESS) return(res); gpg_ctx = fko_ctx->gpg_ctx; err = gpgme_data_new(&plaintext); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_PLAINTEXT_DATA_OBJ); } /* Initialize the cipher data (place into gpgme_data object) */ err = gpgme_data_new_from_mem(&cipher, (char*)indata, in_len, 0); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_CIPHER_DATA_OBJ); } /* Set the passphrase callback. */ gpgme_set_passphrase_cb(gpg_ctx, my_passphrase_cb, (void*)pw); /* Now decrypt and verify. */ err = gpgme_op_decrypt_verify(gpg_ctx, cipher, plaintext); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_data_release(cipher); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_DECRYPT_FAILED); } /* Done with the cipher text. */ gpgme_data_release(cipher); /* We check the "usupported_algorithm" flag in the decrypt result. */ decrypt_res = gpgme_op_decrypt_result(gpg_ctx); if(decrypt_res->unsupported_algorithm) { gpgme_data_release(plaintext); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; return(FKO_ERROR_GPGME_DECRYPT_UNSUPPORTED_ALGORITHM); } /* Now verify the signatures if so configured. */ if(fko_ctx->verify_gpg_sigs) { verify_res = gpgme_op_verify_result(gpg_ctx); res = process_sigs(fko_ctx, verify_res); if(res != FKO_SUCCESS) { gpgme_data_release(plaintext); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; return(res); } } /* Get the encrypted data and its length from the gpgme data object. */ tmp_buf = gpgme_data_release_and_get_mem(plaintext, out_len); /* Use calloc here with an extra byte because I am not sure if all systems * will include the terminating NULL with the decrypted data (which is * expected to be a string). */ *out = calloc(1, *out_len+1); /* This is freed upon fko_ctx destruction. */ if(*out == NULL) res = FKO_ERROR_MEMORY_ALLOCATION; else { memcpy(*out, tmp_buf, *out_len); res = FKO_SUCCESS; } gpgme_free(tmp_buf); return(res); }
/* The main GPG encryption routine for libfko. */ int gpgme_encrypt(fko_ctx_t fko_ctx, unsigned char *indata, size_t in_len, const char *pw, unsigned char **out, size_t *out_len) { char *tmp_buf; int res; gpgme_ctx_t gpg_ctx = NULL; gpgme_data_t cipher = NULL; gpgme_data_t plaintext = NULL; gpgme_key_t key[2] = { NULL, NULL }; gpgme_error_t err; /* Initialize gpgme */ res = init_gpgme(fko_ctx); if(res != FKO_SUCCESS) return(res); gpg_ctx = fko_ctx->gpg_ctx; /* Initialize the plaintext data (place into gpgme_data object) */ err = gpgme_data_new_from_mem(&plaintext, (char*)indata, in_len, 1); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_PLAINTEXT_DATA_OBJ); } /* Set protocol */ err = gpgme_set_protocol(gpg_ctx, GPGME_PROTOCOL_OpenPGP); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_SET_PROTOCOL); } /* Set ascii-armor off (we will be base64-encoding the encrypted data * ourselves. */ gpgme_set_armor(gpg_ctx, 0); /* The gpgme_encrypt.... functions take a recipient key array, so we add * our single key here. */ key[0] = fko_ctx->recipient_key; /* Create the buffer for our encrypted data. */ err = gpgme_data_new(&cipher); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_CIPHER_DATA_OBJ); } /* Here we add the signer to the gpgme context if there is one. */ if(fko_ctx->gpg_signer != NULL) { gpgme_signers_clear(gpg_ctx); err = gpgme_signers_add(gpg_ctx, fko_ctx->signer_key); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_data_release(cipher); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; return(FKO_ERROR_GPGME_ADD_SIGNER); } } /* Set the passphrase callback. */ gpgme_set_passphrase_cb(gpg_ctx, my_passphrase_cb, (void*)pw); /* Encrypt and sign (if a sig was provided) the SPA data. */ if(fko_ctx->gpg_signer == NULL) err = gpgme_op_encrypt( gpg_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, cipher ); else err = gpgme_op_encrypt_sign( gpg_ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, plaintext, cipher ); if(gpg_err_code(err) != GPG_ERR_NO_ERROR) { gpgme_data_release(plaintext); gpgme_data_release(cipher); gpgme_release(gpg_ctx); fko_ctx->gpg_ctx = NULL; fko_ctx->gpg_err = err; if(gpgme_err_code(err) == GPG_ERR_CANCELED) return(FKO_ERROR_GPGME_BAD_PASSPHRASE); return(FKO_ERROR_GPGME_ENCRYPT_SIGN); } /* Done with the plaintext. */ gpgme_data_release(plaintext); /* Get the encrypted data and its length from the gpgme data object. * BTW, this does free the memory used by cipher. */ tmp_buf = gpgme_data_release_and_get_mem(cipher, out_len); *out = malloc(*out_len); /* This is freed upon fko_ctx destruction. */ if(*out == NULL) res = FKO_ERROR_MEMORY_ALLOCATION; else { memcpy(*out, tmp_buf, *out_len); res = FKO_SUCCESS; } gpgme_free(tmp_buf); return(res); }
retvalue signature_check_inline(const struct signature_requirement *requirements, const char *filename, char **chunk_p) { gpg_error_t err; gpgme_data_t dh, dh_gpg; int fd; fd = open(filename, O_RDONLY|O_NOCTTY); if (fd < 0) { int e = errno; fprintf(stderr, "Error opening '%s': %s\n", filename, strerror(e)); return RET_ERRNO(e); } err = gpgme_data_new_from_fd(&dh_gpg, fd); if (err != 0) { (void)close(fd); return gpgerror(err); } err = gpgme_data_new(&dh); if (err != 0) { (void)close(fd); gpgme_data_release(dh_gpg); return gpgerror(err); } err = gpgme_op_verify(context, dh_gpg, NULL, dh); (void)close(fd); if (gpg_err_code(err) == GPG_ERR_NO_DATA) { char *chunk; const char *n; size_t len; retvalue r; gpgme_data_release(dh); gpgme_data_release(dh_gpg); r = readtextfile(filename, filename, &chunk, &len); assert (r != RET_NOTHING); if (RET_WAS_ERROR(r)) return r; assert (chunk[len] == '\0'); len = chunk_extract(chunk, chunk, len, false, &n); if (chunk[0] == '-' || *n != '\0') { fprintf(stderr, "Cannot parse '%s': found no signature but does not looks safe to be assumed unsigned, either.\n", filename); free(chunk); return RET_ERROR; } if (requirements != NULL) { free(chunk); return RET_ERROR_BADSIG; } fprintf(stderr, "WARNING: No signature found in %s, assuming it is unsigned!\n", filename); assert (chunk[len] == '\0'); *chunk_p = realloc(chunk, len+1); if (FAILEDTOALLOC(*chunk_p)) *chunk_p = chunk; return RET_OK; } else { char *plain_data, *chunk; const char *n; size_t plain_len, len; retvalue r; if (err != 0) { gpgme_data_release(dh_gpg); gpgme_data_release(dh); return gpgerror(err); } gpgme_data_release(dh_gpg); plain_data = gpgme_data_release_and_get_mem(dh, &plain_len); if (plain_data == NULL) { fprintf(stderr, "Error: libgpgme failed to extract the plain data out of\n" "'%s'.\n" "While it did so in a way indicating running out of memory, experience says\n" "this also happens when gpg returns a error code it does not understand.\n" "To check this please try running gpg --verify '%s' manually.\n" "Continuing extracting it ignoring all signatures...", filename, filename); return RET_ERROR; } chunk = malloc(plain_len+1); if (FAILEDTOALLOC(chunk)) return RET_ERROR_OOM; len = chunk_extract(chunk, plain_data, plain_len, false, &n); #ifdef HAVE_GPGPME_FREE gpgme_free(plain_data); #else free(plain_data); #endif assert (len <= plain_len); if (plain_len != (size_t)(n - plain_data)) { fprintf(stderr, "Cannot parse '%s': extraced signed data looks malformed.\n", filename); r = RET_ERROR; } else r = verify_signature(requirements, filename, NULL); if (RET_IS_OK(r)) { *chunk_p = realloc(chunk, len+1); if (FAILEDTOALLOC(*chunk_p)) *chunk_p = chunk; } else free(chunk); return r; } }
static void gpa_file_sign_operation_done_cb (GpaContext *context, gpg_error_t err, GpaFileSignOperation *op) { gpa_file_item_t file_item = GPA_FILE_OPERATION (op)->current->data; if (file_item->direct_in) { size_t len; char *sig_gpgme = gpgme_data_release_and_get_mem (op->sig, &len); op->sig = NULL; /* Do the memory allocation dance. */ if (sig_gpgme) { /* Conveniently make ASCII stuff into a string. */ file_item->direct_out = g_malloc (len + 1); memcpy (file_item->direct_out, sig_gpgme, len); gpgme_free (sig_gpgme); file_item->direct_out[len] = '\0'; /* Yep, excluding the trailing zero. */ file_item->direct_out_len = len; } else { file_item->direct_out = NULL; file_item->direct_out_len = 0; } } /* Do clean up on the operation */ gpgme_data_release (op->plain); op->plain = NULL; close (op->plain_fd); op->plain_fd = -1; gpgme_data_release (op->sig); op->sig = NULL; close (op->sig_fd); op->sig_fd = -1; gtk_widget_hide (GPA_FILE_OPERATION (op)->progress_dialog); if (err) { if (! file_item->direct_in) { /* If an error happened, (or the user canceled) delete the created file and abort further signions. */ g_unlink (op->sig_filename); g_free (op->sig_filename); } g_signal_emit_by_name (GPA_OPERATION (op), "completed", err); } else { /* We've just created a file */ g_signal_emit_by_name (GPA_OPERATION (op), "created_file", file_item); /* Go to the next file in the list and sign it */ GPA_FILE_OPERATION (op)->current = g_list_next (GPA_FILE_OPERATION (op)->current); gpa_file_sign_operation_next (op); } }
static retvalue extract_signed_data(const char *buffer, size_t bufferlen, const char *filenametoshow, char **chunkread, /*@null@*/ /*@out@*/struct signatures **signatures_p, bool *brokensignature) { char *chunk; gpg_error_t err; gpgme_data_t dh, dh_gpg; size_t plain_len; char *plain_data; retvalue r; struct signatures *signatures = NULL; bool foundbroken = false; r = signature_init(false); if (RET_WAS_ERROR(r)) return r; err = gpgme_data_new_from_mem(&dh_gpg, buffer, bufferlen, 0); if (err != 0) return gpgerror(err); err = gpgme_data_new(&dh); if (err != 0) { gpgme_data_release(dh_gpg); return gpgerror(err); } err = gpgme_op_verify(context, dh_gpg, NULL, dh); if (gpg_err_code(err) == GPG_ERR_NO_DATA) { if (verbose > 5) fprintf(stderr, "Data seems not to be signed trying to use directly....\n"); gpgme_data_release(dh); gpgme_data_release(dh_gpg); return RET_NOTHING; } else { if (err != 0) { gpgme_data_release(dh_gpg); gpgme_data_release(dh); return gpgerror(err); } if (signatures_p != NULL || brokensignature != NULL) { r = checksigs(filenametoshow, (signatures_p!=NULL)?&signatures:NULL, (brokensignature!=NULL)?&foundbroken:NULL); if (RET_WAS_ERROR(r)) { gpgme_data_release(dh_gpg); gpgme_data_release(dh); return r; } } gpgme_data_release(dh_gpg); plain_data = gpgme_data_release_and_get_mem(dh, &plain_len); if (plain_data == NULL) { fprintf(stderr, "(not yet fatal) ERROR: libgpgme failed to extract the plain data out of\n" "'%s'.\n" "While it did so in a way indicating running out of memory, experience says\n" "this also happens when gpg returns a error code it does not understand.\n" "To check this please try running gpg --verify '%s' manually.\n" "Continuing extracting it ignoring all signatures...", filenametoshow, filenametoshow); signatures_free(signatures); return RET_NOTHING; } if (signatures != NULL) { r = check_primary_keys(signatures); if (RET_WAS_ERROR(r)) { signatures_free(signatures); return r; } } } if (FAILEDTOALLOC(plain_data)) r = RET_ERROR_OOM; else { size_t len; const char *afterchanges; chunk = malloc(plain_len + 1); len = chunk_extract(chunk, plain_data, plain_len, false, &afterchanges); if (len == 0) { fprintf(stderr, "Could only find spaces within '%s'!\n", filenametoshow); free(chunk); r = RET_ERROR; } else if (afterchanges != plain_data + plain_len) { if (*afterchanges == '\0') fprintf(stderr, "Unexpected \\0 character within '%s'!\n", filenametoshow); else fprintf(stderr, "Unexpected data after ending empty line in '%s'!\n", filenametoshow); free(chunk); r = RET_ERROR; } else *chunkread = chunk; } #ifdef HAVE_GPGPME_FREE gpgme_free(plain_data); #else free(plain_data); #endif if (RET_IS_OK(r)) { if (signatures_p != NULL) *signatures_p = signatures; if (brokensignature != NULL) *brokensignature = foundbroken; } else { signatures_free(signatures); } return r; }
/* ------------------ * encrypt a plain string with the key found with fingerprint fpr * ------------------ */ static char* encrypt(const char* plain_str, const char* fpr) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_key_t key; gpgme_data_t plain,cipher; char* cipher_str = NULL; char* cipher_str_dup = NULL; size_t len; gpgme_key_t key_arr[2]; key_arr[0] = NULL; key_arr[1] = NULL; // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // get key by fingerprint error = gpgme_get_key(ctx,fpr,&key,0); if (error || !key) { purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } key_arr[0] = key; // create data containers gpgme_data_new_from_mem (&plain, plain_str,strlen(plain_str),1); gpgme_data_new(&cipher); // encrypt, ascii armored gpgme_set_armor(ctx,1); error = gpgme_op_encrypt (ctx, key_arr,GPGME_ENCRYPT_ALWAYS_TRUST,plain,cipher); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_encrypt failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // release memory for data containers gpgme_data_release(plain); cipher_str = gpgme_data_release_and_get_mem(cipher,&len); if (cipher_str != NULL) { cipher_str_dup = str_unarmor(cipher_str); } gpgme_free(cipher_str); // close gpgme connection gpgme_release (ctx); return cipher_str_dup; }
/* ------------------ * sign a plain string with the key found with fingerprint fpr * FREE MEMORY AFTER USAGE OF RETURN VALUE! * ------------------ */ static char* sign(const char* plain_str,const char* fpr) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_key_t key; gpgme_data_t plain,sig; const int MAX_LEN = 10000; char *sig_str = NULL; char *sig_str_dup = NULL; size_t len = 0; // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // get key by fingerprint error = gpgme_get_key(ctx,fpr,&key,1); if (error || !key) { purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // select signers gpgme_signers_clear(ctx); error = gpgme_signers_add (ctx,key); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_signers_add failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // create data containers gpgme_data_new_from_mem (&plain, plain_str,strlen(plain_str),1); gpgme_data_new(&sig); // sign message, ascii armored gpgme_set_armor(ctx,1); error = gpgme_op_sign(ctx,plain,sig,GPGME_SIG_MODE_DETACH); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_sign failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // release memory for data containers gpgme_data_release(plain); sig_str = gpgme_data_release_and_get_mem(sig,&len); if (sig_str != NULL) { sig_str[len] = 0; sig_str_dup = str_unarmor(sig_str); } gpgme_free(sig_str); // close gpgme connection gpgme_release (ctx); return sig_str_dup; }
char* p_gpg_decrypt(const char *const cipher) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL); char *cipher_with_headers = _add_header_footer(cipher, PGP_MESSAGE_HEADER, PGP_MESSAGE_FOOTER); gpgme_data_t cipher_data; gpgme_data_new_from_mem(&cipher_data, cipher_with_headers, strlen(cipher_with_headers), 1); free(cipher_with_headers); gpgme_data_t plain_data; gpgme_data_new(&plain_data); error = gpgme_op_decrypt(ctx, cipher_data, plain_data); gpgme_data_release(cipher_data); if (error) { log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_data_release(plain_data); gpgme_release(ctx); return NULL; } gpgme_decrypt_result_t res = gpgme_op_decrypt_result(ctx); if (res) { GString *recipients_str = g_string_new(""); gpgme_recipient_t recipient = res->recipients; while (recipient) { gpgme_key_t key; error = gpgme_get_key(ctx, recipient->keyid, &key, 1); if (!error && key) { const char *addr = gpgme_key_get_string_attr(key, GPGME_ATTR_EMAIL, NULL, 0); if (addr) { g_string_append(recipients_str, addr); } gpgme_key_unref(key); } if (recipient->next) { g_string_append(recipients_str, ", "); } recipient = recipient->next; } log_debug("GPG: Decrypted message for recipients: %s", recipients_str->str); g_string_free(recipients_str, TRUE); } gpgme_release(ctx); size_t len = 0; char *plain_str = gpgme_data_release_and_get_mem(plain_data, &len); char *result = NULL; if (plain_str) { plain_str[len] = 0; result = g_strdup(plain_str); } gpgme_free(plain_str); if (passphrase_attempt) { passphrase = strdup(passphrase_attempt); } return result; }
char* p_gpg_encrypt(const char *const barejid, const char *const message, const char *const fp) { ProfPGPPubKeyId *pubkeyid = g_hash_table_lookup(pubkeys, barejid); if (!pubkeyid) { return NULL; } if (!pubkeyid->id) { return NULL; } gpgme_key_t keys[3]; keys[0] = NULL; keys[1] = NULL; keys[2] = NULL; gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } gpgme_key_t receiver_key; error = gpgme_get_key(ctx, pubkeyid->id, &receiver_key, 0); if (error || receiver_key == NULL) { log_error("GPG: Failed to get receiver_key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } keys[0] = receiver_key; gpgme_key_t sender_key = NULL; error = gpgme_get_key(ctx, fp, &sender_key, 0); if (error || sender_key == NULL) { log_error("GPG: Failed to get sender_key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } keys[1] = sender_key; gpgme_data_t plain; gpgme_data_new_from_mem(&plain, message, strlen(message), 1); gpgme_data_t cipher; gpgme_data_new(&cipher); gpgme_set_armor(ctx, 1); error = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, plain, cipher); gpgme_data_release(plain); gpgme_release(ctx); gpgme_key_unref(receiver_key); gpgme_key_unref(sender_key); if (error) { log_error("GPG: Failed to encrypt message. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } size_t len; char *cipher_str = gpgme_data_release_and_get_mem(cipher, &len); char *result = NULL; if (cipher_str) { GString *cipher_gstr = g_string_new(""); g_string_append_len(cipher_gstr, cipher_str, len); result = _remove_header_footer(cipher_gstr->str, PGP_MESSAGE_FOOTER); g_string_free(cipher_gstr, TRUE); gpgme_free(cipher_str); } return result; }
char* p_gpg_sign(const char *const str, const char *const fp) { gpgme_ctx_t ctx; gpgme_error_t error = gpgme_new(&ctx); if (error) { log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error)); return NULL; } gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL); gpgme_key_t key = NULL; error = gpgme_get_key(ctx, fp, &key, 1); if (error || key == NULL) { log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } gpgme_signers_clear(ctx); error = gpgme_signers_add(ctx, key); gpgme_key_unref(key); if (error) { log_error("GPG: Failed to load signer. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_release(ctx); return NULL; } char *str_or_empty = NULL; if (str) { str_or_empty = strdup(str); } else { str_or_empty = strdup(""); } gpgme_data_t str_data; gpgme_data_new_from_mem(&str_data, str_or_empty, strlen(str_or_empty), 1); free(str_or_empty); gpgme_data_t signed_data; gpgme_data_new(&signed_data); gpgme_set_armor(ctx,1); error = gpgme_op_sign(ctx, str_data, signed_data, GPGME_SIG_MODE_DETACH); gpgme_data_release(str_data); gpgme_release(ctx); if (error) { log_error("GPG: Failed to sign string. %s %s", gpgme_strsource(error), gpgme_strerror(error)); gpgme_data_release(signed_data); return NULL; } char *result = NULL; size_t len = 0; char *signed_str = gpgme_data_release_and_get_mem(signed_data, &len); if (signed_str) { GString *signed_gstr = g_string_new(""); g_string_append_len(signed_gstr, signed_str, len); result = _remove_header_footer(signed_gstr->str, PGP_SIGNATURE_FOOTER); g_string_free(signed_gstr, TRUE); gpgme_free(signed_str); } if (passphrase_attempt) { passphrase = strdup(passphrase_attempt); } return result; }
/* ------------------ * encrypt a plain string with the key found with fingerprint fpr * ------------------ */ static char* encrypt(const char* plain_str, const char* fpr) { gpgme_error_t error; gpgme_ctx_t ctx; gpgme_key_t key; gpgme_key_t sender_key; gpgme_data_t plain,cipher; char* cipher_str = NULL; char* cipher_str_dup = NULL; size_t len; gpgme_key_t key_arr[3]; key_arr[0] = NULL; key_arr[1] = NULL; key_arr[2] = NULL; // connect to gpgme gpgme_check_version (NULL); error = gpgme_new(&ctx); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_new failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); return NULL; } // get key by fingerprint error = gpgme_get_key(ctx,fpr,&key,0); if (error || !key) { purple_debug_error(PLUGIN_ID,"gpgme_get_key failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } key_arr[0] = key; // check if user selected a main key const char* sender_fpr = purple_prefs_get_string(PREF_MY_KEY); if ( sender_fpr != NULL && strcmp(sender_fpr,"") != 0) { // get own key by fingerprint error = gpgme_get_key(ctx,sender_fpr,&sender_key,0); if (!error && sender_key) key_arr[1] = sender_key; else purple_debug_error(PLUGIN_ID,"gpgme_get_key: sender key for fingerprint %s is missing! error: %s %s\n", sender_fpr, gpgme_strsource (error), gpgme_strerror (error) ); } else purple_debug_error(PLUGIN_ID,"purple_prefs_get_string: PREF_MY_KEY was empty\n"); // create data containers gpgme_data_new_from_mem (&plain, plain_str,strlen(plain_str),1); gpgme_data_new(&cipher); // encrypt, ascii armored gpgme_set_armor(ctx,1); error = gpgme_op_encrypt (ctx, key_arr,GPGME_ENCRYPT_ALWAYS_TRUST,plain,cipher); if (error) { purple_debug_error(PLUGIN_ID,"gpgme_op_encrypt failed: %s %s\n",gpgme_strsource (error), gpgme_strerror (error)); gpgme_release (ctx); return NULL; } // release memory for data containers gpgme_data_release(plain); cipher_str = gpgme_data_release_and_get_mem(cipher,&len); if (cipher_str != NULL) { cipher_str_dup = str_unarmor(cipher_str); } gpgme_free(cipher_str); // close gpgme connection gpgme_release (ctx); return cipher_str_dup; }
static void gpa_file_decrypt_operation_done_cb (GpaContext *context, gpg_error_t err, GpaFileDecryptOperation *op) { gpa_file_item_t file_item = GPA_FILE_OPERATION (op)->current->data; if (file_item->direct_in) { size_t len; char *plain_gpgme = gpgme_data_release_and_get_mem (op->plain, &len); op->plain = NULL; /* Do the memory allocation dance. */ if (plain_gpgme) { /* Conveniently make ASCII stuff into a string. */ file_item->direct_out = g_malloc (len + 1); memcpy (file_item->direct_out, plain_gpgme, len); gpgme_free (plain_gpgme); file_item->direct_out[len] = '\0'; /* Yep, excluding the trailing zero. */ file_item->direct_out_len = len; } else { file_item->direct_out = NULL; file_item->direct_out_len = 0; } } /* Do clean up on the operation */ gpgme_data_release (op->plain); op->plain = NULL; close (op->plain_fd); op->plain_fd = -1; gpgme_data_release (op->cipher); op->cipher = NULL; close (op->cipher_fd); op->cipher_fd = -1; gtk_widget_hide (GPA_FILE_OPERATION (op)->progress_dialog); if (err) { if (! file_item->direct_in) { /* If an error happened, (or the user canceled) delete the created file and abort further decryptions. */ g_unlink (file_item->filename_out); g_free (file_item->filename_out); file_item->filename_out = NULL; } /* FIXME:CLIPBOARD: Server finish? */ g_signal_emit_by_name (GPA_OPERATION (op), "completed", err); } else { /* We've just created a file */ g_signal_emit_by_name (GPA_OPERATION (op), "created_file", file_item); if (op->verify) { gpgme_verify_result_t result; result = gpgme_op_verify_result (GPA_OPERATION (op)->context->ctx); if (result->signatures) { /* Add the file to the result dialog. FIXME: Maybe we should use the filename without the directory. */ gpa_file_verify_dialog_add_file (GPA_FILE_VERIFY_DIALOG (op->dialog), file_item->direct_name ? file_item->direct_name : file_item->filename_in, NULL, NULL, result->signatures); op->signed_files++; } } /* Go to the next file in the list and decrypt it */ GPA_FILE_OPERATION (op)->current = g_list_next (GPA_FILE_OPERATION (op)->current); gpa_file_decrypt_operation_next (op); } }