Merge branch 'x86_64-sha_ni-sha256'
[gd/nettle] / examples / rsa-encrypt.c
1 /* rsa-encrypt.c
2
3    Copyright (C) 2002 Niels Möller
4
5    This file is part of GNU Nettle.
6
7    GNU Nettle is free software: you can redistribute it and/or
8    modify it under the terms of either:
9
10      * the GNU Lesser General Public License as published by the Free
11        Software Foundation; either version 3 of the License, or (at your
12        option) any later version.
13
14    or
15
16      * the GNU General Public License as published by the Free
17        Software Foundation; either version 2 of the License, or (at your
18        option) any later version.
19
20    or both in parallel, as here.
21
22    GNU Nettle is distributed in the hope that it will be useful,
23    but WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25    General Public License for more details.
26
27    You should have received copies of the GNU General Public License and
28    the GNU Lesser General Public License along with this program.  If
29    not, see http://www.gnu.org/licenses/.
30 */
31    
32 #if HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <assert.h>
37 #include <ctype.h>
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #ifdef WIN32
43 #include <fcntl.h>
44 #endif
45
46 /* string.h must be included before gmp.h */
47 #include "bignum.h"
48 #include "buffer.h"
49 #include "macros.h"
50 #include "rsa.h"
51 #include "yarrow.h"
52
53 #include "io.h"
54 #include "rsa-session.h"
55
56 #include "getopt.h"
57
58 void
59 rsa_session_set_encrypt_key(struct rsa_session *ctx,
60                             const struct rsa_session_info *key)
61 {
62   const uint8_t *aes_key = SESSION_AES_KEY(key);
63   const uint8_t *iv = SESSION_IV(key);
64   const uint8_t *hmac_key = SESSION_HMAC_KEY(key);
65   
66   aes256_set_encrypt_key(&ctx->aes.ctx, aes_key);
67   CBC_SET_IV(&ctx->aes, iv);
68   hmac_sha1_set_key(&ctx->hmac, SHA1_DIGEST_SIZE, hmac_key);
69 }
70
71 static int
72 write_uint32(FILE *f, uint32_t n)
73 {
74   uint8_t buffer[4];
75   WRITE_UINT32(buffer, n);
76
77   return write_data(f, sizeof(buffer), buffer);
78 }
79
80 static int
81 write_version(FILE *f)
82 {
83   return write_uint32(f, 1);
84 }
85
86 static int
87 write_bignum(FILE *f, mpz_t x)
88 {
89   unsigned size = nettle_mpz_sizeinbase_256_u(x);
90   uint8_t *p;
91   int res;
92   
93   if (!write_uint32(f, size))
94     return 0;
95   
96   p = xalloc(size);
97   nettle_mpz_get_str_256(size, p, x);
98
99   res = write_data(f, size, p);
100   free(p);
101   return res;
102 }
103
104 #define BLOCK_SIZE (AES_BLOCK_SIZE * 100)
105
106 static int
107 process_file(struct rsa_session *ctx,
108              FILE *in, FILE *out)
109 {
110   uint8_t buffer[BLOCK_SIZE + SHA1_DIGEST_SIZE];
111
112   for (;;)
113     {
114       size_t size = fread(buffer, 1, BLOCK_SIZE, in);
115       hmac_sha1_update(&ctx->hmac, size, buffer);
116
117       if (size < BLOCK_SIZE)
118         {
119           unsigned leftover;
120           unsigned padding;
121
122           if (ferror(in))
123             {
124               werror("Reading input failed: %s\n", strerror(errno));
125               return 0;
126             }
127           
128           leftover = size % AES_BLOCK_SIZE;
129           padding = AES_BLOCK_SIZE - leftover;
130
131           assert (size + padding <= BLOCK_SIZE);
132           
133           if (padding > 1)
134             yarrow256_random(&ctx->yarrow, padding - 1, buffer + size);
135
136           size += padding;
137
138           buffer[size - 1] = padding;
139           CBC_ENCRYPT(&ctx->aes, aes256_encrypt, size, buffer, buffer);
140
141           assert (size + SHA1_DIGEST_SIZE <= sizeof(buffer));
142
143           hmac_sha1_digest(&ctx->hmac, SHA1_DIGEST_SIZE, buffer + size);
144           size += SHA1_DIGEST_SIZE;
145
146           if (!write_data(out, size, buffer))
147             {
148               werror("Writing output failed: %s\n", strerror(errno));
149               return 0;
150             }
151           return 1;
152         }
153
154       CBC_ENCRYPT(&ctx->aes, aes256_encrypt, size, buffer, buffer);
155       if (!write_data(out, size, buffer))
156         {
157           werror("Writing output failed: %s\n", strerror(errno));
158           return 0;
159         }
160     }
161 }
162
163 static void
164 usage (FILE *out)
165 {
166   fprintf (out, "Usage: rsa-encrypt [OPTIONS] PUBLIC-KEY < cleartext\n"
167            "Options:\n"
168            "   -r, --random=FILE   seed file for randomness generator\n"
169            "       --help          display this help\n");  
170 }
171
172 int
173 main(int argc, char **argv)
174 {
175   struct rsa_session ctx;
176   struct rsa_session_info info;
177   
178   struct rsa_public_key key;
179   mpz_t x;
180   
181   int c;
182   const char *random_name = NULL;
183
184   enum { OPT_HELP = 300 };
185   
186   static const struct option options[] =
187     {
188       /* Name, args, flag, val */
189       { "help", no_argument, NULL, OPT_HELP },
190       { "random", required_argument, NULL, 'r' },
191       { NULL, 0, NULL, 0}
192     };
193   
194   while ( (c = getopt_long(argc, argv, "o:r:", options, NULL)) != -1)
195     switch (c)
196       {
197       case 'r':
198         random_name = optarg;
199         break;
200         
201       case '?':
202         return EXIT_FAILURE;
203
204       case OPT_HELP:
205         usage(stdout);
206         return EXIT_SUCCESS;
207       default:
208         abort();
209       }
210
211   argv += optind;
212   argc -= optind;
213
214   if (argc != 1)
215     {
216       usage (stderr);
217       return EXIT_FAILURE;
218     }
219
220   rsa_public_key_init(&key);
221   
222   if (!read_rsa_key(argv[0], &key, NULL))
223     {
224       werror("Invalid key\n");
225       return EXIT_FAILURE;
226     }
227
228   /* NOTE: No sources */
229   yarrow256_init(&ctx.yarrow, 0, NULL);
230   
231   /* Read some data to seed the generator */
232   if (!simple_random(&ctx.yarrow, random_name))
233     {
234       werror("Initialization of randomness generator failed.\n");
235       return EXIT_FAILURE;
236     }
237
238   WRITE_UINT32(SESSION_VERSION(&info), RSA_VERSION);
239   
240   yarrow256_random(&ctx.yarrow, sizeof(info.key) - 4, info.key + 4);
241
242   rsa_session_set_encrypt_key(&ctx, &info);
243   
244 #ifdef WIN32
245   _setmode(0, O_BINARY);
246   _setmode(1, O_BINARY);
247 #endif
248
249   write_version(stdout);
250   
251   mpz_init(x);
252
253   if (!rsa_encrypt(&key,
254                    &ctx.yarrow, (nettle_random_func *) yarrow256_random,
255                    sizeof(info.key), info.key, 
256                    x))
257     {
258       werror("RSA encryption failed.\n");
259       return EXIT_FAILURE;
260     }
261
262   write_bignum(stdout, x);
263
264   mpz_clear (x);
265
266   if (!process_file(&ctx,
267                     stdin, stdout))
268     return EXIT_FAILURE;
269
270   rsa_public_key_clear(&key);
271
272   return EXIT_SUCCESS;
273 }