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