summaryrefslogtreecommitdiff
path: root/src/gpg.c
blob: 51e614f07fd1cae693c2243d481d6721e8150447 (plain)
    1 // GPGEdit edits GPG encrypted files
    2 // Copyright (C) 2018  Aaron Ball <nullspoon@oper.io>
    3 //
    4 // This program is free software: you can redistribute it and/or modify
    5 // it under the terms of the GNU General Public License as published by
    6 // the Free Software Foundation, either version 3 of the License, or
    7 // (at your option) any later version.
    8 //
    9 // This program is distributed in the hope that it will be useful,
   10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12 // GNU General Public License for more details.
   13 //
   14 // You should have received a copy of the GNU General Public License
   15 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
   16 #include "gpg.h"
   17 
   18 
   19 int gpg_failiferr(gpgme_error_t err) {
   20   if(err != GPG_ERR_NO_ERROR) {
   21     printf("ERROR: ");
   22     if(err == GPG_ERR_INV_VALUE) {
   23       printf("Invalid data structure\n");
   24     } else if(err == GPG_ERR_ENOMEM) {
   25       printf("Insufficient memory to allocate GPG context\n");
   26     } else if(err == GPG_ERR_ENOMEM) {
   27       printf("Insufficient memory to allocate GPG context\n");
   28     } else if(err == GPG_ERR_NOT_OPERATIONAL) {
   29       printf("GPGME not initialized\n");
   30     } else if(err == GPG_ERR_UNUSABLE_PUBKEY) {
   31       printf("One or more public keys unusable\n");
   32     } else if(err == GPG_ERR_BAD_PASSPHRASE) {
   33       printf("Incorrect passphrase\n");
   34     } else {
   35       printf("Unknown error: %d\n", err);
   36     }
   37     printf("Message:\n  %s\n", gpgme_strerror(err));
   38     return err;
   39   }
   40   return 0;
   41 }
   42 
   43 
   44 gpgme_error_t init_gpg(gpgme_ctx_t* ctx, gpgme_protocol_t proto) {
   45   gpgme_error_t err;
   46 
   47   gpgme_check_version (NULL);
   48   setlocale (LC_ALL, "");
   49   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
   50 
   51   err = gpgme_engine_check_version (proto);
   52   gpg_failiferr(err);
   53 
   54   err = gpgme_new(ctx);
   55   gpg_failiferr(err);
   56 
   57   gpgme_set_protocol(*ctx, proto);
   58   gpgme_set_armor(*ctx, 1);
   59 
   60   return err;
   61 }
   62 
   63 
   64 int gpg_data_fwrite(gpgme_data_t dh, FILE* out) {
   65   char buf[READSIZE];
   66   size_t total = 0;
   67   size_t size = 0;
   68 
   69   gpgme_data_seek(dh, 0, SEEK_SET);
   70   if(gpgme_data_read(dh, buf, 1) < 1) {
   71     printf("Error: GPG data struct is empty. Nothing to write.\n");
   72     return -1;
   73   }
   74 
   75   // Set seek to beginning of file
   76   gpgme_data_seek(dh, 0, SEEK_SET);
   77 
   78   while((size = gpgme_data_read(dh, buf, READSIZE)) > 0) {
   79     total += size;
   80     buf[size] = '\0';        // Ensure string terminates at the correct length
   81     fprintf(out, "%s", buf); // Write to file descriptor
   82   }
   83 
   84   return total;
   85 }
   86 
   87 
   88 int gpg_recip_count(gpgme_recipient_t firstrecip) {
   89   gpgme_recipient_t recip; // Current recipient object
   90   int count = 0;           // Count of recipients
   91 
   92   // Get recipient list
   93   recip = firstrecip;
   94   while(recip != NULL) {
   95     //printf("-- recipient: %s\n", recip->keyid);
   96     recip = recip->next;
   97     count++;
   98   }
   99 
  100   return count;
  101 }
  102 
  103 
  104 // gpg_strll_to_key_t:
  105 // Converts a string linked list containing keyids (multiple identifier types
  106 // are supported) into an array of gpgme_key_t objects.
  107 //
  108 // @ctx        GPGME context (already initialized)
  109 // @firstrecip First linkedlist recipient item
  110 //
  111 // @return gpgme_key_t* Array of gpgme_key_t objects, one for each keyid string
  112 gpgme_key_t* gpg_strll_to_key_t(gpgme_ctx_t ctx, struct strll* firstrecip) {
  113   gpgme_key_t* out;
  114   gpgme_error_t err;
  115   int i               = 0;
  116   struct strll* recip = firstrecip;
  117 
  118   // Initialize the gpgme_key_t pointer array
  119   out = (gpgme_key_t*) malloc(1);
  120   out = NULL;
  121 
  122   // Loop over the keys back to zero
  123   while(recip != NULL) {
  124     out = realloc(out, sizeof(gpgme_key_t) * (i + 1));
  125     err = gpgme_get_key(ctx, recip->str, &out[i], 0);
  126     gpg_failiferr(err);
  127     recip = recip->next;
  128     i++;
  129   }
  130   out[i] = NULL;
  131   return out;
  132 }
  133 
  134 
  135 void gpg_key_dump(gpgme_key_t key) {
  136   printf("Recipient: %s\n", key->fpr);
  137   printf("  protocol:      %d\n", key->protocol);
  138   printf("  revoked:       %d\n", key->revoked);
  139   printf("  expired:       %d\n", key->expired);
  140   printf("  disabled:      %d\n", key->disabled);
  141   printf("  invalid:       %d\n", key->invalid);
  142   printf("  can_encrypt:   %d\n", key->can_encrypt);
  143   printf("  can_sign:      %d\n", key->can_sign);
  144   printf("  can_certify:   %d\n", key->can_certify);
  145   printf("  can_auth:      %d\n", key->can_authenticate);
  146   printf("  qualified:     %d\n", key->is_qualified);
  147   printf("  secret:        %d\n", key->secret);
  148   printf("  issuer_serial: %s\n", key->issuer_serial);
  149   printf("  issuer_name:   %s\n", key->issuer_name);
  150   printf("  chain_id:      %s\n", key->chain_id);
  151 }
  152 
  153 
  154 size_t gpg_encrypt_file(char* infile, char* outfile, struct strll* recipll) {
  155   gpgme_ctx_t   ctx;
  156   gpgme_data_t  indata;
  157   gpgme_data_t  outdata;
  158   gpgme_error_t err;
  159   gpgme_key_t*  keys = NULL;
  160 
  161   err = init_gpg(&ctx, GPGME_PROTOCOL_OPENPGP);
  162   gpg_failiferr(err);
  163 
  164   // For debugging purposes
  165   // printf("Reading updated data from memory\n"); // Initialize data structures
  166   err = gpgme_data_new_from_file(&indata, infile, 1);
  167   gpg_failiferr(err);
  168 
  169   err = gpgme_data_new(&outdata);
  170   gpg_failiferr(err);
  171 
  172   // Get key id objects from keyids char array
  173   keys = gpg_strll_to_key_t(ctx, recipll);
  174 
  175   // For debugging purposes
  176   // int i = 0;
  177   // while(keys[i] != NULL) {
  178   //   gpg_key_dump(keys[i]);
  179   //   i++;
  180   // }
  181 
  182   // Encrypt!
  183   err = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, indata, outdata);
  184   gpg_failiferr(err);
  185 
  186   // For debugging purposes
  187   // printf("No errors detecting during encryption.\n");
  188 
  189   // For debugging purposes
  190   // printf("Writing to disk\n");
  191   // Write to disk!
  192   FILE* refd = fopen(outfile, "w");
  193   gpg_data_fwrite(outdata, refd);
  194   fclose(refd);
  195 
  196   // cleanup
  197   gpgme_data_release(indata);
  198   gpgme_data_release(outdata);
  199   gpgme_release(ctx);
  200   return 0;
  201 }
  202 
  203 
  204 gpgme_decrypt_result_t
  205 gpg_decrypt_file(char* infile, char* outfile, gpgme_ctx_t ctx) {
  206   gpgme_error_t err;
  207   gpgme_data_t indata = NULL;
  208   gpgme_data_t outdata = NULL;
  209 
  210   // Read ciphertext file into gpgme data struct, and fail if any errors
  211   // returned.
  212   gpgme_data_new(&outdata);
  213   err = gpgme_data_new_from_file(&indata, infile, 1);
  214   if(err != GPG_ERR_NO_ERROR) {
  215     printf("ERROR: ");
  216     if(err == GPG_ERR_INV_VALUE) {
  217       printf("Invalid data struct or file path\n");
  218     } else if(err == GPG_ERR_NOT_IMPLEMENTED) {
  219       printf("Not implemented\n");
  220     } else if(err == GPG_ERR_ENOMEM) {
  221       printf("Insufficient memory to allocate data struct\n");
  222     }
  223     return NULL;
  224   }
  225 
  226   // Attempt to decrypt
  227   err = gpgme_op_decrypt(ctx, indata, outdata);
  228   if(err != GPG_ERR_NO_ERROR) {
  229     printf("ERROR: ");
  230     if(err == GPG_ERR_INV_VALUE) {
  231       printf("Invalid pointer to cipher or plain data structs\n");
  232     } else if(err == GPG_ERR_NO_DATA) {
  233       printf("Cipher struct contains no encrypted data\n");
  234     } else if(err == GPG_ERR_DECRYPT_FAILED) {
  235       printf("Ciphertext is invalid\n");
  236     } else if(err == GPG_ERR_BAD_PASSPHRASE) {
  237       printf("Passphrase is incorrect\n");
  238     } else {
  239       printf("Unhandled error\n  %s\n", gpgme_strerror(err));
  240     }
  241     return NULL;
  242   }
  243 
  244   // Write decrypted data to outfile
  245   FILE* outfd = fopen(outfile, "w");
  246   gpg_data_fwrite(outdata, outfd);
  247 
  248   // Clean up
  249   fclose(outfd);
  250   gpgme_data_release(indata);
  251   gpgme_data_release(outdata);
  252   return gpgme_op_decrypt_result(ctx);
  253 }

Generated by cgit