rsa-decrypt.c 5.57 KB
Newer Older
1
/* rsa-decrypt.c
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

   Copyright (C) 2002 Niels Möller

   This file is part of GNU Nettle.

   GNU Nettle is free software: you can redistribute it and/or
   modify it under the terms of either:

     * the GNU Lesser General Public License as published by the Free
       Software Foundation; either version 3 of the License, or (at your
       option) any later version.

   or

     * the GNU General Public License as published by the Free
       Software Foundation; either version 2 of the License, or (at your
       option) any later version.

   or both in parallel, as here.

   GNU Nettle 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
   General Public License for more details.

   You should have received copies of the GNU General Public License and
   the GNU Lesser General Public License along with this program.  If
   not, see http://www.gnu.org/licenses/.
*/
31 32 33 34 35 36 37 38 39 40

#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
41 42 43
#ifdef WIN32
#include <fcntl.h>
#endif
44 45 46 47 48 49 50 51 52 53 54 55

/* 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"
56
#include "rsa-session.h"
57 58 59 60 61 62 63 64 65

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);
  
66 67 68
  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);
69 70 71 72 73 74 75 76 77
}

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

78
  *n = READ_UINT32(buf);
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
  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)
    {
96
      uint8_t *p = xalloc(size);
97
      if (fread(p, 1, size, f) != size)
98 99 100 101
	{
	  free(p);
	  return 0;
	}
102 103

      nettle_mpz_set_str_256_u(x, size, p);
104 105
      free(p);

106 107 108 109 110 111 112 113 114 115 116 117
      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;
};

118 119 120 121 122
#define BUF_SIZE (100 * AES_BLOCK_SIZE)

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

123
static int
124
process_file(struct rsa_session *ctx,
125 126
	     FILE *in, FILE *out)
{
127 128 129
  uint8_t buffer[BUF_SIZE + BUF_FINAL];
  uint8_t digest[SHA1_DIGEST_SIZE];
  size_t size;
130 131
  unsigned padding;

132
  size = fread(buffer, 1, BUF_FINAL, in);
133
  if (size < BUF_FINAL)
134
    {
135 136 137 138
      if (ferror(in))
	werror("Reading input failed: %s\n", strerror(errno));
      else
	werror("Unexpected EOF on input.\n");
139 140 141 142
      return 0;
    }

  do
143
    {
144 145
      size = fread(buffer + BUF_FINAL, 1, BUF_SIZE, in);

146
      if (size < BUF_SIZE && ferror(in))
147 148 149 150 151
	{
	  werror("Reading input failed: %s\n", strerror(errno));
	  return 0;
	}

152
      if (size % AES_BLOCK_SIZE != 0)
153
	{
154 155 156
	  werror("Unexpected EOF on input.\n");
	  return 0;
	}
157

158 159 160 161
      if (size)
	{
	  CBC_DECRYPT(&ctx->aes, aes_decrypt, size, buffer, buffer);
	  hmac_sha1_update(&ctx->hmac, size, buffer);
162
	  if (!write_data(out, size, buffer))
163 164 165 166 167
	    {
	      werror("Writing output failed: %s\n", strerror(errno));
	      return 0;
	    }
	  memmove(buffer, buffer + size, BUF_FINAL);
168
	}
169 170
    }
  while (size == BUF_SIZE);
171

172 173 174 175 176 177 178 179 180 181 182 183 184
  /* 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);
185
      if (!write_data(out, leftover, buffer))
186 187 188 189 190
	{
	  werror("Writing output failed: %s\n", strerror(errno));
	  return 0;
	}
    }
191 192
  hmac_sha1_digest(&ctx->hmac, SHA1_DIGEST_SIZE, digest);
  if (memcmp(digest, buffer + AES_BLOCK_SIZE, SHA1_DIGEST_SIZE) != 0)
193
    {
194
      werror("Decryption failed: Invalid mac.\n");
195 196
      return 0;
    }
197
  
198 199 200 201 202 203 204 205 206 207
  return 1;
}

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

208
  size_t length;
209
  mpz_t x;
210 211

  mpz_init(x);
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
  
  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
227
#ifdef WIN32
228 229
  _setmode(0, O_BINARY);
  _setmode(1, O_BINARY);
Martin Storsjö's avatar
Martin Storsjö committed
230 231
#endif

232 233 234 235 236 237 238 239 240 241 242 243 244
  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);
245
  if (!rsa_decrypt(&key, &length, session.key, x) || length != sizeof(session.key))
246 247 248 249
    {
      werror("Failed to decrypt rsa header in input file.\n");
      return EXIT_FAILURE;      
    }
250 251
  mpz_clear(x);
  
252 253 254 255 256 257 258 259 260 261
  rsa_session_set_decrypt_key(&ctx, &session);

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

  return EXIT_SUCCESS;
}