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 Suspend-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/suspend-devel