Hi, This is the version of the libgcrypt patch that I'd like to apply, if there are no objections.
Of course it makes s2disk/s2both and resume use libgcrypt instead of openssl, and replaces Blowfish with 128-bit AES (AES appears to 10% faster, although it is slower than the Blowfish out of openssl). I've tested it on two x86_64 machines with 1024- and 2048-bit RSA keys as well as on i386. NOTE1: libgcrypt requires /dev/random to be present in the resume initrd (I've added /dev/urandom too, for completness). NOTE2: Of course the RSA keys have to be regenerated to work with the patched utilities. A documentation update will follow. Greetings, Rafael -- Makefile | 9 + encrypt.c | 17 +-- encrypt.h | 48 ++++++--- keygen.c | 177 +++++++++++++++++++++++++---------- resume.c | 198 ++++++++++++++++++++++++++++++---------- scripts/create-resume-initrd.sh | 2 suspend.c | 193 +++++++++++++++++++++++++++----------- swsusp.h | 6 - 8 files changed, 463 insertions(+), 187 deletions(-) Index: suspend/encrypt.h =================================================================== --- suspend.orig/encrypt.h +++ suspend/encrypt.h @@ -11,40 +11,52 @@ */ #ifdef CONFIG_ENCRYPT -#include <openssl/blowfish.h> -#include <openssl/rsa.h> +#include <gcrypt.h> +/* Maximum length of a passphrase, in characters */ #define PASS_SIZE 128 +/* Symmetric cipher used for image encryption, the size of its key and its + * block, in bytes + */ +#define IMAGE_CIPHER GCRY_CIPHER_BLOWFISH #define KEY_SIZE 16 -#define IVEC_SIZE 8 -#define RSA_DATA_SIZE 1200 -#define KEY_DATA_SIZE 800 +#define CIPHER_BLOCK 8 +/* Symmetric cipher used for encrypting RSA private keys, the size of its key + * and its block, in bytes + */ +#define PK_CIPHER GCRY_CIPHER_AES +#define PK_KEY_SIZE 16 +#define PK_CIPHER_BLOCK 16 +/* Auxiliary constants */ +#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; -}; - struct encrypted_key { unsigned short size; unsigned char data[KEY_DATA_SIZE]; }; +struct key_data { + unsigned char key[KEY_SIZE]; + unsigned char ivec[CIPHER_BLOCK]; + struct RSA_data rsa; + struct encrypted_key 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 get_random_salt(char *salt, size_t size); +void encrypt_init(unsigned char *, unsigned char *, char *, int); +void get_random_salt(unsigned char *salt, size_t size); -#define KEY_FILE "/etc/suspend.key" +#define KEY_FILE "" #endif Index: suspend/keygen.c =================================================================== --- suspend.orig/keygen.c +++ suspend/keygen.c @@ -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[PK_KEY_SIZE]; + gcry_cipher_hd_t sym_hd; + unsigned char ivec[PK_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, PK_CIPHER_BLOCK); + strncpy((char *)ivec, pass_buf, PK_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(&sym_hd, PK_CIPHER, GCRY_CIPHER_MODE_CFB, + GCRY_CIPHER_SECURE); + if (ret) goto Free_RSA; + + ret = gcry_cipher_setkey(sym_hd, key_buf, PK_KEY_SIZE); + if (!ret) + ret = gcry_cipher_setiv(sym_hd, ivec, PK_CIPHER_BLOCK); + + if (!ret) + ret = gcry_cipher_encrypt(sym_hd, rsa.key_test, KEY_TEST_SIZE, + KEY_TEST_DATA, KEY_TEST_SIZE); + + gcry_cipher_close(sym_hd); + if (ret) + goto Free_RSA; + + /* Now, we can encrypt the private RSA key */ + ret = gcry_cipher_open(&sym_hd, PK_CIPHER, GCRY_CIPHER_MODE_CFB, + GCRY_CIPHER_SECURE); + if (ret) + goto Free_RSA; + + ret = gcry_cipher_setkey(sym_hd, key_buf, PK_KEY_SIZE); + if (!ret) + ret = gcry_cipher_setiv(sym_hd, ivec, PK_CIPHER_BLOCK); + + if (ret) + goto Free_sym; + + /* 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_sym; + + 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(sym_hd, rsa.data + offset, s, NULL, 0); + if (ret) + goto Free_sym; + + 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_sym: + gcry_cipher_close(sym_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 +++ suspend/suspend.c @@ -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,52 @@ 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) + goto No_RSA; + + error = gcry_cipher_setiv(cipher_handle, + key_data->ivec, CIPHER_BLOCK); + + if (error) + goto No_RSA; + + 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)); } else { int j; +No_RSA: 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 +636,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 +694,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 +709,7 @@ int suspend_system(int snapshot_fd, int goto Unfreeze; } #else - shutdown(); + suspend_shutdown(); #endif } else { free_swap_pages(snapshot_fd); @@ -918,10 +939,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 +955,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) { + unsigned short size; + + ret = gcry_ac_data_new(&key_set); + if (ret) + goto Destroy_key; + + rnd_fd = open("/dev/urandom", O_RDONLY); + if (rnd_fd <= 0) + goto Destroy_set; + + size = KEY_SIZE + CIPHER_BLOCK; + if (read(rnd_fd, key_data->key, size) != size) + goto Close_urandom; + + 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 = &key_data->encrypted_key; + char *str; + size_t s; + + 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_urandom: close(rnd_fd); +Destroy_set: + gcry_ac_data_destroy(key_set); +Destroy_key: + 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 +1089,18 @@ 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); + ret = gcry_cipher_open(&cipher_handle, IMAGE_CIPHER, + GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE); + if (ret) { + fprintf(stderr, "suspend: libgcrypt error %s\n", + gcry_strerror(ret)); + encrypt = 0; + } + } + if (encrypt) { mem_size -= buffer_size; key_data = (struct key_data *)((char *)mem_pool + mem_size); generate_key(); @@ -1138,6 +1213,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 +++ suspend/swsusp.h @@ -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; + unsigned char salt[CIPHER_BLOCK]; + struct RSA_data rsa; + struct encrypted_key key; #endif }; Index: suspend/encrypt.c =================================================================== --- suspend.orig/encrypt.c +++ suspend/encrypt.c @@ -59,32 +59,31 @@ 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) +void get_random_salt(unsigned char *salt, size_t size) { int fd; memset(salt, 0, size); - fd = open("/dev/random", O_RDONLY); + fd = open("/dev/urandom", O_RDONLY); if (fd >= 0) { read(fd, salt, size); close(fd); } } #endif + Index: suspend/resume.c =================================================================== --- suspend.orig/resume.c +++ suspend/resume.c @@ -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, + (void *)handle->read_buffer, handle->area_size, + dst, handle->area_size); #endif return error; } @@ -370,63 +368,147 @@ 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; - unsigned char *buf, *out, *key_buf; + 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, *ivec_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 sym_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(&sym_hd, PK_CIPHER, + GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE); + + if (ret) + goto Free_rsa; pass_buf = buffer; key_buf = (unsigned char *)pass_buf + PASS_SIZE; + ivec_buf = key_buf + PK_KEY_SIZE; + out = ivec_buf + PK_CIPHER_BLOCK; do { read_password(pass_buf, 0); - memset(ivec, 0, IVEC_SIZE); - strncpy((char *)ivec, pass_buf, IVEC_SIZE); + memset(ivec_buf, 0, PK_CIPHER_BLOCK); + strncpy((char *)ivec_buf, pass_buf, PK_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(sym_hd, key_buf, PK_KEY_SIZE); + if (!ret) + ret = gcry_cipher_setiv(sym_hd, ivec_buf, + PK_CIPHER_BLOCK); + + if (!ret) + ret = gcry_cipher_encrypt(sym_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(sym_hd); + if (!ret) + ret = gcry_cipher_open(&sym_hd, PK_CIPHER, + GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE); + + if (ret) + goto Free_rsa; + + ret = gcry_cipher_setkey(sym_hd, key_buf, PK_KEY_SIZE); + if (!ret) + ret = gcry_cipher_setiv(sym_hd, ivec_buf, PK_CIPHER_BLOCK); + + if (!ret) + ret = gcry_ac_data_new(&rsa_data_set); + + if (ret) { + gcry_cipher_close(sym_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(sym_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(sym_hd); + Free_rsa: - RSA_free(rsa); + gcry_ac_close(rsa_hd); + return ret; } #endif @@ -481,24 +563,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, + IMAGE_CIPHER, 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 +662,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 +711,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 +++ suspend/Makefile @@ -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 @@ -93,8 +96,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: $(S2DISK) $(S2BOTH) 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 +++ suspend/scripts/create-resume-initrd.sh @@ -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