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