rsa-decrypt.c 5.47 KB
Newer Older
1
2
3
4
5
6
/* rsa-decrypt.c
 *
 */

/* nettle, low-level cryptographics library
 *
Niels Möller's avatar
Niels Möller committed
7
 * Copyright (C) 2002 Niels Möller
8
9
10
11
12
13
14
15
16
17
18
19
20
 *  
 * The nettle library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * The nettle library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with the nettle library; see the file COPYING.LIB.  If not, write to
21
22
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02111-1301, USA.
23
24
25
26
27
28
29
30
31
32
33
 */

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
Martin Storsjö's avatar
Martin Storsjö committed
34
35
36
#ifdef WIN32
#include <fcntl.h>
#endif
37
38
39
40
41
42
43
44
45
46
47
48

/* string.h must be included before gmp.h */
#include "aes.h"
#include "bignum.h"
#include "buffer.h"
#include "cbc.h"
#include "hmac.h"
#include "macros.h"
#include "rsa.h"
#include "yarrow.h"

#include "io.h"
49
#include "rsa-session.h"
50
51
52
53
54
55
56
57
58

void
rsa_session_set_decrypt_key(struct rsa_session *ctx,
			    const struct rsa_session_info *key)
{
  const uint8_t *aes_key = SESSION_AES_KEY(key);
  const uint8_t *iv = SESSION_IV(key);
  const uint8_t *hmac_key = SESSION_HMAC_KEY(key);
  
59
60
61
  aes_set_decrypt_key(&ctx->aes.ctx, AES_KEY_SIZE, aes_key);
  CBC_SET_IV(&ctx->aes, iv);
  hmac_sha1_set_key(&ctx->hmac, SHA1_DIGEST_SIZE, hmac_key);
62
63
64
65
66
67
68
69
70
}

static int
read_uint32(FILE *f, uint32_t *n)
{
  uint8_t buf[4];
  if (fread(buf, 1, sizeof(buf), f) != sizeof(buf))
    return 0;

71
  *n = READ_UINT32(buf);
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  return 1;
}

static int
read_version(FILE *f)
{
  uint32_t version;
  return read_uint32(f, &version) && version == RSA_VERSION;
}

static int
read_bignum(FILE *f, mpz_t x)
{
  uint32_t size;
  if (read_uint32(f, &size)
      && size < 1000)
    {
89
      uint8_t *p = xalloc(size);
90
      if (fread(p, 1, size, f) != size)
91
92
93
94
	{
	  free(p);
	  return 0;
	}
95
96

      nettle_mpz_set_str_256_u(x, size, p);
97
98
      free(p);

99
100
101
102
103
104
105
106
107
108
109
110
      return 1;
    }
  return 0;
}

struct process_ctx
{
  struct CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE) aes;
  struct hmac_sha1_ctx hmac;
  struct yarrow256_ctx yarrow;
};

111
112
113
114
115
#define BUF_SIZE (100 * AES_BLOCK_SIZE)

/* Trailing data that needs special processing */
#define BUF_FINAL (AES_BLOCK_SIZE + SHA1_DIGEST_SIZE)

116
static int
117
process_file(struct rsa_session *ctx,
118
119
	     FILE *in, FILE *out)
{
120
121
122
  uint8_t buffer[BUF_SIZE + BUF_FINAL];
  uint8_t digest[SHA1_DIGEST_SIZE];
  size_t size;
123
124
  unsigned padding;

125
  size = fread(buffer, 1, BUF_FINAL, in);
126
  if (size < BUF_FINAL)
127
    {
128
129
130
131
      if (ferror(in))
	werror("Reading input failed: %s\n", strerror(errno));
      else
	werror("Unexpected EOF on input.\n");
132
133
134
135
      return 0;
    }

  do
136
    {
137
138
      size = fread(buffer + BUF_FINAL, 1, BUF_SIZE, in);

139
      if (size < BUF_SIZE && ferror(in))
140
141
142
143
144
	{
	  werror("Reading input failed: %s\n", strerror(errno));
	  return 0;
	}

145
      if (size % AES_BLOCK_SIZE != 0)
146
	{
147
148
149
	  werror("Unexpected EOF on input.\n");
	  return 0;
	}
150

151
152
153
154
155
156
157
158
159
160
      if (size)
	{
	  CBC_DECRYPT(&ctx->aes, aes_decrypt, size, buffer, buffer);
	  hmac_sha1_update(&ctx->hmac, size, buffer);
	  if (!write_string(out, size, buffer))
	    {
	      werror("Writing output failed: %s\n", strerror(errno));
	      return 0;
	    }
	  memmove(buffer, buffer + size, BUF_FINAL);
161
	}
162
163
    }
  while (size == BUF_SIZE);
164

165
166
167
168
169
170
171
172
173
174
175
176
177
178
  /* Decrypt final block */
  CBC_DECRYPT(&ctx->aes, aes_decrypt, AES_BLOCK_SIZE, buffer, buffer);
  padding = buffer[AES_BLOCK_SIZE - 1];
  if (padding > AES_BLOCK_SIZE)
    {
      werror("Decryption failed: Invalid padding.\n");
      return 0;
    }

  if (padding < AES_BLOCK_SIZE)
    {
      unsigned leftover = AES_BLOCK_SIZE - padding;
      hmac_sha1_update(&ctx->hmac, leftover, buffer);
      if (!write_string(out, leftover, buffer))
179
180
181
182
183
	{
	  werror("Writing output failed: %s\n", strerror(errno));
	  return 0;
	}
    }
184
185
  hmac_sha1_digest(&ctx->hmac, SHA1_DIGEST_SIZE, digest);
  if (memcmp(digest, buffer + AES_BLOCK_SIZE, SHA1_DIGEST_SIZE) != 0)
186
    {
187
      werror("Decryption failed: Invalid mac.\n");
188
189
      return 0;
    }
190
  
191
192
193
194
195
196
197
198
199
200
  return 1;
}

int
main(int argc, char **argv)
{
  struct rsa_private_key key;
  struct rsa_session ctx;
  struct rsa_session_info session;

201
  size_t length;
202
  mpz_t x;
203
204

  mpz_init(x);
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
  
  if (argc != 2)
    {
      werror("Usage: rsa-decrypt PRIVATE-KEY < ciphertext\n");
      return EXIT_FAILURE;
    }

  rsa_private_key_init(&key);
  
  if (!read_rsa_key(argv[1], NULL, &key))
    {
      werror("Invalid key\n");
      return EXIT_FAILURE;
    }

Martin Storsjö's avatar
Martin Storsjö committed
220
#ifdef WIN32
221
222
  _setmode(0, O_BINARY);
  _setmode(1, O_BINARY);
Martin Storsjö's avatar
Martin Storsjö committed
223
224
#endif

225
226
227
228
229
230
231
232
233
234
235
236
237
  if (!read_version(stdin))
    {
      werror("Bad version number in input file.\n");
      return EXIT_FAILURE;
    }

  if (!read_bignum(stdin, x))
    {
      werror("Bad rsa header in input file.\n");
      return EXIT_FAILURE;
    }

  length = sizeof(session.key);
238
  if (!rsa_decrypt(&key, &length, session.key, x) || length != sizeof(session.key))
239
240
241
242
    {
      werror("Failed to decrypt rsa header in input file.\n");
      return EXIT_FAILURE;      
    }
243
244
  mpz_clear(x);
  
245
246
247
248
249
250
251
252
253
254
  rsa_session_set_decrypt_key(&ctx, &session);

  if (!process_file(&ctx,
		    stdin, stdout))
    return EXIT_FAILURE;
  
  rsa_private_key_clear(&key);

  return EXIT_SUCCESS;
}