rsa-encrypt.c 5.55 KB
Newer Older
1 2 3 4 5 6
/* rsa-encrypt.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
 */
   
#if HAVE_CONFIG_H
# include "config.h"
#endif

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

/* 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"

49 50
#include "getopt.h"

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
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);

  return write_string(f, sizeof(buffer), buffer);
}

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;
84
  int res;
85 86 87 88
  
  if (!write_uint32(f, size))
    return 0;
  
89
  p = xalloc(size);
90 91
  nettle_mpz_get_str_256(size, p, x);

92 93 94
  res = write_string(f, size, p);
  free(p);
  return res;
95 96
}

97 98
#define BLOCK_SIZE (AES_BLOCK_SIZE * 100)

99 100 101 102
static int
process_file(struct rsa_session *ctx,
	     FILE *in, FILE *out)
{
103
  uint8_t buffer[BLOCK_SIZE + SHA1_DIGEST_SIZE];
104 105

  for (;;)
106
    {
107
      size_t size = fread(buffer, 1, BLOCK_SIZE, in);
108
      hmac_sha1_update(&ctx->hmac, size, buffer);
109 110

      if (size < BLOCK_SIZE)
111
	{
112 113 114 115 116 117 118 119 120
	  unsigned leftover;
	  unsigned padding;

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

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
	  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;

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

      CBC_ENCRYPT(&ctx->aes, aes_encrypt, size, buffer, buffer);
      if (!write_string(out, size, buffer))
	{
	  werror("Writing output failed: %s\n", strerror(errno));
	  return 0;
	}
    }
154
}
155

156 157 158 159 160 161 162
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");  
163 164 165 166 167 168 169 170 171 172 173 174 175
}

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;
176

177 178 179 180 181 182 183 184 185 186 187
  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)
188 189 190 191 192 193 194 195
    switch (c)
      {
      case 'r':
	random_name = optarg;
	break;
	
      case '?':
	return EXIT_FAILURE;
196

197 198 199
      case OPT_HELP:
	usage(stdout);
	return EXIT_SUCCESS;
200 201 202 203 204 205 206 207 208
      default:
	abort();
      }

  argv += optind;
  argc -= optind;

  if (argc != 1)
    {
209
      usage (stderr);
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
      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
237
#ifdef WIN32
238 239
  _setmode(0, O_BINARY);
  _setmode(1, O_BINARY);
Martin Storsjö's avatar
Martin Storsjö committed
240 241
#endif

242 243 244 245 246
  write_version(stdout);
  
  mpz_init(x);

  if (!rsa_encrypt(&key,
247
		   &ctx.yarrow, (nettle_random_func *) yarrow256_random,
248 249 250 251 252 253 254 255
		   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
256 257 258

  mpz_clear (x);

259 260 261
  if (!process_file(&ctx,
		    stdin, stdout))
    return EXIT_FAILURE;
Tim Ruehsen's avatar
Tim Ruehsen committed
262

263 264 265 266
  rsa_public_key_clear(&key);

  return EXIT_SUCCESS;
}