Il Wed, Jul 19, 2006 at 05:55:17PM +0200, Rafael J. Wysocki ha scritto:
> 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.
Agree...
Btw, it should be made very clear that the user has to regenerate his
RSA key after the update. I think that if the old key is left in place
the image will be encrypted with a random key, since generate_key()
will leave key_data->key uninitialized. See below.
Also I find the code hard to read especially due to the "allocate one
big buffer and use it multiple times for different stuff"... I know that
mlockall() may cause future allocations to fail but we are talking about
a couple of pages at most.
> 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
> @@ -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;
Is the order of exponents and primes guaranteed to be always the same?
Maybe it's better to get them using their names.
> +
> + 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;
> --- suspend.orig/suspend.c 2006-07-19 17:23:54.000000000 +0200
> +++ suspend/suspend.c 2006-07-19 17:24:17.000000000 +0200
> @@ -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);
key_data->key is initialized in generate_key() which may fail silently.
> + 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));
> + }
> @@ -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);
Suppose old key file was left in place. gcry_ac_key_init will probably
fail, since rsa_data_set is filled with "garbage". key_data->key is left
uninitlialed and will be used for encrypting the image.
Easy fix is to propagated the error, if generate_key() fails suspend
aborts.
> +
> + 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);
> }
Hum, I'd reorganize the code to reduce the indendation (and the
wrapping).
> - 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));
Btw, gcry_check_version should be used to ensure that the expected
version of the library is in place. Bebian for example ships at least 3
different versions (I don't know if/how the API differs).
> + gcry_control(GCRYCTL_INIT_SECMEM, page_size, 0);
You can also disable secure memory, it's nothing more than a mlock()'ed
area and we call mlockall() anyway.
> + 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;
Will test it ASAP and report back ;)
Luca
--
Home: http://kronoz.cjb.net
Al termine di un pranzo di nozze mi hanno dato un
amaro alle erbe cosi' schifoso che perfino sull'etichetta
c'era un frate che vomitava.
-------------------------------------------------------------------------
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