summaryrefslogtreecommitdiff
path: root/src/gpg.c
blob: 335d03f94e77bf893412e5a0ceb31b3a088f6746 (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 
   17 #include "gpg.h"
   18 
   19 #ifndef GPG_H
   20 #define GPG_H
   21 
   22 #define READSIZE 256
   23 
   24 gpgme_error_t init_gpg(gpgme_ctx_t* ctx, gpgme_protocol_t proto) {
   25   gpgme_error_t err;
   26 
   27   gpgme_check_version (NULL);
   28   setlocale (LC_ALL, "");
   29   gpgme_set_locale (NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
   30 
   31   err = gpgme_engine_check_version (proto);
   32 
   33   err = gpgme_new(ctx);
   34   if(err != GPG_ERR_NO_ERROR) {
   35     printf("ERROR: ");
   36     if(err == GPG_ERR_INV_VALUE) {
   37       printf("GPG context is not valid pointer\n");
   38     } else if(err == GPG_ERR_ENOMEM) {
   39       printf("Insufficient memory to allocate GPG context\n");
   40     } else if(err == GPG_ERR_ENOMEM) {
   41       printf("Insufficient memory to allocate GPG context\n");
   42     } else if(err == GPG_ERR_NOT_OPERATIONAL) {
   43       printf("GPGME not initialized\n");
   44     } else {
   45       printf("Unknown\n");
   46     }
   47     return err;
   48   }
   49 
   50   gpgme_set_protocol(*ctx, proto);
   51   gpgme_set_armor(*ctx, 1);
   52 
   53   return err;
   54 }
   55 
   56 
   57 int gpg_data_fwrite(gpgme_data_t dh, FILE* out) {
   58   char buf[READSIZE];
   59   size_t total = 0;
   60   size_t size = 0;
   61 
   62   gpgme_data_seek(dh, 0, SEEK_SET);
   63   if(gpgme_data_read(dh, buf, 1) < 1) {
   64     printf("Error: GPG data struct is empty. Nothing to write.\n");
   65     return -1;
   66   }
   67 
   68   // Set seek to beginning of file
   69   gpgme_data_seek(dh, 0, SEEK_SET);
   70 
   71   while((size = gpgme_data_read(dh, buf, READSIZE)) > 0) {
   72     total += size;
   73     buf[size] = '\0';        // Ensure string terminates at the correct length
   74     fprintf(out, "%s", buf); // Write to file descriptor
   75   }
   76 
   77   return total;
   78 }
   79 
   80 
   81 int gpg_recip_count(gpgme_recipient_t firstrecip) {
   82   gpgme_recipient_t recip; // Current recipient object
   83   int count = 0;           // Count of recipients
   84 
   85   // Get recipient list
   86   recip = firstrecip;
   87   while(recip != NULL) {
   88     //printf("-- recipient: %s\n", recip->keyid);
   89     recip = recip->next;
   90     count++;
   91   }
   92 
   93   return count;
   94 }
   95 
   96 
   97 char** gpg_recip_get_keyids(gpgme_recipient_t firstrecip) {
   98   gpgme_recipient_t recip; // Current recipient object
   99   int count     = 0;       // Number of recipients
  100   int i         = 0;       // Key index
  101   char** keyids = NULL;
  102 
  103   count = gpg_recip_count(firstrecip);
  104   keyids = (char**) malloc(sizeof(char*) * count + 1);
  105 
  106   // Write each recipient key id to the char array
  107   recip = firstrecip;
  108   while(recip != NULL) {
  109     // For debugging purposes
  110     //printf("Getting key for %s\n", recip->keyid);
  111     keyids[i] = malloc(strlen(recip->keyid) + 1);
  112     strcpy(keyids[i], recip->keyid);
  113 
  114     i++;
  115     recip = recip->next;
  116   }
  117 
  118   keyids[i] = NULL;
  119   return keyids;
  120 }
  121 
  122 
  123 gpgme_key_t* gpg_keyids_to_key_t(gpgme_ctx_t ctx, char** keyids) {
  124   gpgme_key_t* out;
  125   gpgme_error_t err;
  126   int count     = 0; // Number of recipients
  127   int i         = 0;
  128 
  129   // Count the keys
  130   while(keyids[count] != NULL)
  131     count++;
  132 
  133   // Allocate the gpgme_key_t pointer array
  134   out = malloc(sizeof(gpgme_key_t) * (count + 1));
  135 
  136   // Loop over the keys back to zero
  137   while(i < count) {
  138     err = gpgme_get_key(ctx, keyids[i], &out[i], 0);
  139     if(err != GPG_ERR_NO_ERROR) {
  140       printf("Ooops! Something went wrong getting key %s\n", keyids[i]);
  141     }
  142     i++;
  143   }
  144   out[i] = NULL;
  145   return out;
  146 }
  147 
  148 void gpg_keyids_release(char** keyids) {
  149   int i = 0;
  150 
  151   while(keyids[i] != NULL) {
  152     free(keyids[i]);
  153     i++;
  154   }
  155   free(keyids);
  156 }
  157 
  158 
  159 
  160 void gpg_dump_key(gpgme_key_t key) {
  161   printf("Recipient: %s\n", key->fpr);
  162   printf("  protocol:      %d\n", key->protocol);
  163   printf("  revoked:       %d\n", key->revoked);
  164   printf("  expired:       %d\n", key->expired);
  165   printf("  disabled:      %d\n", key->disabled);
  166   printf("  invalid:       %d\n", key->invalid);
  167   printf("  can_encrypt:   %d\n", key->can_encrypt);
  168   printf("  can_sign:      %d\n", key->can_sign);
  169   printf("  can_certify:   %d\n", key->can_certify);
  170   printf("  can_auth:      %d\n", key->can_authenticate);
  171   printf("  qualified:     %d\n", key->is_qualified);
  172   printf("  secret:        %d\n", key->secret);
  173   printf("  origin:        %d\n", key->origin);
  174   printf("  issuer_serial: %s\n", key->issuer_serial);
  175   printf("  issuer_name:   %s\n", key->issuer_name);
  176   printf("  chain_id:      %s\n", key->chain_id);
  177   printf("  last_update:   %ld\n", key->last_update);
  178 }
  179 
  180 
  181 size_t gpg_encrypt_file(char* infile, char* outfile, char** keyids) {
  182   gpgme_ctx_t   ctx;
  183   gpgme_data_t  indata;
  184   gpgme_data_t  outdata;
  185   gpgme_error_t err;
  186   gpgme_key_t*  keys = NULL;
  187 
  188   err = init_gpg(&ctx, GPGME_PROTOCOL_OPENPGP);
  189   if(err != GPG_ERR_NO_ERROR) {
  190     printf("Error: %s\n", gpgme_strerror(err));
  191     return -1;
  192   }
  193 
  194   // For debugging purposes
  195   // printf("Reading updated data from memory\n");
  196   // Initialize data structures
  197   err = gpgme_data_new_from_file(&indata, infile, 1);
  198   if(err != GPG_ERR_NO_ERROR)
  199     printf("Error: %s\n", gpgme_strerror(err));
  200 
  201   err = gpgme_data_new(&outdata);
  202   if(err != GPG_ERR_NO_ERROR)
  203     printf("Error: %s\n", gpgme_strerror(err));
  204 
  205   // Get key id objects from keyids char array
  206   keys = gpg_keyids_to_key_t(ctx, keyids);
  207   // For debugging purposes
  208   // int i = 0;
  209   // while(keys[i] != NULL) {
  210   //   gpg_dump_key(keys[i]);
  211   //   i++;
  212   // }
  213 
  214   // Encrypt!
  215   err = gpgme_op_encrypt(ctx, keys, GPGME_ENCRYPT_ALWAYS_TRUST, indata, outdata);
  216 
  217   if(err != GPG_ERR_NO_ERROR) {
  218     if(err == GPG_ERR_UNUSABLE_PUBKEY) {
  219       printf("One or more public keys unusable\n");
  220     } else if(err == GPG_ERR_INV_VALUE) {
  221       printf("Invalid data structure\n");
  222     } else if(err == GPG_ERR_BAD_PASSPHRASE) {
  223       printf("Incorrect passphrase\n");
  224     } else {
  225       printf("Unknown error: %d\n", err);
  226       printf("Message:\n  %s\n", gpgme_strerror(err));
  227     }
  228   }
  229   // For debugging purposes
  230   // printf("No errors detecting during encryption.\n");
  231 
  232   // For debugging purposes
  233   // printf("Writing to disk\n");
  234   // Write to disk!
  235   FILE* refd = fopen(outfile, "w");
  236   gpg_data_fwrite(outdata, refd);
  237   fclose(refd);
  238 
  239   // cleanup
  240   gpgme_data_release(indata);
  241   gpgme_data_release(outdata);
  242   gpgme_release(ctx);
  243   return 0;
  244 }
  245 
  246 
  247 gpgme_decrypt_result_t
  248 gpg_decrypt_file(char* infile, char* outfile, gpgme_ctx_t ctx) {
  249   gpgme_error_t err;
  250   gpgme_data_t indata = NULL;
  251   gpgme_data_t outdata = NULL;
  252 
  253   // Read ciphertext file into gpgme data struct, and fail if any errors
  254   // returned.
  255   gpgme_data_new(&outdata);
  256   err = gpgme_data_new_from_file(&indata, infile, 1);
  257   if(err != GPG_ERR_NO_ERROR) {
  258     printf("ERROR: ");
  259     if(err == GPG_ERR_INV_VALUE) {
  260       printf("Invalid data struct or file path\n");
  261     } else if(err == GPG_ERR_NOT_IMPLEMENTED) {
  262       printf("Not implemented\n");
  263     } else if(err == GPG_ERR_ENOMEM) {
  264       printf("Insufficient memory to allocate data struct\n");
  265     }
  266     return NULL;
  267   }
  268 
  269   // Attempt to decrypt
  270   err = gpgme_op_decrypt(ctx, indata, outdata);
  271   if(err != GPG_ERR_NO_ERROR) {
  272     printf("ERROR: ");
  273     if(err == GPG_ERR_INV_VALUE) {
  274       printf("Invalid pointer to cipher or plain data structs\n");
  275     } else if(err == GPG_ERR_NO_DATA) {
  276       printf("Cipher struct contains no encrypted data\n");
  277     } else if(err == GPG_ERR_DECRYPT_FAILED) {
  278       printf("Ciphertext is invalid\n");
  279     } else if(err == GPG_ERR_BAD_PASSPHRASE) {
  280       printf("Passphrase is incorrect\n");
  281     } else {
  282       printf("Unhandled error\n  %s\n", gpgme_strerror(err));
  283     }
  284     return NULL;
  285   }
  286 
  287   // Write decrypted data to outfile
  288   FILE* outfd = fopen(outfile, "w");
  289   gpg_data_fwrite(outdata, outfd);
  290 
  291   // Clean up
  292   fclose(outfd);
  293   gpgme_data_release(indata);
  294   gpgme_data_release(outdata);
  295   return gpgme_op_decrypt_result(ctx);
  296 }
  297 #endif

Generated by cgit