Hi,
The appended patch makes s2disk/s2both and resume use libgcrypt instead
of openssl. It also replaces Blowfish with AES (128bit).
Unfortunately it's huge, but seems to work. I've tested it on two x86_64
machines with 1024- and 2048-bit RSA keys. I'd be grateful if someone
could test it on i386.
NOTE: libgcrypt requires /dev/random to be present in the resume
initrd (I've added /dev/urandom too, for completness), so please take
this into consideration. Of course the RSA keys generated without the
patch won't work with the patched utilities.
The libgcrypt's AES seems to be significantly slower than the openssl's
Blowfish, but well. Also IMHO libgcrypt is less convenient than openssl
and the documentation sucks. Still it's GPLed and works on SUSE 10.1
(for me).
Greetings,
Rafael
--
Makefile | 9 +
encrypt.c | 12 +-
encrypt.h | 23 ++--
keygen.c | 177 +++++++++++++++++++++++++-----------
resume.c | 194 ++++++++++++++++++++++++++++++----------
scripts/create-resume-initrd.sh | 2
suspend.c | 187 ++++++++++++++++++++++++++------------
swsusp.h | 6 -
8 files changed, 432 insertions(+), 178 deletions(-)
Index: suspend/encrypt.h
===================================================================
--- suspend.orig/encrypt.h 2006-07-19 17:23:54.000000000 +0200
+++ suspend/encrypt.h 2006-07-19 17:24:17.000000000 +0200
@@ -11,29 +11,29 @@
*/
#ifdef CONFIG_ENCRYPT
-#include <openssl/blowfish.h>
-#include <openssl/rsa.h>
+#include <gcrypt.h>
#define PASS_SIZE 128
#define KEY_SIZE 16
-#define IVEC_SIZE 8
-#define RSA_DATA_SIZE 1200
-#define KEY_DATA_SIZE 800
+#define CIPHER_BLOCK 16
+#define RSA_DATA_SIZE 2000
+#define KEY_DATA_SIZE 1000
+#define RSA_FIELDS 6
+#define RSA_FIELDS_PUB 2
#define KEY_TEST_SIZE 8
#define KEY_TEST_DATA (unsigned char *)"12345678"
struct RSA_data {
- unsigned short n_size;
- unsigned short e_size;
- unsigned short d_size;
+ char field[RSA_FIELDS][2];
+ unsigned short size[RSA_FIELDS];
unsigned char key_test[KEY_TEST_SIZE];
unsigned char data[RSA_DATA_SIZE];
};
struct key_data {
unsigned char key[KEY_SIZE];
- unsigned char ivec[IVEC_SIZE];
- struct RSA_data rsa_data;
+ unsigned char ivec[CIPHER_BLOCK];
+ struct RSA_data rsa;
};
struct encrypted_key {
@@ -42,8 +42,7 @@ struct encrypted_key {
};
void read_password(char *pass_buf, int vrfy);
-void encrypt_init(BF_KEY *key, unsigned char *ivec, int *num,
- char *pass_buf, void *key_buf, int vrfy);
+void encrypt_init(unsigned char *, unsigned char *, char *, int);
void get_random_salt(char *salt, size_t size);
#define KEY_FILE "/etc/suspend.key"
Index: suspend/keygen.c
===================================================================
--- suspend.orig/keygen.c 2006-07-19 17:23:54.000000000 +0200
+++ suspend/keygen.c 2006-07-19 17:24:17.000000000 +0200
@@ -14,8 +14,6 @@
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
-#include <openssl/blowfish.h>
-#include <openssl/rsa.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -26,25 +24,38 @@
#define MIN_KEY_BITS 1024
#define MAX_KEY_BITS 4096
-#define MAX_OUT_SIZE 1200
+#define MAX_OUT_SIZE (sizeof(struct RSA_data))
#define MAX_STR_LEN 256
-#define IVEC_SIZE 8
#define DEFAULT_FILE "suspend.key"
static char in_buffer[MAX_STR_LEN];
static char pass_buf[MAX_STR_LEN];
-static struct RSA_data rsa_data;
+static struct RSA_data rsa;
static unsigned char encrypt_buffer[RSA_DATA_SIZE];
int main(int argc, char *argv[])
{
- RSA *rsa;
+ gcry_ac_data_t rsa_data_set;
+ gcry_ac_handle_t rsa_hd;
+ gcry_ac_key_t rsa_priv;
+ gcry_ac_key_pair_t rsa_key_pair;
+ gcry_mpi_t mpi;
+ size_t offset;
int len = MIN_KEY_BITS, ret = EXIT_SUCCESS;
- unsigned char *buf;
struct termios termios;
char *vrfy_buf;
+ struct md5_ctx ctx;
+ unsigned char key_buf[KEY_SIZE];
+ gcry_cipher_hd_t aes_hd;
+ unsigned char ivec[CIPHER_BLOCK];
unsigned short size;
- int fd;
+ int j, fd;
+
+ printf("libgcrypt version: %s\n", gcry_check_version(NULL));
+ gcry_control(GCRYCTL_INIT_SECMEM, 4096, 0);
+ ret = gcry_ac_open(&rsa_hd, GCRY_AC_RSA, 0);
+ if (ret)
+ return ret;
do {
printf("Key bits (between %d and %d inclusive) [%d]: ",
@@ -55,18 +66,51 @@ int main(int argc, char *argv[])
} while (len < MIN_KEY_BITS || len > MAX_KEY_BITS);
Retry:
- printf("Generating %d-bit RSA keys.\n", len);
- rsa = RSA_generate_key(len, RSA_F4, NULL, NULL);
- if (!rsa) {
- fprintf(stderr, "Key generation failed.\n");
+ printf("Generating %d-bit RSA keys. Please wait.\n", len);
+ ret = gcry_ac_key_pair_generate(rsa_hd, len, NULL, &rsa_key_pair, NULL);
+ if (ret) {
+ fprintf(stderr, "Key generation failed: %s\n",
gcry_strerror(ret));
ret = EXIT_FAILURE;
- goto Free_RSA;
+ goto Close_RSA;
}
- if (RSA_check_key(rsa) <= 0) {
+ printf("Testing the private key. Please wait.\n");
+ rsa_priv = gcry_ac_key_pair_extract(rsa_key_pair, GCRY_AC_KEY_SECRET);
+ ret = gcry_ac_key_test(rsa_hd, rsa_priv);
+ if (ret) {
printf("RSA key test failed. Retrying.\n");
goto Retry;
}
+ rsa_data_set = gcry_ac_key_data_get(rsa_priv);
+ if (gcry_ac_data_length(rsa_data_set) != RSA_FIELDS) {
+ fprintf(stderr, "Wrong number of key fields\n");
+ ret = -EINVAL;
+ goto Free_RSA;
+ }
+
+ /* Convert the key length into bytes */
+ size = (len + 7) >> 3;
+ /* Copy the public key components to struct RSA_data */
+ offset = 0;
+ for (j = 0; j < RSA_FIELDS_PUB; j++) {
+ char *str;
+ size_t s;
+
+ if (offset + size >= RSA_DATA_SIZE)
+ goto Free_RSA;
+
+ gcry_ac_data_get_index(rsa_data_set, GCRY_AC_FLAG_COPY, j,
+ (const char **)&str, &mpi);
+ gcry_mpi_print(GCRYMPI_FMT_USG, rsa.data + offset,
+ size, &s, mpi);
+ rsa.field[j][0] = str[0];
+ rsa.field[j][1] = '\0';
+ rsa.size[j] = s;
+ offset += s;
+ gcry_mpi_release(mpi);
+ gcry_free(str);
+ }
+
tcgetattr(0, &termios);
termios.c_lflag &= ~ECHO;
termios.c_lflag |= ICANON | ECHONL;
@@ -88,42 +132,70 @@ Retry:
termios.c_lflag |= ECHO;
tcsetattr(0, TCSANOW, &termios);
- buf = rsa_data.data;
- size = BN_bn2mpi(rsa->n, NULL);
- if (size <= RSA_DATA_SIZE) {
- rsa_data.n_size = BN_bn2mpi(rsa->n, buf);
- buf += rsa_data.n_size;
- }
- size += BN_bn2mpi(rsa->e, NULL);
- if (size <= RSA_DATA_SIZE) {
- rsa_data.e_size = BN_bn2mpi(rsa->e, buf);
- buf += rsa_data.e_size;
- }
- size += BN_bn2mpi(rsa->d, NULL);
- if (size <= RSA_DATA_SIZE) {
- struct md5_ctx ctx;
- unsigned char key_buf[KEY_SIZE];
- BF_KEY key;
- unsigned char ivec[IVEC_SIZE];
- int n = 0;
-
- memset(ivec, 0, IVEC_SIZE);
- strncpy((char *)ivec, pass_buf, IVEC_SIZE);
- md5_init_ctx(&ctx);
- md5_process_bytes(pass_buf, strlen(pass_buf), &ctx);
- md5_finish_ctx(&ctx, key_buf);
- BF_set_key(&key, KEY_SIZE, key_buf);
- BF_ecb_encrypt(KEY_TEST_DATA, rsa_data.key_test, &key,
BF_ENCRYPT);
- rsa_data.d_size = BN_bn2mpi(rsa->d, encrypt_buffer);
- BF_cfb64_encrypt(encrypt_buffer, buf, rsa_data.d_size,
- &key, ivec, &n, BF_ENCRYPT);
- }
- if (size > RSA_DATA_SIZE) {
- fprintf(stderr, "Buffer is too small. Giving up.\n");
- ret = EXIT_FAILURE;
+ memset(ivec, 0, CIPHER_BLOCK);
+ strncpy((char *)ivec, pass_buf, CIPHER_BLOCK);
+ md5_init_ctx(&ctx);
+ md5_process_bytes(pass_buf, strlen(pass_buf), &ctx);
+ md5_finish_ctx(&ctx, key_buf);
+
+ /* First, we encrypt the key test */
+ ret = gcry_cipher_open(&aes_hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB,
+ GCRY_CIPHER_SECURE);
+ if (ret)
goto Free_RSA;
+
+ ret = gcry_cipher_setkey(aes_hd, key_buf, KEY_SIZE);
+ if (!ret)
+ ret = gcry_cipher_setiv(aes_hd, ivec, CIPHER_BLOCK);
+
+ if (!ret)
+ ret = gcry_cipher_encrypt(aes_hd, rsa.key_test, KEY_TEST_SIZE,
+ KEY_TEST_DATA, KEY_TEST_SIZE);
+
+ gcry_cipher_close(aes_hd);
+ if (ret)
+ goto Free_RSA;
+
+ /* Now, we can encrypt the private RSA key */
+ ret = gcry_cipher_open(&aes_hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB,
+ GCRY_CIPHER_SECURE);
+ if (ret)
+ goto Free_RSA;
+
+ ret = gcry_cipher_setkey(aes_hd, key_buf, KEY_SIZE);
+ if (!ret)
+ ret = gcry_cipher_setiv(aes_hd, ivec, CIPHER_BLOCK);
+
+ if (ret)
+ goto Free_AES;
+
+ /* Copy the private key components (encrypted) to struct RSA_data */
+ for (j = RSA_FIELDS_PUB; j < RSA_FIELDS; j++) {
+ char *str;
+ size_t s;
+
+ if (offset + size >= RSA_DATA_SIZE)
+ goto Free_AES;
+
+ gcry_ac_data_get_index(rsa_data_set, GCRY_AC_FLAG_COPY, j,
+ (const char **)&str, &mpi);
+ gcry_mpi_print(GCRYMPI_FMT_USG, rsa.data + offset,
+ size, &s, mpi);
+
+ /* We encrypt the data in place */
+ ret = gcry_cipher_encrypt(aes_hd, rsa.data + offset, s, NULL,
0);
+ if (ret)
+ goto Free_AES;
+
+ rsa.field[j][0] = str[0];
+ rsa.field[j][1] = '\0';
+ rsa.size[j] = s;
+ offset += s;
+ gcry_mpi_release(mpi);
+ gcry_free(str);
}
- size += 3 * sizeof(short) + KEY_TEST_SIZE;
+
+ size = offset + sizeof(struct RSA_data) - RSA_DATA_SIZE;
printf("File name [%s]: ", DEFAULT_FILE);
fgets(in_buffer, MAX_STR_LEN, stdin);
@@ -133,15 +205,18 @@ Retry:
in_buffer[strlen(in_buffer)-1] = '\0';
fd = open(in_buffer, O_RDWR | O_CREAT | O_TRUNC, 00600);
if (fd >= 0) {
- write(fd, &rsa_data, size);
+ write(fd, &rsa, size);
close(fd);
} else {
fprintf(stderr, "Could not open the file %s\n", in_buffer);
ret = EXIT_FAILURE;
}
-
+Free_AES:
+ gcry_cipher_close(aes_hd);
Free_RSA:
- RSA_free(rsa);
+ gcry_ac_data_destroy(rsa_data_set);
+Close_RSA:
+ gcry_ac_close(rsa_hd);
return ret;
}
Index: suspend/suspend.c
===================================================================
--- suspend.orig/suspend.c 2006-07-19 17:23:54.000000000 +0200
+++ suspend/suspend.c 2006-07-19 17:24:17.000000000 +0200
@@ -138,6 +138,7 @@ static unsigned int buffer_size;
static void *mem_pool;
#ifdef CONFIG_ENCRYPT
struct key_data *key_data;
+gcry_cipher_hd_t cipher_handle;
#endif
static inline loff_t check_free_swap(int dev)
@@ -217,9 +218,6 @@ struct swap_map_handle {
struct md5_ctx ctx;
#ifdef CONFIG_ENCRYPT
unsigned char *encrypt_buffer;
- BF_KEY key;
- unsigned char ivec[IVEC_SIZE];
- int num;
#endif
};
@@ -301,17 +299,19 @@ static int try_get_more_swap(struct swap
static int flush_buffer(struct swap_map_handle *handle)
{
void *src = handle->write_buffer;
- int error;
+ int error = 0;
#ifdef CONFIG_ENCRYPT
if (encrypt) {
- BF_cfb64_encrypt(src, handle->encrypt_buffer,
handle->cur_area.size,
- &handle->key, handle->ivec, &handle->num, BF_ENCRYPT);
+ error = gcry_cipher_encrypt(cipher_handle,
+ handle->encrypt_buffer, handle->cur_area.size,
+ src, handle->cur_area.size);
src = handle->encrypt_buffer;
}
#endif
- error = write_area(handle->fd, src, handle->cur_area.offset,
- handle->cur_area.size);
+ if (!error)
+ error = write_area(handle->fd, src, handle->cur_area.offset,
+ handle->cur_area.size);
if (error)
return error;
handle->areas[handle->k].offset = handle->cur_area.offset;
@@ -521,31 +521,51 @@ int write_image(int snapshot_fd, int res
#ifdef CONFIG_ENCRYPT
if (encrypt) {
if (use_RSA) {
- BF_set_key(&handle.key, KEY_SIZE,
key_data->key);
- memcpy(handle.ivec, key_data->ivec, IVEC_SIZE);
- handle.num = 0;
- header->image_flags |= IMAGE_ENCRYPTED |
IMAGE_USE_RSA;
- memcpy(&header->rsa_data, &key_data->rsa_data,
- sizeof(struct RSA_data));
- memcpy(&header->key_data, key_data + 1,
- sizeof(struct encrypted_key));
+ error = gcry_cipher_setkey(cipher_handle,
+ key_data->key, KEY_SIZE);
+ if (!error)
+ error = gcry_cipher_setiv(cipher_handle,
+ key_data->ivec, CIPHER_BLOCK);
+
+ if (!error) {
+ struct encrypted_key *key;
+
+ header->image_flags |= IMAGE_ENCRYPTED |
+ IMAGE_USE_RSA;
+ memcpy(&header->rsa, &key_data->rsa,
+ sizeof(struct RSA_data));
+ key = (struct encrypted_key *)(key_data
+ 1);
+ memcpy(&header->key, key,
+ sizeof(struct encrypted_key));
+ }
} else {
int j;
chvt(vt_no);
- encrypt_init(&handle.key, handle.ivec,
&handle.num,
- handle.write_buffer,
- handle.encrypt_buffer, 1);
+ encrypt_init(key_data->key, key_data->ivec,
+ handle.write_buffer, 1);
splash.switch_to();
splash.progress(20);
- get_random_salt(header->salt, IVEC_SIZE);
- for (j = 0; j < IVEC_SIZE; j++)
- handle.ivec[j] ^= header->salt[j];
- header->image_flags |= IMAGE_ENCRYPTED;
+ get_random_salt(header->salt, CIPHER_BLOCK);
+ for (j = 0; j < CIPHER_BLOCK; j++)
+ key_data->ivec[j] ^= header->salt[j];
+
+ error = gcry_cipher_setkey(cipher_handle,
+ key_data->key, KEY_SIZE);
+ if (!error)
+ error = gcry_cipher_setiv(cipher_handle,
+ key_data->ivec, CIPHER_BLOCK);
+
+ if (!error)
+ header->image_flags |= IMAGE_ENCRYPTED;
}
+ if (error)
+ printf("suspend: libgcrypt error: %s\n",
+ gcry_strerror(error));
}
#endif
- error = save_image(&handle, header->pages - 1);
+ if (!error)
+ error = save_image(&handle, header->pages - 1);
}
if (!error) {
error = flush_swap_writer(&handle);
@@ -615,7 +635,7 @@ static int reset_signature(int fd)
}
#endif
-static void shutdown(void)
+static void suspend_shutdown(void)
{
power_off();
/* Signature is on disk, it is very dangerous to continue now.
@@ -673,14 +693,14 @@ int suspend_system(int snapshot_fd, int
splash.progress(100);
#ifdef CONFIG_BOTH
if (!s2ram) {
- shutdown();
+ suspend_shutdown();
} else {
/* If we die (and allow system to
continue) between
* now and reset_signature(), very bad
things will
* happen. */
error = suspend_to_ram(snapshot_fd);
if (error)
- shutdown();
+ suspend_shutdown();
reset_signature(resume_fd);
free_swap_pages(snapshot_fd);
free_snapshot(snapshot_fd);
@@ -688,7 +708,7 @@ int suspend_system(int snapshot_fd, int
goto Unfreeze;
}
#else
- shutdown();
+ suspend_shutdown();
#endif
} else {
free_swap_pages(snapshot_fd);
@@ -918,10 +938,14 @@ static inline void close_swappiness(void
#ifdef CONFIG_ENCRYPT
static void generate_key(void)
{
- RSA *rsa;
- int fd, rnd_fd;
- struct RSA_data *rsa_data;
+ gcry_ac_handle_t rsa_hd;
+ gcry_ac_data_t rsa_data_set, key_set;
+ gcry_ac_key_t rsa_pub;
+ gcry_mpi_t mpi;
+ int ret, fd, rnd_fd;
+ struct RSA_data *rsa;
unsigned char *buf;
+ int j;
if (!key_data)
return;
@@ -930,41 +954,79 @@ static void generate_key(void)
if (fd < 0)
return;
- rsa = RSA_new();
- if (!rsa)
+ rsa = &key_data->rsa;
+ if (read(fd, rsa, sizeof(struct RSA_data)) <= 0)
goto Close;
- rsa_data = &key_data->rsa_data;
- if (read(fd, rsa_data, sizeof(struct RSA_data)) <= 0)
- goto Free_rsa;
+ ret = gcry_ac_open(&rsa_hd, GCRY_AC_RSA, 0);
+ if (ret)
+ goto Close;
- buf = rsa_data->data;
- rsa->n = BN_mpi2bn(buf, rsa_data->n_size, NULL);
- buf += rsa_data->n_size;
- rsa->e = BN_mpi2bn(buf, rsa_data->e_size, NULL);
- if (!rsa->n || !rsa->e)
+ buf = rsa->data;
+ ret = gcry_ac_data_new(&rsa_data_set);
+ if (ret)
goto Free_rsa;
- rnd_fd = open("/dev/urandom", O_RDONLY);
- if (rnd_fd > 0) {
- unsigned short size = KEY_SIZE + IVEC_SIZE;
-
- if (read(rnd_fd, key_data->key, size) == size) {
- struct encrypted_key *enc_key;
- int ret;
-
- enc_key = (struct encrypted_key *)(key_data + 1);
- ret = RSA_public_encrypt(size, key_data->key,
- enc_key->data, rsa, RSA_PKCS1_PADDING);
- if (ret > 0) {
- enc_key->size = ret;
- use_RSA = 'y';
+ for (j = 0; j < RSA_FIELDS_PUB; j++) {
+ size_t s = rsa->size[j];
+
+ gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, buf, s, NULL);
+ ret = gcry_ac_data_set(rsa_data_set, GCRY_AC_FLAG_COPY,
+ rsa->field[j], mpi);
+ gcry_mpi_release(mpi);
+ if (ret)
+ break;
+
+ buf += s;
+ }
+ if (!ret)
+ ret = gcry_ac_key_init(&rsa_pub, rsa_hd, GCRY_AC_KEY_PUBLIC,
+ rsa_data_set);
+
+ if (!ret) {
+ ret = gcry_ac_data_new(&key_set);
+ if (!ret) {
+ rnd_fd = open("/dev/urandom", O_RDONLY);
+ if (rnd_fd > 0) {
+ unsigned short size = KEY_SIZE + CIPHER_BLOCK;
+
+ if (read(rnd_fd, key_data->key, size) == size) {
+ gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG,
+ key_data->key, size, NULL);
+ ret = gcry_ac_data_encrypt(rsa_hd, 0,
+ rsa_pub, mpi, &key_set);
+ gcry_mpi_release(mpi);
+ if (!ret) {
+ struct encrypted_key *key;
+ char *str;
+ size_t s;
+
+ key = (struct encrypted_key *)
+ (key_data + 1);
+ 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,
KEY_DATA_SIZE,
+ &s, mpi);
+ gcry_mpi_release(mpi);
+ key->size = s;
+ use_RSA = 'y';
+ }
+ }
+ close(rnd_fd);
}
+ gcry_ac_data_destroy(key_set);
}
- close(rnd_fd);
+ gcry_ac_key_destroy(rsa_pub);
+ } else {
+ gcry_ac_data_destroy(rsa_data_set);
}
+
Free_rsa:
- RSA_free(rsa);
+ gcry_ac_close(rsa_hd);
Close:
close(fd);
}
@@ -1026,6 +1088,13 @@ int main(int argc, char *argv[])
}
#ifdef CONFIG_ENCRYPT
if (encrypt) {
+ printf("suspend: libgcrypt version: %s\n",
+ gcry_check_version(NULL));
+ gcry_control(GCRYCTL_INIT_SECMEM, page_size, 0);
+ encrypt = !gcry_cipher_open(&cipher_handle, GCRY_CIPHER_AES,
+ GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE);
+ }
+ if (encrypt) {
mem_size -= buffer_size;
key_data = (struct key_data *)((char *)mem_pool + mem_size);
generate_key();
@@ -1138,6 +1207,10 @@ Close_snapshot_fd:
Close_resume_fd:
close(resume_fd);
+#ifdef CONFIG_ENCRYPT
+ if (encrypt)
+ gcry_cipher_close(cipher_handle);
+#endif
free(mem_pool);
return ret;
Index: suspend/swsusp.h
===================================================================
--- suspend.orig/swsusp.h 2006-07-19 17:23:54.000000000 +0200
+++ suspend/swsusp.h 2006-07-19 17:24:17.000000000 +0200
@@ -58,9 +58,9 @@ struct swsusp_info {
uint32_t image_flags;
unsigned char checksum[16];
#ifdef CONFIG_ENCRYPT
- char salt[IVEC_SIZE];
- struct RSA_data rsa_data;
- struct encrypted_key key_data;
+ char salt[CIPHER_BLOCK];
+ struct RSA_data rsa;
+ struct encrypted_key key;
#endif
};
Index: suspend/encrypt.c
===================================================================
--- suspend.orig/encrypt.c 2006-07-19 17:23:54.000000000 +0200
+++ suspend/encrypt.c 2006-07-19 17:24:17.000000000 +0200
@@ -59,21 +59,19 @@ void read_password(char *pass_buf, int v
* long
*/
-void encrypt_init(BF_KEY *key, unsigned char *ivec, int *num,
- char *pass_buf, void *key_buf, int vrfy)
+void
+encrypt_init(unsigned char *key, unsigned char *ivec, char *pass_buf, int vrfy)
{
struct md5_ctx ctx;
read_password(pass_buf, vrfy);
- memset(ivec, 0, IVEC_SIZE);
- strncpy((char *)ivec, pass_buf, IVEC_SIZE);
+ memset(ivec, 0, CIPHER_BLOCK);
+ strncpy((char *)ivec, pass_buf, CIPHER_BLOCK);
md5_init_ctx(&ctx);
md5_process_bytes(pass_buf, strlen(pass_buf), &ctx);
- md5_finish_ctx(&ctx, key_buf);
- BF_set_key(key, KEY_SIZE, key_buf);
- *num = 0;
+ md5_finish_ctx(&ctx, key);
}
void get_random_salt(char *salt, size_t size)
Index: suspend/resume.c
===================================================================
--- suspend.orig/resume.c 2006-07-19 17:23:54.000000000 +0200
+++ suspend/resume.c 2006-07-19 17:24:17.000000000 +0200
@@ -164,9 +164,7 @@ struct swap_map_handle {
struct md5_ctx ctx;
#ifdef CONFIG_ENCRYPT
char *decrypt_buffer;
- BF_KEY key;
- unsigned char ivec[IVEC_SIZE];
- int num;
+ gcry_cipher_hd_t cipher_handle;
#endif
};
@@ -220,9 +218,9 @@ static int fill_buffer(struct swap_map_h
handle->area_size);
#ifdef CONFIG_ENCRYPT
if (!error && decrypt)
- BF_cfb64_encrypt(dst, (unsigned char *)handle->read_buffer,
- handle->area_size, &handle->key, handle->ivec,
- &handle->num, BF_DECRYPT);
+ error = gcry_cipher_decrypt(handle->cipher_handle,
+ handle->read_buffer, handle->area_size,
+ dst, handle->area_size);
#endif
return error;
}
@@ -370,63 +368,145 @@ static inline void print_checksum(unsign
}
#ifdef CONFIG_ENCRYPT
-static int decrypt_key(struct swsusp_info *header, BF_KEY *key, unsigned char
*ivec,
- void *buffer)
+static int decrypt_key(struct swsusp_info *header, unsigned char *key,
+ unsigned char *ivec, void *buffer)
{
- RSA *rsa;
+ gcry_ac_handle_t rsa_hd;
+ 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;
char *pass_buf;
struct md5_ctx ctx;
- struct RSA_data *rsa_data;
- int n = 0, ret = 0;
+ struct RSA_data *rsa;
+ gcry_cipher_hd_t aes_hd;
+ int j, ret = 0;
- rsa = RSA_new();
- if (!rsa)
- return -ENOMEM;
+ rsa = &header->rsa;
+
+ ret = gcry_ac_open(&rsa_hd, GCRY_AC_RSA, 0);
+ if (ret)
+ return ret;
- rsa_data = &header->rsa_data;
- buf = rsa_data->data;
- rsa->n = BN_mpi2bn(buf, rsa_data->n_size, NULL);
- buf += rsa_data->n_size;
- rsa->e = BN_mpi2bn(buf, rsa_data->e_size, NULL);
- buf += rsa_data->e_size;
+ if (!ret)
+ ret = gcry_cipher_open(&aes_hd, GCRY_CIPHER_AES,
+ GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE);
+
+ if (ret)
+ goto Free_rsa;
pass_buf = buffer;
key_buf = (unsigned char *)pass_buf + PASS_SIZE;
+ out = key_buf + KEY_SIZE;
do {
read_password(pass_buf, 0);
- memset(ivec, 0, IVEC_SIZE);
- strncpy((char *)ivec, pass_buf, IVEC_SIZE);
+ memset(ivec, 0, CIPHER_BLOCK);
+ strncpy((char *)ivec, pass_buf, CIPHER_BLOCK);
md5_init_ctx(&ctx);
md5_process_bytes(pass_buf, strlen(pass_buf), &ctx);
md5_finish_ctx(&ctx, key_buf);
- BF_set_key(key, KEY_SIZE, key_buf);
- BF_ecb_encrypt(KEY_TEST_DATA, key_buf, key, BF_ENCRYPT);
- ret = memcmp(key_buf, rsa_data->key_test, KEY_TEST_SIZE);
+ ret = gcry_cipher_setkey(aes_hd, key_buf, KEY_SIZE);
+ if (!ret)
+ ret = gcry_cipher_setiv(aes_hd, ivec, CIPHER_BLOCK);
+
+ if (!ret)
+ ret = gcry_cipher_encrypt(aes_hd,
+ out, KEY_TEST_SIZE,
+ KEY_TEST_DATA, KEY_TEST_SIZE);
+
+ if (ret)
+ break;
+
+ ret = memcmp(out, rsa->key_test, KEY_TEST_SIZE);
+
if (ret)
printf("resume: Wrong passphrase, try again.\n");
} while (ret);
- out = key_buf + KEY_SIZE;
- BF_cfb64_encrypt(buf, out, rsa_data->d_size, key, ivec, &n, BF_DECRYPT);
- rsa->d = BN_mpi2bn(out, rsa_data->d_size, NULL);
- if (!rsa->n || !rsa->e || !rsa->d) {
- ret = -EFAULT;
+ gcry_cipher_close(aes_hd);
+ if (!ret)
+ ret = gcry_cipher_open(&aes_hd, GCRY_CIPHER_AES,
+ GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE);
+
+ if (ret)
+ goto Free_rsa;
+
+ ret = gcry_cipher_setkey(aes_hd, key_buf, KEY_SIZE);
+ if (!ret)
+ ret = gcry_cipher_setiv(aes_hd, ivec, CIPHER_BLOCK);
+
+ if (!ret)
+ ret = gcry_ac_data_new(&rsa_data_set);
+
+ if (ret) {
+ gcry_cipher_close(aes_hd);
goto Free_rsa;
}
- ret = RSA_private_decrypt(header->key_data.size, header->key_data.data,
- out, rsa, RSA_PKCS1_PADDING);
- if (ret != (int)(KEY_SIZE + IVEC_SIZE)) {
- ret = -ENODATA;
+ 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(aes_hd, buf, s, NULL, 0);
+ if (ret)
+ break;
+ }
+
+ gcry_mpi_scan(&mpi, GCRYMPI_FMT_USG, buf, s, NULL);
+ ret = gcry_ac_data_set(rsa_data_set, GCRY_AC_FLAG_COPY,
+ rsa->field[j], mpi);
+ gcry_mpi_release(mpi);
+ if (ret)
+ break;
+
+ buf += s;
+ }
+ if (!ret)
+ ret = gcry_ac_key_init(&rsa_priv, rsa_hd,
+ GCRY_AC_KEY_SECRET, rsa_data_set);
+
+ 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);
+ ret = gcry_ac_data_set(key_set, GCRY_AC_FLAG_COPY,
+ "a", mpi);
+ if (!ret) {
+ gcry_mpi_release(mpi);
+ ret = gcry_ac_data_decrypt(rsa_hd, 0, rsa_priv,
+ &mpi, key_set);
+ }
+ if (!ret) {
+ unsigned char *res;
+ size_t s;
+
+ gcry_mpi_aprint(GCRYMPI_FMT_USG, &res, &s, mpi);
+ if (s == KEY_SIZE + CIPHER_BLOCK) {
+ memcpy(key, res, KEY_SIZE);
+ memcpy(ivec, res + KEY_SIZE,
+ CIPHER_BLOCK);
+ } else {
+ ret = -ENODATA;
+ }
+ gcry_free(res);
+ }
+ gcry_mpi_release(mpi);
+ gcry_ac_data_destroy(key_set);
+ }
+ gcry_ac_key_destroy(rsa_priv);
} else {
- BF_set_key(key, KEY_SIZE, out);
- memcpy(ivec, out + KEY_SIZE, IVEC_SIZE);
- ret = 0;
+ gcry_ac_data_destroy(rsa_data_set);
}
+ gcry_cipher_close(aes_hd);
+
Free_rsa:
- RSA_free(rsa);
+ gcry_ac_close(rsa_hd);
+
return ret;
}
#endif
@@ -481,24 +561,41 @@ static int read_image(int dev, char *res
}
if (!error && (header->image_flags & IMAGE_ENCRYPTED)) {
#ifdef CONFIG_ENCRYPT
+ static unsigned char key[KEY_SIZE], ivec[CIPHER_BLOCK];
+
printf("resume: Encrypted image\n");
splash.to_verbose();
if (header->image_flags & IMAGE_USE_RSA) {
- handle.num = 0;
- error = decrypt_key(header, &handle.key,
- handle.ivec, buffer);
+ error = decrypt_key(header, key, ivec, buffer);
} else {
int j;
- encrypt_init(&handle.key, handle.ivec,
&handle.num,
- buffer, buffer + page_size, 0);
- for (j = 0; j < IVEC_SIZE; j++)
- handle.ivec[j] ^= header->salt[j];
+ encrypt_init(key, ivec, buffer, 0);
+ for (j = 0; j < CIPHER_BLOCK; j++)
+ ivec[j] ^= header->salt[j];
}
splash.to_silent();
splash.progress(15);
if (!error)
+ error = gcry_cipher_open(&handle.cipher_handle,
+ GCRY_CIPHER_AES, GCRY_CIPHER_MODE_CFB,
+ GCRY_CIPHER_SECURE);
+ if (!error) {
decrypt = 1;
+ error = gcry_cipher_setkey(handle.cipher_handle,
+ key, KEY_SIZE);
+ }
+ if (!error)
+ error = gcry_cipher_setiv(handle.cipher_handle,
+ ivec, CIPHER_BLOCK);
+
+ if (error) {
+ if (decrypt)
+ gcry_cipher_close(handle.cipher_handle);
+ decrypt = 0;
+ printf("resume: libgcrypt error: %s\n",
+ gcry_strerror(error));
+ }
#else
printf("resume: Encryption not supported\n");
error = -EINVAL;
@@ -563,6 +660,11 @@ static int read_image(int dev, char *res
}
fsync(fd);
close(fd);
+#ifdef CONFIG_ENCRYPT
+ if (decrypt)
+ gcry_cipher_close(handle.cipher_handle);
+#endif
+
if (!error) {
printf("resume: Image successfully loaded\n");
} else {
@@ -607,6 +709,8 @@ int main(int argc, char *argv[])
buffer_size = BUFFER_PAGES * page_size;
#ifdef CONFIG_ENCRYPT
+ printf("resume: libgcrypt version: %s\n", gcry_check_version(NULL));
+ gcry_control(GCRYCTL_INIT_SECMEM, page_size, 0);
mem_size = 3 * page_size + 2 * buffer_size;
#else
mem_size = 3 * page_size + buffer_size;
Index: suspend/Makefile
===================================================================
--- suspend.orig/Makefile 2006-07-19 17:23:54.000000000 +0200
+++ suspend/Makefile 2006-07-19 17:25:09.000000000 +0200
@@ -11,8 +11,11 @@ CC_FLAGS += -DCONFIG_COMPRESS
LD_FLAGS += -llzf
endif
ifdef CONFIG_ENCRYPT
+GCRYPT_CC_FLAGS := $(shell libgcrypt-config --cflags)
+GCRYPT_LD_FLAGS := $(shell libgcrypt-config --libs)
CC_FLAGS += -DCONFIG_ENCRYPT
-LD_FLAGS += -lcrypto
+CC_FLAGS += $(GCRYPT_CC_FLAGS)
+LD_FLAGS += $(GCRYPT_LD_FLAGS)
endif
SUSPEND_DIR=/usr/local/sbin
@@ -96,8 +99,8 @@ resume: md5.o encrypt.o config.o resume.
$(CC) -Wall $(CC_FLAGS) md5.o encrypt.o config.o vt.o resume.c
$(SPLASHOBJ) -static -o resume $(LD_FLAGS)
ifdef CONFIG_ENCRYPT
-suspend-keygen: md5.o encrypt.o keygen.c encrypt.h md5.h
- $(CC) -Wall -DHAVE_INTTYPES_H -DHAVE_STDINT_H -DCONFIG_ENCRYPT md5.o
keygen.c -o suspend-keygen -lcrypto
+suspend-keygen: md5.o keygen.c encrypt.h md5.h
+ $(CC) -Wall -DHAVE_INTTYPES_H -DHAVE_STDINT_H $(CC_FLAGS) md5.o
keygen.c -o suspend-keygen $(LD_FLAGS)
install-suspend: suspend suspend-keygen conf/$(CONFIGFILE)
if [ ! -c /dev/snapshot ]; then mknod /dev/snapshot c 10 231; fi
Index: suspend/scripts/create-resume-initrd.sh
===================================================================
--- suspend.orig/scripts/create-resume-initrd.sh 2006-07-19
17:23:54.000000000 +0200
+++ suspend/scripts/create-resume-initrd.sh 2006-07-19 17:24:17.000000000
+0200
@@ -43,6 +43,8 @@ if [ -f $RESUME -a -d $MOUNT_POINT -a -b
mkdir $MOUNT_POINT/dev
cp -r /dev/console $MOUNT_POINT/dev/
cp -r /dev/snapshot $MOUNT_POINT/dev/
+ cp -r /dev/random $MOUNT_POINT/dev/
+ cp -r /dev/urandom $MOUNT_POINT/dev/
cp -r $RESUME_DEVICE $MOUNT_POINT/dev/
mkdir $MOUNT_POINT/proc
mkdir $MOUNT_POINT/etc
-------------------------------------------------------------------------
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/suspend-devel