]> pd.if.org Git - zpackage/blob - crypto/libeddsa/sign.c
cleanup sign tests
[zpackage] / crypto / libeddsa / sign.c
1 #define _POSIX_C_SOURCE 200809L
2
3 /* general zpm sign function */
4
5 /* read key, export key, import key, sign, export signature, import
6  * signature, verify signature
7  */
8
9 /* import and export is base64 encoded */
10
11 /* -v verify
12  * -s sign
13  * -g generate key
14  * -e extract public key
15  *
16  * -o output file
17  *
18  * -p read key from file
19  * -P read public key from argument to -P
20  * -S read secret key from argument
21  * -m message from argument
22  * -h message is hex encoded
23  */
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <sys/mman.h>
33 #include <time.h>
34
35 /* linux specific for getrandom */
36 #include <sys/random.h>
37
38 #include "eddsa.h"
39 #include "sha512.h"
40
41 #define VERIFY 1
42 #define SIGN 2
43 #define GENKEY 3
44 #define EXTRACT 4
45
46 //#define MARK do { fprintf(stderr, "%s %s:%d\n", __FILE__, __func__, __LINE__); } while (0)
47
48 static void hexdump(void *src, size_t len) {
49         unsigned char *b = src;
50         while (len--) {
51                 printf("%02x", *b++);
52         }
53         printf("\n");
54 }
55
56 static char hexchars[] = "0123456789abcdefABCDEF";
57
58 static void hex(char *dst, uint8_t *src, size_t len) {
59         while (len--) {
60                 dst[0] = hexchars[(src[0]>>4)&0xf];
61                 dst[1] = hexchars[src[0]&0xf];
62                 dst+=2;
63                 src++;
64         }
65 }
66
67 static void hexbin(uint8_t *dst, unsigned char *src, size_t len) {
68         size_t i;
69         int x;
70
71         for (i=0; i<len; i+=2) {
72                 sscanf((const char *)src+i, "%02x", &x);
73                 dst[i/2] = x;
74         }
75 }
76
77 void *map(char *file, size_t *size) {
78         int fd, rv;
79         void *m;
80         struct stat st;
81
82         fd = open(file, O_RDONLY);
83         if (fd == -1) {
84                 return NULL;
85         }
86
87         rv = fstat(fd, &st);
88         if (rv == -1) {
89                 close(fd);
90                 return NULL;
91         }
92
93         m = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
94         if (m == MAP_FAILED) {
95                 return 0;
96         }
97
98         close(fd);
99         *size = st.st_size;
100         return m;
101 }
102
103 ssize_t readbytes(char *dest, char *file, size_t n) {
104         char *m;
105         size_t fs;
106
107         m = map(file, &fs);
108         if (!m) {
109                 return -1;
110         }
111         if (n > fs) {
112                 n = fs;
113         }
114
115         size_t pk = strspn(m, hexchars);
116         pk /= 2;
117         if (n > pk) {
118                 n = pk;
119         }
120
121         hexbin(dest, m, n*2);
122         munmap(m, fs);
123         return n;
124 }
125
126
127 /* private key format is:
128  * "ZPMS" 4 byte magic "ZPMS"
129  * byte 0x01 = version 1
130  * byte 0x01 = private key
131  * byte 0x01 = chacha encrypted, 0x00 = plain/raw key bytes
132  * byte 0x00 reserved, probably "key usage"
133  * 32 bytes private key
134  * 24 bytes reserved
135  * sub keys, public keys?  No point to the public key, since it's
136  * always derivable.  could have 16 bytes of IV for chacha to encrypt.
137  *
138  * entire thing is then hexencoded, but 
139  */
140
141 /* public key format is:
142  * "ZPMS" 4 byte magic "ZPMS"
143  * 0x01   1 byte version
144  * 0x02   1 byte "public key packet"
145  * 0x00   1 byte reserved
146  * 0x00   1 byte reserved
147  * 0x..  32 bytes public key
148  * 0x..  24 bytes reserved
149  * 0x..     revocation signatures
150  * 0x..     user id packets
151  * 0x..     certification signatures
152  * 0x..     sub key packets
153  */
154
155 /* timestamps are 8 byte little endian integers of seconds since
156  * the epoch.  or unix time, or some such.  Times are a mess.
157  * Unix time is leap second unaware, and ambiguous during leap seconds.
158  * UTC requires a database of leap seconds for past time, and the
159  * specified second in the future possibly changes.
160  * TAI is good, but currently 37 seconds behind UTC, which is just weird
161  */
162
163 /* signature items from openpgp */
164 /* revokable flag
165  * 0-255 trust level
166  *
167  */
168
169 /* signature format:
170  * "ZPMS" 4 byte magic "ZPMS"
171  * 0x01   1 byte version
172  * 0x03   1 byte "signature packet"
173  * 0x00   1 byte reserved
174  * 0x00   1 byte reserved
175  * 0x..   8 bytes timestamp of signature time
176  * 0x..   8 bytes timestamp of signature expiration, 0 if none
177  * 0x..  64 bytes of actual signature
178  * 0x..  32 bytes of public key making the signature
179  * 0x..   8 bytes reserved
180  * Total is 128 bytes.
181  */
182
183 /* expires time could probably be 4 bytes as an offset from created.
184  * That would free up 4 bytes.  Sign time could probably be four
185  * bytes with an epoch of say 2019-01-01, since negative times don't
186  * really make any sense, that give more than 100 years, and frees
187  * up another 4 bytes
188  *
189  * version is zero until this proof of concept is better validated
190  */
191 struct signature {
192         char magic[4]; /* magic ZPMS */
193         char info[4]; /* version = 0, type=3, 1 byte trust, 1 byte reserved */
194         uint64_t signtime; /* unix time */
195         uint64_t expires; /* unix time, 0 = none */
196         char sig[64]; 
197         char pub[32];
198         char reserved[8];
199 };
200
201 struct key {
202         char magic[4]; /* "ZPMS" */
203         char info[4]; /* version, type = 0x02, reserved, reserved */
204         char key[32];
205         uint64_t created;
206         uint64_t expires;
207         char reserved[8];
208         char sig[64]; /* zeroes for a private key, or fill in, doesn't matter*/
209         /* could fill in the first 32 bytes of sig with the public key
210          * if this is a private key, then you don't need another structure */
211 };
212
213 int create_key(struct key *sk) {
214         char info[] = { 0, 1, 0, 0 };
215         memcpy(sk->magic, "ZPMS", 4);
216         memcpy(sk->info, info, 4);
217         getrandom(sk->key, sizeof sk->key, 0);
218         ed25519_genpub(sk->sig, sk->key);
219         sk->created = time(NULL);
220         memset(sk->reserved, 0, 8);
221         memset(sk->sig+32, 0, 32);
222         return 1;
223 }
224
225 int derive_pubkey(struct key *pk, struct key *sk) {
226         char info[] = { 0, 2, 0, 0 };
227
228         memcpy(sk->magic, "ZPMS", 4);
229         memcpy(sk->info, info, 4);
230         ed25519_genpub(pk->key, sk->key);
231         pk->created = sk->created;
232         pk->expires = sk->expires;
233         memset(sk->reserved, 0, 8);
234
235         ed25519_sign(pk->sig, sk->key, pk->sig, sk->info, 52);
236         return 1;
237
238 }
239
240 /* if reserved used 16 bytes for signtime and expires, and we added
241  * 64 bytes as a signature, a public key could include it's own self
242  * signature, and a key would be 128 bytes, as would a signature.  This
243  * would make all structures 128 bytes.
244  */
245
246 int read_secret_key(uint8_t *sec, uint8_t *pub, char *file) {
247         uint8_t sk[64];
248         
249         readbytes(sk, file, sizeof sk);
250         if (sk[4] != 1 || sk[5] != 1) {
251                 printf("magic: ");
252                 hexdump(sk, 16);
253                 return 0;
254         }
255         memcpy(sec, sk+8, 32);
256         //printf("sec: ");
257         //hexdump(sec, 32);
258
259         if (pub) {
260                 ed25519_genpub(pub, sec);
261         //      printf("pub: ");
262         //      hexdump(pub, 32);
263         }
264
265         return 1;
266 }
267
268 /* private key format is:
269  * "ZPMS" 4 byte magic "ZPMS"
270  * byte 0x01 = version 1
271  * byte 0x01 = private key
272  * byte 0x01 = chacha encrypted, 0x00 = plain/raw key bytes
273  * byte 0x00 reserved, probably "key usage"
274  * 32 bytes private key
275  * 24 bytes reserved
276  * sub keys, public keys?  No point to the public key, since it's
277  * always derivable.  could have 16 bytes of IV for chacha to encrypt.
278  *
279  * entire thing is then hexencoded, but 
280  */
281
282 int write_secret_key(uint8_t *sec, int flags, int fd) {
283         uint8_t skh[128] = "5A504D5301010000"; /* ZPMS 1 1 0 0 */
284
285         if (flags & 0x01) {
286                 skh[13] = '1';
287         }
288         //hexdump(sec, 32);
289         hex(skh + 16, sec, 32);
290         memset(skh + 80, '0', 48);
291         write(fd, skh, sizeof skh);
292         memset(skh, 0, sizeof skh);
293
294         return 1;
295 }
296
297 int main(int ac, char *av[]) {
298         int option;
299         int mode = 0;
300         char *outfile = 0;
301         uint8_t pub[ED25519_KEY_LEN];
302         /* TODO should use mlock()ed memory for the secret key */
303         uint8_t sec[ED25519_KEY_LEN];
304         uint8_t sig[ED25519_SIG_LEN];
305         void *message = 0;
306         char *messagefile = 0;
307         char *messagestring = 0;
308         char messagehash[SHA512_HASH_LENGTH];
309         char *keystring = 0, *keyfile = 0;
310         unsigned char *sigstring = 0, *sigfile = 0;
311         char *passphrase = 0;
312         size_t mlen;
313         int rawsig = 0, hexencoded = 0;
314         int debug = 0;
315
316         while ((option = getopt(ac, av, "o:vS:f:sgek:K:rm:hd")) != -1) {
317                 switch (option) {
318                         case 'o': outfile = optarg; break;
319                         case 'v': mode = VERIFY; break;
320                         case 'S': sigstring = optarg; break;
321                         case 'f': sigfile = optarg; break;
322                         case 's': mode = SIGN; break;
323                         case 'g': mode = GENKEY; break;
324                         case 'e': mode = EXTRACT; break;
325                         case 'k': keystring = optarg; break;
326                         case 'K': keyfile = optarg; break;
327                         case 'p': passphrase = optarg; break;
328                         case 'm': messagestring = optarg; break;
329                         case 'h': hexencoded = 1; break;
330                         case 'r': rawsig = 1; break;
331                         case 'd': debug++; break;
332                         default:
333                                   exit(EXIT_FAILURE);
334                                   break;
335                 }
336         }
337
338         if (sigfile) {
339                 ssize_t r;
340                 memset(sig, 0, sizeof sig);
341                 r = readbytes(sig, sigfile, sizeof sig);
342                 if (r == -1) {
343                         return 8;
344                 }
345                 if ((size_t)r < sizeof sig) {
346                         return 7;
347                 }
348         } else if (sigstring) {
349                 memset(sig, 0, sizeof sig);
350                 hexbin(sig, sigstring, sizeof sig);
351         }
352
353         if (keystring) {
354                 memset(sec, 0, sizeof sec);
355                 hexbin(sec, keystring, strlen(keystring));
356                 ed25519_genpub(pub, sec);
357                 if (debug) {
358                         printf("sec:\n"); hexdump(sec, sizeof sec);
359                 }
360         } else if (keyfile) {
361                 read_secret_key(sec, pub, keyfile);
362                 //hexdump(sec, sizeof sec);
363                 //hexdump(pub, sizeof pub);
364         }
365
366         if (mode == EXTRACT) {
367                 /* want to print the pubkey only */
368                 hexdump(pub, sizeof pub);
369                 exit(0);
370         }
371
372         /* need to be able to encrypt the private keys */
373         /* use chacha */
374         if (mode == GENKEY) {
375                 /* a private key is just 32 random bytes */
376                 getrandom(sec, sizeof sec, 0);
377                 ed25519_genpub(pub, sec);
378                 ed25519_sign(sig, sec, pub, sec, sizeof sec);
379                 //int rv = ed25519_verify(sig, pub, sec, sizeof sec);
380                 if (outfile) {
381                         int fd;
382                         fd = open(outfile, O_WRONLY|O_CREAT, 0600);
383                         if (fd == -1) {
384                                 perror("can't open outfile");
385                                 exit(EXIT_FAILURE);
386                         }
387                         write_secret_key(sec, 0, fd);
388                         close(fd);
389                 } else {
390                         write_secret_key(sec, 0, 1);
391                 }
392         }
393
394         /* set up the message data */
395         if (mode == SIGN || mode == VERIFY) {
396                 messagefile = av[optind];
397                 if (messagefile) {
398                         message = map(messagefile, &mlen);
399                         if (!message) {
400                                 return 9;
401                         }
402                 } else if (messagestring) {
403                         message = messagestring;
404                         if (hexencoded) {
405                                 mlen = strlen(messagestring)/2;
406                                 message = malloc(mlen);
407                                 if (!message) {
408                                         return 10;
409                                 }
410                                 hexbin(message, messagestring, mlen*2);
411                         } else {
412                                 mlen = strlen(messagestring);
413                         }
414                 } else {
415                         return 2;
416                 }
417                 if (!message) {
418                         return 3;
419                 }
420         }
421
422         if (mode == SIGN) {
423                 struct signature s;
424                 s.magic[0] = 'Z';
425                 s.magic[1] = 'P';
426                 s.magic[2] = 'M';
427                 s.magic[3] = 'S';
428                 s.info[0] = 1;
429                 s.info[1] = 1;
430                 s.info[2] = 0;
431                 s.info[3] = 0;
432                 s.signtime = time(NULL);
433                 s.expires = 0;
434                 memset(s.reserved, 0, 8);
435                 if (!rawsig) {
436                         struct sha512 hash;
437                         sha512_init(&hash);
438                         sha512_add(&hash, message, mlen);
439                         sha512_add(&hash, (uint8_t *)&s.signtime, sizeof s.signtime);
440                         sha512_add(&hash, (uint8_t *)&s.expires, sizeof s.expires);
441                         sha512_add(&hash, s.info, sizeof s.info);
442                         sha512_final(&hash, messagehash);
443                         message = messagehash;
444                 }
445
446                 if (message == 0) {
447                         return 5;
448                 }
449
450                 ed25519_sign(sig, sec, pub, message, mlen);
451                 memcpy(s.sig, sig, sizeof sig);
452                 memcpy(s.pub, pub, sizeof pub);
453                 if (rawsig) {
454                         hexdump(sig, sizeof sig);
455                 } else {
456                         hexdump(&s, sizeof s);
457                 }
458         }
459
460         if (mode == VERIFY) {
461                 fprintf(stderr, "sig: ");
462                 hexdump(sig, sizeof sig);
463                 int rv = ed25519_verify(sig, pub, message, mlen);
464                 if (rv) {
465                         fprintf(stderr, "verified\n");
466                         return 0;
467                 } else {
468                         fprintf(stderr, "not verified\n");
469                         return 6;
470                 }
471         }
472
473         if (message && messagefile) {
474                 munmap(message, mlen);
475         }
476
477         return 0;
478 }