diff options
-rw-r--r-- | src/r-gpgme.c | 157 | ||||
-rw-r--r-- | src/r-gpgme.h | 7 |
2 files changed, 164 insertions, 0 deletions
diff --git a/src/r-gpgme.c b/src/r-gpgme.c new file mode 100644 index 0000000..f4e2b92 --- /dev/null +++ b/src/r-gpgme.c @@ -0,0 +1,157 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <locale.h> +#include <errno.h> +#include <gpgme.h> + +#include "r-gpgme.h" + +#define BUF_SIZE 128 + +#ifdef DEBUG + #define ret_if_err(ret, err) \ + do { \ + if(err != GPG_ERR_NO_ERROR) { \ + fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, \ + __LINE__, gpgme_strsource(err), \ + gpgme_strerror(err)); \ + return ret; \ + } \ + } while(0) +#else + #define ret_if_err(ret, err) \ + do { \ + if(err != GPG_ERR_NO_ERROR) { \ + fprintf(stderr, "%s: %s\n", \ + gpgme_strsource(err), gpgme_strerror(err)); \ + return ret; \ + } \ + } while(0) +#endif + +static void init_gpgme() +{ + /* The GPGME library communicates with child processes (the + crypto engines). If a child process dies unexpectedly, for + example due to a bug, or system problem, a SIGPIPE signal + will be delivered to the application. The default action is + to abort the program. To protect against this, + gpgme_check_version sets the SIGPIPE signal action to SIG_IGN + which means that the signal will be ignored. */ + setlocale(LC_ALL, ""); + gpgme_check_version(NULL); + gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); +#ifdef LC_MESSAGES + gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL)); +#endif +} + +static int init_ctx(gpgme_ctx_t ctx, gpgme_protocol_t protocol) +{ + gpgme_error_t err; + err = gpgme_engine_check_version(protocol); + ret_if_err(1, err); + err = gpgme_set_protocol(ctx, protocol); + ret_if_err(1, err); + /* output be ASCII armored */ + gpgme_set_armor(ctx, 1); + return 0; +} + +static int loop_read(const char *path, gpgme_data_t dh) +{ + char buf[BUF_SIZE]; + int ret; + + FILE *f = fopen(path, "w"); + if(f == NULL) + return 1; + + ret = gpgme_data_seek(dh, 0, SEEK_SET); + if(ret) { + fclose(f); + ret_if_err(1, gpgme_err_code_from_errno(errno)); + } + while((ret = gpgme_data_read(dh, buf, BUF_SIZE)) > 0) + fwrite(buf, ret, 1, f); + if(ret < 0) { + fclose(f); + ret_if_err(1, gpgme_err_code_from_errno(errno)); + } + + fclose(f); + return 0; +} + +int ecnrypt_data(const char *path, const char *data, const char *pubkey) +{ + gpgme_error_t err; + gpgme_ctx_t ctx; + gpgme_data_t plain, cipher; + gpgme_key_t key[] = { NULL, NULL }; + init_gpgme(); + + err = gpgme_new(&ctx); + ret_if_err(1, err); + err = init_ctx(ctx, GPGME_PROTOCOL_OPENPGP); + ret_if_err(1, err); + + /* start encrypt */ + + err = gpgme_data_new_from_mem(&plain, data, + sizeof(char) * (strlen(data) + 1), 0); + ret_if_err(1, err); + err = gpgme_data_new(&cipher); + ret_if_err(1, err); + + err = gpgme_get_key(ctx, pubkey, &key[0], 0); + ret_if_err(1, err); + + err = gpgme_op_encrypt(ctx, key, GPGME_ENCRYPT_ALWAYS_TRUST, + plain, cipher); + ret_if_err(1, err); + + if(loop_read(path, cipher)) + return 1; + + gpgme_data_release(plain); + gpgme_data_release(cipher); + gpgme_release(ctx); + return 0; +} + +char *decrypt_data(const char *path) +{ + gpgme_error_t err; + gpgme_ctx_t ctx; + gpgme_data_t cipher, plain; + init_gpgme(); + + err = gpgme_new(&ctx); + ret_if_err(NULL, err); + err = init_ctx(ctx, GPGME_PROTOCOL_OPENPGP); + ret_if_err(NULL, err); + + /* start decrypt */ + + err = gpgme_data_new_from_file(&cipher, path, 1); + ret_if_err(NULL, err); + err = gpgme_data_new(&plain); + ret_if_err(NULL, err); + + err = gpgme_op_decrypt(ctx, cipher, plain); + ret_if_err(NULL, err); + + int ret = gpgme_data_seek(plain, 0, SEEK_SET); + if(ret) + ret_if_err(NULL, gpgme_err_code_from_errno(errno)); + + char *data = malloc(sizeof(char) * (BUF_SIZE + 1)); + gpgme_data_read(plain, data, BUF_SIZE); + + gpgme_data_release(plain); + gpgme_data_release(cipher); + gpgme_release(ctx); + return data; +} diff --git a/src/r-gpgme.h b/src/r-gpgme.h new file mode 100644 index 0000000..7a5a4ab --- /dev/null +++ b/src/r-gpgme.h @@ -0,0 +1,7 @@ +#ifndef LPASS_RGPGME_H +#define LPASS_RGPGME_H + +int ecnrypt_data(const char *path, const char *data, const char *pubkey); +char *decrypt_data(const char *path); + +#endif /* LPASS_RGPGME_H */ |