From 980c7cd3b9f3eab53527f75570c77d302ab13737 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se>
Date: Fri, 19 Sep 2003 15:16:59 +0200
Subject: [PATCH] New files, demonstrating rsa encryption and decryption.

Rev: src/nettle/examples/rsa-decrypt.c:1.1
Rev: src/nettle/examples/rsa-encrypt.c:1.1
Rev: src/nettle/examples/rsa-session.h:1.1
---
 examples/rsa-decrypt.c | 215 +++++++++++++++++++++++++++++++++++
 examples/rsa-encrypt.c | 246 +++++++++++++++++++++++++++++++++++++++++
 examples/rsa-session.h |  58 ++++++++++
 3 files changed, 519 insertions(+)
 create mode 100644 examples/rsa-decrypt.c
 create mode 100644 examples/rsa-encrypt.c
 create mode 100644 examples/rsa-session.h

diff --git a/examples/rsa-decrypt.c b/examples/rsa-decrypt.c
new file mode 100644
index 00000000..69668460
--- /dev/null
+++ b/examples/rsa-decrypt.c
@@ -0,0 +1,215 @@
+/* rsa-decrypt.c
+ *
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2002 Niels Möller
+ *  
+ * 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
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* For getopt */
+#include <unistd.h>
+
+/* 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"
+
+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);
+  
+  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);
+}
+
+static int
+read_uint32(FILE *f, uint32_t *n)
+{
+  uint8_t buf[4];
+  if (fread(buf, 1, sizeof(buf), f) != sizeof(buf))
+    return 0;
+
+  *n = WRITE_UINT32(buf);
+  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)
+    {
+      uint8_t *p = alloca(size);
+      if (fread(p, 1, size, f) != size)
+	return 0;
+
+      nettle_mpz_set_str_256_u(x, size, p);
+      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;
+};
+
+static int
+process_file(struct process_ctx *ctx,
+	     FILE *in, FILE *out)
+{
+  uint8_t buffer[AES_BLOCK_SIZE * 100];
+  unsigned leftover;
+  unsigned padding;
+
+  /* FIXME: Cut'n'paste code, not working yet */
+  abort();
+  for (padding = leftover = 0; padding == 0;)
+    {
+      size_t size = fread(buffer, 1, sizeof(buffer), in);
+      if (ferror(in))
+	{
+	  werror("Reading input failed: %s\n", strerror(errno));
+	  return 0;
+	}
+
+      hmac_sha1_update(&ctx->hmac, size, buffer);
+      if (size < sizeof(buffer))
+	{
+	  /* Setting padding != ends the loop */
+	  leftover = size % AES_BLOCK_SIZE;
+	  padding = AES_BLOCK_SIZE - leftover;
+	  size -= leftover;
+
+	  if (!size)
+	    break;
+	}
+
+      CBC_DECRYPT(&ctx->aes, aes_encrypt, size, buffer, buffer);
+      if (!write_string(out, size, buffer))
+	{
+	  werror("Writing output failed: %s\n", strerror(errno));
+	  return 0;
+	}
+    }
+  if (padding > 1)
+    yarrow256_random(&ctx->yarrow, padding - 1, buffer + leftover);
+
+  buffer[AES_BLOCK_SIZE - 1] = padding;
+  CBC_ENCRYPT(&ctx->aes, aes_encrypt, AES_BLOCK_SIZE, buffer, buffer);
+  hmac_sha1_digest(&ctx->hmac, SHA1_DIGEST_SIZE, buffer + AES_BLOCK_SIZE);
+  if (!write_string(out, AES_BLOCK_SIZE + SHA1_DIGEST_SIZE, buffer))
+    {
+      werror("Writing output failed: %s\n", strerror(errno));
+      return 0;
+    }
+
+  return 1;
+}
+
+int
+main(int argc, char **argv)
+{
+  struct process_ctx ctx;
+  
+  struct rsa_private_key key;
+  struct rsa_session ctx;
+  struct rsa_session_info session;
+
+  unsigned length;
+  mpz_t x;
+  
+  int c;
+  
+  if (argc != 2)
+    {
+      werror("Usage: rsa-decrypt PRIVATE-KEY < ciphertext\n");
+      return EXIT_FAILURE;
+    }
+
+  rsa_public_key_init(&pub);
+  rsa_private_key_init(&key);
+  
+  if (!read_rsa_key(argv[1], NULL, &key))
+    {
+      werror("Invalid key\n");
+      return EXIT_FAILURE;
+    }
+
+  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);
+  if (!rsa_decrypt(&key, &length, session->key, x))
+    {
+      werror("Failed to decrypt rsa header in input file.\n");
+      return EXIT_FAILURE;      
+    }
+
+  rsa_session_set_decrypt_key(&ctx, &session);
+
+  if (!process_file(&ctx,
+		    stdin, stdout))
+    return EXIT_FAILURE;
+  
+  rsa_private_key_clear(&key);
+
+  return EXIT_SUCCESS;
+}
diff --git a/examples/rsa-encrypt.c b/examples/rsa-encrypt.c
new file mode 100644
index 00000000..c597f997
--- /dev/null
+++ b/examples/rsa-encrypt.c
@@ -0,0 +1,246 @@
+/* rsa-encrypt.c
+ *
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2002 Niels Möller
+ *  
+ * 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
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/* Encryption program using the following file format:
+
+     uint32_t version = 1;
+     uint32_t nsize;
+     uint8_t x[nsize];
+     uint8_t encrypted[n];
+     uint8_t hmac[SHA1_DIGEST_SIZE];
+
+   where x is the data
+
+     uint32_t version = 1;
+     uint8_t aes_key[AES_KEY_SIZE];
+     uint8_t iv[AES_BLOCK_SIZE];
+     uint8_t hmac_key[SHA1_DIGEST_SIZE];
+
+   of size (4 + AES_KEY_SIZE + AES_BLOCK_SIZE + SHA1_DIGEST_SIZE) = 72
+   bytes, encrypted using rsa-pkcs1.
+*/
+   
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* For getopt */
+#include <unistd.h>
+
+/* 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"
+
+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;
+  
+  if (!write_uint32(f, size))
+    return 0;
+  
+  p = alloca(size);
+  nettle_mpz_get_str_256(size, p, x);
+
+  return write_string(f, size, p);
+}
+
+static int
+process_file(struct rsa_session *ctx,
+	     FILE *in, FILE *out)
+{
+  uint8_t buffer[AES_BLOCK_SIZE * 100];
+  unsigned leftover;
+  unsigned padding;
+  
+  for (padding = leftover = 0; padding == 0;)
+    {
+      size_t size = fread(buffer, 1, sizeof(buffer), in);
+      if (ferror(in))
+	{
+	  werror("Reading input failed: %s\n", strerror(errno));
+	  return 0;
+	}
+
+      hmac_sha1_update(&ctx->hmac, size, buffer);
+      if (size < sizeof(buffer))
+	{
+	  /* Setting padding != ends the loop */
+	  leftover = size % AES_BLOCK_SIZE;
+	  padding = AES_BLOCK_SIZE - leftover;
+	  size -= leftover;
+
+	  if (!size)
+	    break;
+	}
+
+      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;
+	}
+    }
+  if (padding > 1)
+    yarrow256_random(&ctx->yarrow, padding - 1, buffer + leftover);
+
+  buffer[AES_BLOCK_SIZE - 1] = padding;
+  CBC_ENCRYPT(&ctx->aes, aes_encrypt, AES_BLOCK_SIZE, buffer, buffer);
+  hmac_sha1_digest(&ctx->hmac, SHA1_DIGEST_SIZE, buffer + AES_BLOCK_SIZE);
+  if (!write_string(out, AES_BLOCK_SIZE + SHA1_DIGEST_SIZE, buffer))
+    {
+      werror("Writing output failed: %s\n", strerror(errno));
+      return 0;
+    }
+
+  return 1;
+}
+
+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;
+  
+  while ( (c = getopt(argc, argv, "o:r:")) != -1)
+    switch (c)
+      {
+      case 'r':
+	random_name = optarg;
+	break;
+	
+      case '?':
+	if (isprint (optopt))
+	  werror("Unknown option `-%c'.\n", optopt);
+	else
+	  werror("Unknown option character `\\x%x'.\n",
+		  optopt);
+	return EXIT_FAILURE;
+      default:
+	abort();
+      }
+
+  argv += optind;
+  argc -= optind;
+
+  if (argc != 1)
+    {
+      werror("Usage: rsa-encrypt [-r random-file] PUBLIC-KEY < cleartext\n");
+      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);
+  
+  write_version(stdout);
+  
+  mpz_init(x);
+
+  if (!rsa_encrypt(&key,
+		   &ctx.yarrow, (nettle_random_func) yarrow256_random,
+		   sizeof(info.key), info.key, 
+		   x))
+    {
+      werror("RSA encryption failed.\n");
+      return EXIT_FAILURE;
+    }
+
+  write_bignum(stdout, x);
+  
+  if (!process_file(&ctx,
+		    stdin, stdout))
+    return EXIT_FAILURE;
+  
+  rsa_public_key_clear(&key);
+
+  return EXIT_SUCCESS;
+}
diff --git a/examples/rsa-session.h b/examples/rsa-session.h
new file mode 100644
index 00000000..7e161c81
--- /dev/null
+++ b/examples/rsa-session.h
@@ -0,0 +1,58 @@
+/* Session key definitions for the rsa-encrypt and rsa-decrypt programs.
+ */
+
+#ifndef NETTLE_EXAMPLES_RSA_SESSION_H_INCLUDED
+#define NETTLE_EXAMPLES_RSA_SESSION_H_INCLUDED
+
+#include "aes.h"
+#include "cbc.h"
+#include "hmac.h"
+
+#define RSA_VERSION 1
+
+/* Encryption program using the following file format:
+
+     uint32_t version = 1;
+     uint32_t nsize;
+     uint8_t x[nsize];
+     uint8_t encrypted[n];
+     uint8_t hmac[SHA1_DIGEST_SIZE];
+
+   where x is the data
+
+     uint32_t version = 1;
+     uint8_t aes_key[AES_KEY_SIZE];
+     uint8_t iv[AES_BLOCK_SIZE];
+     uint8_t hmac_key[SHA1_DIGEST_SIZE];
+
+   of size (4 + AES_KEY_SIZE + AES_BLOCK_SIZE + SHA1_DIGEST_SIZE) = 72
+   bytes, encrypted using rsa-pkcs1.
+*/
+
+struct rsa_session
+{
+  struct CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE) aes;
+  struct hmac_sha1_ctx hmac;
+  struct yarrow256_ctx yarrow;
+};
+
+struct rsa_session_info
+{
+  /* Version followed by aes key, iv and mac key */
+  uint8_t key[4 + AES_KEY_SIZE + AES_BLOCK_SIZE + SHA1_DIGEST_SIZE];
+};
+
+#define SESSION_VERSION(s) ((s)->key)
+#define SESSION_AES_KEY(s) ((s)->key + 4)
+#define SESSION_IV(s) ((s)->key + 4 + AES_KEY_SIZE)
+#define SESSION_HMAC_KEY(s) ((s)->key + 4 + AES_KEY_SIZE + AES_BLOCK_SIZE)
+
+void
+rsa_session_set_encrypt_key(struct rsa_session *ctx,
+			    const struct rsa_session_info *key);
+
+void
+rsa_session_set_decrypt_key(struct rsa_session *ctx,
+			    const struct rsa_session_info *key);
+
+#endif /* NETTLE_EXAMPLES_RSA_SESSION_H_INCLUDED */
-- 
GitLab