Imported Upstream version 2.4
[platform/upstream/nettle.git] / examples / rsa-decrypt.c
1 /* rsa-decrypt.c
2  *
3  */
4
5 /* nettle, low-level cryptographics library
6  *
7  * Copyright (C) 2002 Niels Möller
8  *  
9  * The nettle library is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or (at your
12  * option) any later version.
13  * 
14  * The nettle library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
17  * License for more details.
18  * 
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with the nettle library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22  * MA 02111-1307, USA.
23  */
24
25 #if HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <ctype.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34
35 /* string.h must be included before gmp.h */
36 #include "aes.h"
37 #include "bignum.h"
38 #include "buffer.h"
39 #include "cbc.h"
40 #include "hmac.h"
41 #include "macros.h"
42 #include "rsa.h"
43 #include "yarrow.h"
44
45 #include "io.h"
46 #include "rsa-session.h"
47
48 void
49 rsa_session_set_decrypt_key(struct rsa_session *ctx,
50                             const struct rsa_session_info *key)
51 {
52   const uint8_t *aes_key = SESSION_AES_KEY(key);
53   const uint8_t *iv = SESSION_IV(key);
54   const uint8_t *hmac_key = SESSION_HMAC_KEY(key);
55   
56   aes_set_decrypt_key(&ctx->aes.ctx, AES_KEY_SIZE, aes_key);
57   CBC_SET_IV(&ctx->aes, iv);
58   hmac_sha1_set_key(&ctx->hmac, SHA1_DIGEST_SIZE, hmac_key);
59 }
60
61 static int
62 read_uint32(FILE *f, uint32_t *n)
63 {
64   uint8_t buf[4];
65   if (fread(buf, 1, sizeof(buf), f) != sizeof(buf))
66     return 0;
67
68   *n = READ_UINT32(buf);
69   return 1;
70 }
71
72 static int
73 read_version(FILE *f)
74 {
75   uint32_t version;
76   return read_uint32(f, &version) && version == RSA_VERSION;
77 }
78
79 static int
80 read_bignum(FILE *f, mpz_t x)
81 {
82   uint32_t size;
83   if (read_uint32(f, &size)
84       && size < 1000)
85     {
86       uint8_t *p = xalloc(size);
87       if (fread(p, 1, size, f) != size)
88         {
89           free(p);
90           return 0;
91         }
92
93       nettle_mpz_set_str_256_u(x, size, p);
94       free(p);
95
96       return 1;
97     }
98   return 0;
99 }
100
101 struct process_ctx
102 {
103   struct CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE) aes;
104   struct hmac_sha1_ctx hmac;
105   struct yarrow256_ctx yarrow;
106 };
107
108 #define BUF_SIZE (100 * AES_BLOCK_SIZE)
109
110 /* Trailing data that needs special processing */
111 #define BUF_FINAL (AES_BLOCK_SIZE + SHA1_DIGEST_SIZE)
112
113 static int
114 process_file(struct rsa_session *ctx,
115              FILE *in, FILE *out)
116 {
117   uint8_t buffer[BUF_SIZE + BUF_FINAL];
118   uint8_t digest[SHA1_DIGEST_SIZE];
119   size_t size;
120   unsigned padding;
121
122   size = fread(buffer, 1, BUF_FINAL, in);
123   if (size < BUF_FINAL || ferror(in))
124     {
125       werror("Reading input failed: %s\n", strerror(errno));
126       return 0;
127     }
128
129   do
130     {
131       size = fread(buffer + BUF_FINAL, 1, BUF_SIZE, in);
132
133       if (ferror(in))
134         {
135           werror("Reading input failed: %s\n", strerror(errno));
136           return 0;
137         }
138
139       if (size % AES_BLOCK_SIZE != 0)
140         {
141           werror("Unexpected EOF on input.\n");
142           return 0;
143         }
144
145       if (size)
146         {
147           CBC_DECRYPT(&ctx->aes, aes_decrypt, size, buffer, buffer);
148           hmac_sha1_update(&ctx->hmac, size, buffer);
149           if (!write_string(out, size, buffer))
150             {
151               werror("Writing output failed: %s\n", strerror(errno));
152               return 0;
153             }
154           memmove(buffer, buffer + size, BUF_FINAL);
155         }
156     }
157   while (size == BUF_SIZE);
158
159   /* Decrypt final block */
160   CBC_DECRYPT(&ctx->aes, aes_decrypt, AES_BLOCK_SIZE, buffer, buffer);
161   padding = buffer[AES_BLOCK_SIZE - 1];
162   if (padding > AES_BLOCK_SIZE)
163     {
164       werror("Decryption failed: Invalid padding.\n");
165       return 0;
166     }
167
168   if (padding < AES_BLOCK_SIZE)
169     {
170       unsigned leftover = AES_BLOCK_SIZE - padding;
171       hmac_sha1_update(&ctx->hmac, leftover, buffer);
172       if (!write_string(out, leftover, buffer))
173         {
174           werror("Writing output failed: %s\n", strerror(errno));
175           return 0;
176         }
177     }
178   hmac_sha1_digest(&ctx->hmac, SHA1_DIGEST_SIZE, digest);
179   if (memcmp(digest, buffer + AES_BLOCK_SIZE, SHA1_DIGEST_SIZE) != 0)
180     {
181       werror("Decryption failed: Invalid mac.\n");
182       return 0;
183     }
184   
185   return 1;
186 }
187
188 int
189 main(int argc, char **argv)
190 {
191   struct rsa_private_key key;
192   struct rsa_session ctx;
193   struct rsa_session_info session;
194
195   unsigned length;
196   mpz_t x;
197
198   mpz_init(x);
199   
200   if (argc != 2)
201     {
202       werror("Usage: rsa-decrypt PRIVATE-KEY < ciphertext\n");
203       return EXIT_FAILURE;
204     }
205
206   rsa_private_key_init(&key);
207   
208   if (!read_rsa_key(argv[1], NULL, &key))
209     {
210       werror("Invalid key\n");
211       return EXIT_FAILURE;
212     }
213
214   if (!read_version(stdin))
215     {
216       werror("Bad version number in input file.\n");
217       return EXIT_FAILURE;
218     }
219
220   if (!read_bignum(stdin, x))
221     {
222       werror("Bad rsa header in input file.\n");
223       return EXIT_FAILURE;
224     }
225
226   length = sizeof(session.key);
227   if (!rsa_decrypt(&key, &length, session.key, x) || length != sizeof(session.key))
228     {
229       werror("Failed to decrypt rsa header in input file.\n");
230       return EXIT_FAILURE;      
231     }
232   mpz_clear(x);
233   
234   rsa_session_set_decrypt_key(&ctx, &session);
235
236   if (!process_file(&ctx,
237                     stdin, stdout))
238     return EXIT_FAILURE;
239   
240   rsa_private_key_clear(&key);
241
242   return EXIT_SUCCESS;
243 }