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 }
|