Rafael J. Wysocki wrote:
Hm, as far as I remember, key_data is not just plain key and it can be
greater than 512 bytes.   And that would explain one bug report related to
the encryption with RSA.

(struct encrypted_key).data contains the encrypted pair (k, i). The session key (k) is 16 bytes and the initialization vector (i) is 8 bytes. The result can't be greater than the 512 bytes long RSA modulus.

Frankly, I have to check the code, but that will need to wait for a couple of
days.

Now, I think we can fix all that by using two pages for the header, but it
would complicate things a bit (not too much, but still).


BTW, I played with shrinking the header even more. I realized that we don't really need all the RSA components (n, e, d, p, q, u) for decryption. Only the modulus (n) and the private exponent (d) are absolutely necessary. It is nice to have the public exponent (e) too, for RSA blinding (anyway, libgcrypt always generates 65537 for (e), unless told otherwise).

You can take a look at the attached patch, which shrinks struct swsusp_info to 2028 bytes on i386. This is achieved by only saving the components (n, e, d). I am _not_ proposing to merge this one, because it requires a slightly modified libgcrypt to work. Original libgcrypt insists on knowing all the six components, even though it doesn't really need them. I consider that a bug in libgcrypt.

Michal

Index: encrypt.c
===================================================================
RCS file: /cvsroot/suspend/suspend/encrypt.c,v
retrieving revision 1.8
diff -u -p -r1.8 encrypt.c
--- encrypt.c   14 Sep 2006 14:18:58 -0000      1.8
+++ encrypt.c   20 Jan 2007 01:29:04 -0000
@@ -88,5 +88,20 @@ void get_random_salt(unsigned char *salt
                close(fd);
        }
 }
+
+int find_RSA_field(struct RSA_data *rsa, char field, unsigned char **pdata)
+{
+       int i;
+       unsigned char *data;
+       data = rsa->data;
+       for (i=0; i<RSA_FIELDS; i++) {
+               if (field == rsa->field[i][0]) {
+                       *pdata = data;
+                       return i;
+               }
+               data += rsa->size[i];
+       }
+       return -1;
+}
 #endif
 
Index: encrypt.h
===================================================================
RCS file: /cvsroot/suspend/suspend/encrypt.h,v
retrieving revision 1.6
diff -u -p -r1.6 encrypt.h
--- encrypt.h   11 Dec 2006 20:42:46 -0000      1.6
+++ encrypt.h   20 Jan 2007 01:29:04 -0000
@@ -28,10 +28,12 @@
 #define PK_KEY_SIZE    16
 #define PK_CIPHER_BLOCK        16
 /* Auxiliary constants */
-#define RSA_DATA_SIZE  3072
-#define KEY_DATA_SIZE  1000
+#define RSA_MAX_KEY_LEN        512
+#define RSA_PUB_EXP_LEN        16
+#define KEY_DATA_SIZE  512
 #define RSA_FIELDS     6
 #define RSA_FIELDS_PUB 2
+#define RSA_DATA_SIZE  (RSA_FIELDS*RSA_MAX_KEY_LEN)
 #define KEY_TEST_SIZE  8
 #define KEY_TEST_DATA  (unsigned char *)"12345678"
 
@@ -42,6 +44,19 @@ struct RSA_data {
        unsigned char   data[RSA_DATA_SIZE];
 };
 
+struct RSA_decrypt_key {
+       /* public part */
+       unsigned short  key_len;
+       unsigned char   modulus[RSA_MAX_KEY_LEN];
+       /* public exponent is not strictly necessary for decryption,
+        * but it's useful for blinding */
+       unsigned short  pub_exp_len;
+       unsigned char   pub_exponent[RSA_PUB_EXP_LEN];
+       /* secret part */
+       unsigned short  exp_len;
+       unsigned char   exponent[RSA_MAX_KEY_LEN];
+};
+
 struct encrypted_key {
        unsigned short  size;
        unsigned char   data[KEY_DATA_SIZE];
@@ -57,6 +72,7 @@ struct key_data {
 void read_password(char *pass_buf, int vrfy);
 void encrypt_init(unsigned char *, unsigned char *, char *);
 void get_random_salt(unsigned char *salt, size_t size);
+int find_RSA_field(struct RSA_data *, char field, unsigned char **);
 
 #define KEY_FILE       ""
 #endif
Index: resume.c
===================================================================
RCS file: /cvsroot/suspend/suspend/resume.c,v
retrieving revision 1.37
diff -u -p -r1.37 resume.c
--- resume.c    3 Dec 2006 11:29:59 -0000       1.37
+++ resume.c    20 Jan 2007 01:29:05 -0000
@@ -393,14 +393,14 @@ static int decrypt_key(struct swsusp_inf
        gcry_ac_data_t rsa_data_set, key_set;
        gcry_ac_key_t rsa_priv;
        gcry_mpi_t mpi;
-       unsigned char *buf, *out, *key_buf, *ivec_buf;
+       unsigned char *out, *key_buf, *ivec_buf;
        char *pass_buf;
        struct md5_ctx ctx;
-       struct RSA_data *rsa;
+       struct RSA_decrypt_key *rsa_key;
        gcry_cipher_hd_t sym_hd;
-       int j, ret = 0;
+       int ret = 0;
 
-       rsa = &header->rsa;
+       rsa_key = &header->secret_key;
 
        ret = gcry_ac_open(&rsa_hd, GCRY_AC_RSA, 0);
        if (ret)
@@ -437,7 +437,7 @@ static int decrypt_key(struct swsusp_inf
                if (ret)
                        break;
 
-               ret = memcmp(out, rsa->key_test, KEY_TEST_SIZE);
+               ret = memcmp(out, header->key_test, KEY_TEST_SIZE);
 
                if (ret)
                        printf("resume: Wrong passphrase, try again.\n");
@@ -463,27 +463,31 @@ static int decrypt_key(struct swsusp_inf
                goto Free_rsa;
        }
 
-       buf = rsa->data;
-       for (j = 0; j < RSA_FIELDS; j++) {
-               size_t s = rsa->size[j];
-
-               /* We need to decrypt some components */
-               if (j >= RSA_FIELDS_PUB) {
-                       /* We use the in-place decryption */
-                       ret = gcry_cipher_decrypt(sym_hd, buf, s, NULL, 0);
-                       if (ret)
-                               break;
-               }
-
-               gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, buf, s, NULL);
+       gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, &rsa_key->modulus,
+                       rsa_key->key_len, NULL);
+       ret = gcry_ac_data_set(rsa_data_set, GCRY_AC_FLAG_COPY,
+                       "n", mpi);
+       gcry_mpi_release(mpi);
+       
+       if (!ret) {
+               gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, &rsa_key->pub_exponent,
+                               rsa_key->pub_exp_len, NULL);
                ret = gcry_ac_data_set(rsa_data_set, GCRY_AC_FLAG_COPY,
-                                       rsa->field[j], mpi);
+                               "e", mpi);
                gcry_mpi_release(mpi);
-               if (ret)
-                       break;
+       }
 
-               buf += s;
+       if (!ret)
+               ret = gcry_cipher_decrypt(sym_hd, &rsa_key->exponent,
+                       rsa_key->exp_len, NULL, 0);
+       if (!ret) {
+               gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, &rsa_key->exponent,
+                               rsa_key->exp_len, NULL);
+               ret = gcry_ac_data_set(rsa_data_set, GCRY_AC_FLAG_COPY,
+                               "d", mpi);
+               gcry_mpi_release(mpi);
        }
+
        if (!ret)
                ret = gcry_ac_key_init(&rsa_priv, rsa_hd,
                                        GCRY_AC_KEY_SECRET, rsa_data_set);
@@ -491,8 +495,8 @@ static int decrypt_key(struct swsusp_inf
        if (!ret) {
                ret = gcry_ac_data_new(&key_set);
                if (!ret) {
-                       gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, header->key.data,
-                                       header->key.size, NULL);
+                       gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, 
header->session_key.data,
+                                       header->session_key.size, NULL);
                        ret = gcry_ac_data_set(key_set, GCRY_AC_FLAG_COPY,
                                                "a", mpi);
                        if (!ret) {
@@ -513,8 +517,8 @@ static int decrypt_key(struct swsusp_inf
                                        ret = -ENODATA;
                                }
                                gcry_free(res);
+                               gcry_mpi_release(mpi);
                        }
-                       gcry_mpi_release(mpi);
                        gcry_ac_data_destroy(key_set);
                }
                gcry_ac_key_destroy(rsa_priv);
Index: suspend.c
===================================================================
RCS file: /cvsroot/suspend/suspend/suspend.c,v
retrieving revision 1.66
diff -u -p -r1.66 suspend.c
--- suspend.c   10 Jan 2007 14:16:45 -0000      1.66
+++ suspend.c   20 Jan 2007 01:29:06 -0000
@@ -593,6 +593,8 @@ int write_image(int snapshot_fd, int res
 #ifdef CONFIG_ENCRYPT
                if (encrypt) {
                        if (use_RSA) {
+                               unsigned char *data;
+                               int index;
                                error = gcry_cipher_setkey(cipher_handle,
                                                key_data->key, KEY_SIZE);
                                if (error)
@@ -606,10 +608,29 @@ int write_image(int snapshot_fd, int res
 
                                header->image_flags |= IMAGE_ENCRYPTED |
                                                        IMAGE_USE_RSA;
-                               memcpy(&header->rsa, &key_data->rsa,
-                                               sizeof(struct RSA_data));
-                               memcpy(&header->key, &key_data->encrypted_key,
-                                               sizeof(struct encrypted_key));
+                               index = find_RSA_field(&key_data->rsa, 'n', 
&data);
+                               if (index<0)
+                                       goto No_RSA;
+                               header->secret_key.key_len = 
key_data->rsa.size[index];
+                               memcpy(&header->secret_key.modulus, data,
+                                               header->secret_key.key_len);
+                               
+                               index = find_RSA_field(&key_data->rsa, 'e', 
&data);
+                               if (index<0)
+                                       goto No_RSA;
+                               header->secret_key.pub_exp_len = 
key_data->rsa.size[index];
+                               memcpy(&header->secret_key.pub_exponent, data,
+                                               header->secret_key.pub_exp_len);
+
+                               index = find_RSA_field(&key_data->rsa, 'd', 
&data);
+                               if (index<0)
+                                       goto No_RSA;
+                               header->secret_key.exp_len = 
key_data->rsa.size[index];
+                               memcpy(&header->secret_key.exponent, data,
+                                               header->secret_key.exp_len);
+
+                               memcpy(&header->key_test, 
&key_data->rsa.key_test, sizeof(header->key_test));
+                               header->session_key = key_data->encrypted_key;
                        } else {
                                int j;
 
@@ -1107,11 +1128,13 @@ static void generate_key(void)
                        gcry_ac_data_get_index(key_set, GCRY_AC_FLAG_COPY, 0,
                                                (const char **)&str, &mpi);
                        gcry_free(str);
-                       gcry_mpi_print(GCRYMPI_FMT_USG, key->data,
+                       ret = gcry_mpi_print(GCRYMPI_FMT_USG, key->data,
                                        KEY_DATA_SIZE, &s, mpi);
                        gcry_mpi_release(mpi);
-                       key->size = s;
-                       use_RSA = 'y';
+                       if (!ret) {
+                               key->size = s;
+                               use_RSA = 'y';
+                       }
                }
 Close_urandom:
                close(rnd_fd);
Index: swsusp.h
===================================================================
RCS file: /cvsroot/suspend/suspend/swsusp.h,v
retrieving revision 1.33
diff -u -p -r1.33 swsusp.h
--- swsusp.h    7 Nov 2006 10:42:49 -0000       1.33
+++ swsusp.h    20 Jan 2007 01:29:06 -0000
@@ -72,8 +72,9 @@ struct swsusp_info {
        unsigned char           checksum[16];
 #ifdef CONFIG_ENCRYPT
        unsigned char           salt[CIPHER_BLOCK];
-       struct RSA_data rsa;
-       struct encrypted_key    key;
+       struct RSA_decrypt_key  secret_key;
+       unsigned char           key_test[KEY_TEST_SIZE];
+       struct encrypted_key    session_key;
 #endif
        double                  writeout_time;
 };
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Suspend-devel mailing list
Suspend-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/suspend-devel

Reply via email to