Lookup pads when unpackaging messages.
[easyotp.git] / libotp.c
blobfe81fee6456a502175663357b72d66dce58acbd7
1 /** Practical One-time Pad Library
3 * Created:20080514
4 * By Jeff Connelly
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sysexits.h>
10 #include <string.h>
12 #include "libotp.h"
13 #include "base64.h"
15 PAD *pads = NULL;
17 /** Show a list of all loaded pads. */
18 void show_pads()
20 PAD *p;
22 for (p = pads; p; p = p->next) {
23 printf("Pad: %s: %s\n", p->name, p->local_filename);
27 /** Open a companion offset file for given pad. Caller must close.
29 * @param mode Either "rt" or "wt", for reading or writing.
31 FILE *open_offset_file(PAD *p, char *mode)
33 FILE *ofp;
34 char *offset_filename;
35 size_t filename_length;
37 /* Offset is stored in a separate file; pad plus OFFSET_FILE_NAME_EXTENSION. */
38 filename_length = strlen(p->local_filename) + strlen(OFFSET_FILE_EXTENSION) + 1;
39 offset_filename = malloc(filename_length);
40 if (!offset_filename) {
41 perror("malloc");
42 exit(EX_UNAVAILABLE);
44 snprintf(offset_filename, filename_length, "%s" OFFSET_FILE_EXTENSION, p->local_filename);
46 /* Read offset from file. */
47 ofp = fopen(offset_filename, mode);
48 if (!ofp) {
49 fprintf(stderr, "opening offset file %s failed\n", offset_filename);
50 perror("fopen");
51 free(offset_filename);
52 exit(EX_IOERR);
54 free(offset_filename);
56 return ofp;
59 /** Read the pad offset of a given pad. */
60 unsigned long read_offset(PAD *p)
62 FILE *ofp;
63 char buffer[OFFSET_SIZE];
64 unsigned long offset;
66 ofp = open_offset_file(p, "rt");
68 memset(buffer, 0, OFFSET_SIZE);
69 if (fread(buffer, 1, OFFSET_SIZE - 1, ofp) < 1) {
70 fprintf(stderr, "could not read offset file for %s\n", p->local_filename);
71 exit(EX_IOERR);
74 if (fclose(ofp) != 0) {
75 fprintf(stderr, "error closing offset file for reading for %s\n", p->local_filename);
76 perror("fclose");
77 exit(EX_IOERR);
80 /* We finally got it! */
81 offset = strtoul(buffer, NULL, 10);
83 return offset;
86 /** Write the pad offset to the given pad. */
87 void write_offset(PAD *p, unsigned long offset)
89 FILE *ofp;
90 char buffer[OFFSET_SIZE];
92 ofp = open_offset_file(p, "wt");
94 memset(buffer, 0, OFFSET_SIZE);
95 snprintf(buffer, OFFSET_SIZE - 1, "%ld", offset);
96 printf("buffer=%s\n", buffer);
97 if (fwrite(buffer, strlen(buffer), 1, ofp) != 1) {
98 fprintf(stderr, "write error saving offset %ld for %s\n", offset, p->local_filename);
99 exit(EX_IOERR);
103 if (fclose(ofp) != 0) {
104 fprintf(stderr, "error closing offset file for writing for %s\n", p->local_filename);
105 perror("fclose");
106 exit(EX_IOERR);
110 /** Load a pad file from disk, adding to 'pads' global. */
111 void load_pad(char *local_filename)
113 FILE *fp;
114 PAD *new_pad;
116 fp = fopen("/Volumes/Not Backed Up/otp/otp-dazzlement", "rb");
117 if (!fp) {
118 perror("fopen");
119 exit(EXIT_FAILURE);
122 new_pad = malloc(sizeof(PAD));
123 if (!new_pad) {
124 perror("malloc");
125 exit(EX_UNAVAILABLE);
128 new_pad->local_filename = strdup(local_filename);
129 new_pad->name = strdup("dc"); /* TODO */
130 new_pad->fp = fp;
131 new_pad->next = NULL;
133 /* Add to linked list. */
134 if (!pads) {
135 pads = new_pad;
136 } else {
137 PAD *p, *tail;
139 /* Find tail */
140 for (p = pads; p; p = p->next)
141 tail = p;
142 tail->next = new_pad;
146 /** Find pad with given name. */
147 PAD *find_pad(char *pad_name)
149 PAD *p;
151 /* Null or blank pad = default (first) pad. */
152 if (!pad_name || !strcmp(pad_name, ""))
153 return pads;
155 for (p = pads; p; p = p->next) {
156 if (!strcmp(p->name, pad_name))
157 return p;
160 return NULL;
163 /** Close all pads and free allocated memory. */
164 void free_pads()
166 PAD *p, *next;
168 for (p = pads; p; p = next) {
169 free(p->name);
170 free(p->local_filename);
171 fclose(p->fp);
172 next = p->next;
173 free(p);
177 void free_message(MESSAGE *msg)
179 free(msg->cipher_text);
180 free(msg);
183 /** Unpackage a message packaged for transport.
185 * Caller must free_message(). */
186 MESSAGE *unpackage(char *input)
188 MESSAGE *msg;
189 unsigned int at, i;
190 char *s, *end, *b64_ct;
191 char pad_name[PAD_NAME_LENGTH];
193 msg = malloc(sizeof(MESSAGE));
194 if (!msg) {
195 perror("malloc");
196 exit(EX_UNAVAILABLE);
199 /** Format <v0.7 (pad name is unspecified; use default):
200 * MARKER_BEGIN + offset + comma
201 * base64'd data
202 * MARKER_END
204 * Format >=0.7:
205 * MARKER_BEGIN + offset + comma + pad_name + comma
206 * base64'd data
207 * MARKER_END
210 at = 0;
212 /* Locate where the message begins. */
213 s = strstr(input, MARKER_BEGIN);
214 if (!s) {
215 fprintf(stderr, "unpackage: input |%s| lacks beginning marker %s\n",
216 input, MARKER_BEGIN);
217 exit(EX_DATAERR);
220 /* ...and ends. */
221 end = strstr(input, MARKER_END);
222 if (!end) {
223 fprintf(stderr, "unpackage: input |%s| lacks ending marker %s\n",
224 input, MARKER_END);
225 exit(EX_DATAERR);
228 s += strlen(MARKER_BEGIN);
229 msg->offset = strtoul(s, &s, 10);
231 printf("offset=%ld\n", msg->offset);
233 /* Move after mandatory comma. */
234 if (s[0] != ',') {
235 fprintf(stderr, "unpackage: missing comma after offset, at |%s|, input |%s|\n",
236 s, input);
237 exit(EX_DATAERR);
239 ++s;
241 memset(pad_name, 0, PAD_NAME_LENGTH);
243 /* Includes pad name? */
244 if (s[0] != '\n' && s[0] != '\r') {
245 unsigned int i;
247 i = 0;
248 /* v0.7+ message, includes pad name */
249 while(s[0] != '\n' && s[0] != '\r' && s[0] != ',' && s < end) {
250 pad_name[i] = s[0];
251 ++s;
252 ++i;
253 if (i > PAD_NAME_LENGTH) {
254 fprintf(stderr, "unpackage: pad name length > maximum %d, in input |%s|\n",
255 PAD_NAME_LENGTH, input);
256 exit(EX_DATAERR);
261 printf("Pad name: |%s|\n", pad_name);
263 msg->pad = find_pad(pad_name);
264 if (!msg->pad) {
265 fprintf(stderr, "No such pad by name '%s'\n", pad_name);
266 exit(EX_DATAERR);
269 /* Go to next line */
270 while((s[0] == '\n' || s[0] == '\r' || s[0] == ',') && (s < end))
271 ++s;
273 printf("s=%s\n", s);
275 /* Extract base64 data from end of message. */
276 b64_ct = strdup(s);
277 b64_ct[end - s] = 0;
279 printf("b64_data=<%s>\n", b64_ct);
281 /* Decode base64 */
282 msg->cipher_text = malloc(strlen(b64_ct));
283 msg->length = base64_decode(b64_ct, msg->cipher_text);
284 free(b64_ct);
286 printf("decoded to %ld bytes\n", msg->length);
288 for (i = 0; i < msg->length; ++i)
289 printf("%c", msg->cipher_text[i]);
290 printf("\n");
292 return msg;