rsa-encrypt.c 5.65 KB
Newer Older
1
/* rsa-encrypt.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
   
#if HAVE_CONFIG_H
# include "config.h"
#endif

36
#include <assert.h>
37 38 39 40 41
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
Martin Storsjö's avatar
Martin Storsjö committed
42 43 44
#ifdef WIN32
#include <fcntl.h>
#endif
45 46 47 48 49 50 51 52 53 54 55

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

#include "io.h"
#include "rsa-session.h"

56 57
#include "getopt.h"

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
void
rsa_session_set_encrypt_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);
  
  aes_set_encrypt_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);
}

static int
write_uint32(FILE *f, uint32_t n)
{
  uint8_t buffer[4];
  WRITE_UINT32(buffer, n);

77
  return write_data(f, sizeof(buffer), buffer);
78 79 80 81 82 83 84 85 86 87 88 89 90
}

static int
write_version(FILE *f)
{
  return write_uint32(f, 1);
}

static int
write_bignum(FILE *f, mpz_t x)
{
  unsigned size = nettle_mpz_sizeinbase_256_u(x);
  uint8_t *p;
91
  int res;
92 93 94 95
  
  if (!write_uint32(f, size))
    return 0;
  
96
  p = xalloc(size);
97 98
  nettle_mpz_get_str_256(size, p, x);

99
  res = write_data(f, size, p);
100 101
  free(p);
  return res;
102 103
}

104 105
#define BLOCK_SIZE (AES_BLOCK_SIZE * 100)

106 107 108 109
static int
process_file(struct rsa_session *ctx,
	     FILE *in, FILE *out)
{
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 120 121 122 123 124 125 126 127
	  unsigned leftover;
	  unsigned padding;

	  if (ferror(in))
	    {
	      werror("Reading input failed: %s\n", strerror(errno));
	      return 0;
	    }
	  
128 129 130
	  leftover = size % AES_BLOCK_SIZE;
	  padding = AES_BLOCK_SIZE - leftover;

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	  assert (size + padding <= BLOCK_SIZE);
	  
	  if (padding > 1)
	    yarrow256_random(&ctx->yarrow, padding - 1, buffer + size);

	  size += padding;

	  buffer[size - 1] = padding;
	  CBC_ENCRYPT(&ctx->aes, aes_encrypt, size, buffer, buffer);

	  assert (size + SHA1_DIGEST_SIZE <= sizeof(buffer));

	  hmac_sha1_digest(&ctx->hmac, SHA1_DIGEST_SIZE, buffer + size);
	  size += SHA1_DIGEST_SIZE;

146
	  if (!write_data(out, size, buffer))
147 148 149 150 151
	    {
	      werror("Writing output failed: %s\n", strerror(errno));
	      return 0;
	    }
	  return 1;
152 153 154
	}

      CBC_ENCRYPT(&ctx->aes, aes_encrypt, size, buffer, buffer);
155
      if (!write_data(out, size, buffer))
156 157 158 159 160
	{
	  werror("Writing output failed: %s\n", strerror(errno));
	  return 0;
	}
    }
161
}
162

163 164 165 166 167 168 169
static void
usage (FILE *out)
{
  fprintf (out, "Usage: rsa-encrypt [OPTIONS] PUBLIC-KEY < cleartext\n"
	   "Options:\n"
	   "   -r, --random=FILE   seed file for randomness generator\n"
	   "       --help          display this help\n");  
170 171 172 173 174 175 176 177 178 179 180 181 182
}

int
main(int argc, char **argv)
{
  struct rsa_session ctx;
  struct rsa_session_info info;
  
  struct rsa_public_key key;
  mpz_t x;
  
  int c;
  const char *random_name = NULL;
183

184 185 186 187 188 189 190 191 192 193 194
  enum { OPT_HELP = 300 };
  
  static const struct option options[] =
    {
      /* Name, args, flag, val */
      { "help", no_argument, NULL, OPT_HELP },
      { "random", required_argument, NULL, 'r' },
      { NULL, 0, NULL, 0}
    };
  
  while ( (c = getopt_long(argc, argv, "o:r:", options, NULL)) != -1)
195 196 197 198 199 200 201 202
    switch (c)
      {
      case 'r':
	random_name = optarg;
	break;
	
      case '?':
	return EXIT_FAILURE;
203

204 205 206
      case OPT_HELP:
	usage(stdout);
	return EXIT_SUCCESS;
207 208 209 210 211 212 213 214 215
      default:
	abort();
      }

  argv += optind;
  argc -= optind;

  if (argc != 1)
    {
216
      usage (stderr);
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
      return EXIT_FAILURE;
    }

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

  /* NOTE: No sources */
  yarrow256_init(&ctx.yarrow, 0, NULL);
  
  /* Read some data to seed the generator */
  if (!simple_random(&ctx.yarrow, random_name))
    {
      werror("Initialization of randomness generator failed.\n");
      return EXIT_FAILURE;
    }

  WRITE_UINT32(SESSION_VERSION(&info), RSA_VERSION);
  
  yarrow256_random(&ctx.yarrow, sizeof(info.key) - 4, info.key + 4);

  rsa_session_set_encrypt_key(&ctx, &info);
  
Martin Storsjö's avatar
Martin Storsjö committed
244
#ifdef WIN32
245 246
  _setmode(0, O_BINARY);
  _setmode(1, O_BINARY);
Martin Storsjö's avatar
Martin Storsjö committed
247 248
#endif

249 250 251 252 253
  write_version(stdout);
  
  mpz_init(x);

  if (!rsa_encrypt(&key,
254
		   &ctx.yarrow, (nettle_random_func *) yarrow256_random,
255 256 257 258 259 260 261 262
		   sizeof(info.key), info.key, 
		   x))
    {
      werror("RSA encryption failed.\n");
      return EXIT_FAILURE;
    }

  write_bignum(stdout, x);
Tim Ruehsen's avatar
Tim Ruehsen committed
263 264 265

  mpz_clear (x);

266 267 268
  if (!process_file(&ctx,
		    stdin, stdout))
    return EXIT_FAILURE;
Tim Ruehsen's avatar
Tim Ruehsen committed
269

270 271 272 273
  rsa_public_key_clear(&key);

  return EXIT_SUCCESS;
}