Browse Source

add rsa_shrink_key()

Steffen Jaeckel 6 years ago
parent
commit
4e28b922a9
4 changed files with 94 additions and 0 deletions
  1. 9 0
      doc/crypt.tex
  2. 2 0
      src/headers/tomcrypt_pk.h
  3. 69 0
      src/pk/rsa/rsa_key.c
  4. 14 0
      tests/rsa_test.c

+ 9 - 0
doc/crypt.tex

@@ -4362,6 +4362,15 @@ int rsa_get_size(rsa_key *key);
 \end{verbatim}
 This can be used to determine the modulus size of an RSA key.
 
+\subsection{RSA Key Shrinking}
+To shrink an RSA key, use the following function:
+\index{rsa\_shrink\_key()}
+\begin{verbatim}
+void rsa_shrink_key(rsa_key *key);
+\end{verbatim}
+This can be used to shrink a key to its minimal memory requirements
+e.g. in cases where you have a long-lived RSA key in a memory-constrained system.
+
 \mysection{RSA Key Encryption}
 Normally RSA is used to encrypt short symmetric keys which are then used in block ciphers to encrypt a message.
 To facilitate encrypting short keys the following functions have been provided.

+ 2 - 0
src/headers/tomcrypt_pk.h

@@ -60,6 +60,8 @@ int rsa_exptmod(const unsigned char *in,   unsigned long inlen,
 
 void rsa_free(rsa_key *key);
 
+void rsa_shrink_key(rsa_key *key);
+
 /* These use PKCS #1 v2.0 padding */
 #define rsa_encrypt_key(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _prng, _prng_idx, _hash_idx, _key) \
   rsa_encrypt_key_ex(_in, _inlen, _out, _outlen, _lparam, _lparamlen, _prng, _prng_idx, _hash_idx, LTC_PKCS_1_OAEP, _key)

+ 69 - 0
src/pk/rsa/rsa_key.c

@@ -15,6 +15,75 @@
 */
 
 #ifdef LTC_MRSA
+#include <stdarg.h>
+
+static void _mpi_shrink_multi(void **a, ...)
+{
+   void **cur;
+   unsigned n;
+   int err;
+   va_list args;
+   void *tmp[10] = { 0 };
+   void **arg[10] = { 0 };
+
+   /* We re-allocate in the order that we received the varargs */
+   n = 0;
+   err = CRYPT_ERROR;
+   cur = a;
+   va_start(args, a);
+   while (cur != NULL) {
+      if (n >= sizeof(tmp)/sizeof(tmp[0])) {
+         goto out;
+      }
+      if (*cur != NULL) {
+         arg[n] = cur;
+         if ((err = mp_init_copy(&tmp[n], *arg[n])) != CRYPT_OK) {
+            goto out;
+         }
+         n++;
+      }
+      cur = va_arg(args, void**);
+   }
+   va_end(args);
+
+   /* but we clear the old values in the reverse order */
+   while (n != 0 && arg[--n] != NULL) {
+      mp_clear(*arg[n]);
+      *arg[n] = tmp[n];
+   }
+out:
+   va_end(args);
+   /* clean-up after an error
+    * or after this was called with too many args
+    */
+   if ((err != CRYPT_OK) ||
+         (n >= sizeof(tmp)/sizeof(tmp[0]))) {
+      for (n = 0; n < sizeof(tmp)/sizeof(tmp[0]); ++n) {
+         if (tmp[n] != NULL) {
+            mp_clear(tmp[n]);
+         }
+      }
+   }
+}
+
+/**
+  This shrinks the allocated memory of a RSA key
+
+     It will use up some more memory temporarily,
+     but then it will free-up the entire sequence that
+     was once allocated when the key was created/populated.
+
+     This only works with libtommath >= 1.2.0 in earlier versions
+     it has the inverse effect due to the way it worked internally.
+     Also works for GNU MP, tomsfastmath naturally shows no effect.
+
+  @param key   The RSA key to shrink
+*/
+void rsa_shrink_key(rsa_key *key)
+{
+   LTC_ARGCHKVD(key != NULL);
+   _mpi_shrink_multi(&key->e, &key->d, &key->N, &key->dQ, &key->dP, &key->qP, &key->p, &key->q, NULL);
+}
 
 /**
   Init an RSA key

+ 14 - 0
tests/rsa_test.c

@@ -9,6 +9,12 @@
 #include <tomcrypt_test.h>
 
 #if defined(LTC_MRSA)
+#if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
+#include <malloc.h>
+#define dbg_malloc_stats() do{ malloc_stats(); }while(0)
+#else
+#define dbg_malloc_stats() do{ }while(0)
+#endif
 
 /* These are test keys [see file test.key] that I use to test my import/export against */
 static const unsigned char openssl_private_rsa[] = {
@@ -512,6 +518,14 @@ print_hex("q", tmp, len);
    DO(rsa_export(tmp, &len2, PK_PUBLIC, &key));
    DO(rsa_import(tmp, len2, &pubKey));
 
+   dbg_malloc_stats();
+   rsa_shrink_key(&key);
+   dbg_malloc_stats();
+   rsa_shrink_key(&pubKey);
+   dbg_malloc_stats();
+   rsa_shrink_key(&privKey);
+   dbg_malloc_stats();
+
    /* verify with original */
    DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat, &key));
    /* change a byte */