Hello.
I know that the documentation says that RSA encrypt and decrypt functions are not working, but well, I see that the examples directory has the files rsa-encrypt.c and rsa-decrypt.c, and they seem to work (I compiled and tested them).
So, I don't really want to do the traditional RSA encryption where an AES (or other cypher) key is encrypted with RSA, and the text is encrypted with the AES key. Suppose I have a list of symmetric cypher keys (possibly for different algorithms, or diferent lengths). I'd then use the the rsa_encrypt and rsa_decrypt functions defined in rsa.h on each of the keys.
I have tried to make that work but rsa-decrypt complains that it can't decrypt the message, and I can't tell exactly how (the rsa-decrypt code may return zero in 4 different situations). Maybe it could set some error variable (like errno) to tell the user what went wrong?
BTW, I'm including the programs I was trying to use. The two functions are supposed to encrypt and decrypt a short message (which will actually be a symmetric cypher key). The encrypted message is returned in base64 from __cryptengine_nettle_asym_enc, so it can be stored in C++ strings and written to newline-separated files. Similarly, __cryptengine_nettle_asym_dec decodes a base64 string and then tries to decrypt the result. Encrypting doesn't give me any errors, but decrypting fails.
Is there something obviously wrong in this?
J.
PS: the two functions:
#include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <nettle/aes.h> #include <nettle/base64.h> #include <nettle/cbc.h> #include <gmp.h> #include <nettle/bignum.h> #include <nettle/rsa.h> #include <nettle/yarrow.h>
char * __cryptengine_nettle_asym_enc (const char *text, const char *pubk, const long size, const int keysize) {
uint8_t random_data[20]; int file_desc=open("/dev/random",O_RDONLY); read (file_desc,random_data,20); close (file_desc); struct yarrow256_ctx yarrow; struct rsa_public_key key; mpz_t x;
rsa_public_key_init(&key); if (!rsa_keypair_from_sexp(&key, NULL, 0, keysize, (uint8_t *) pubk)) { return NULL; }
yarrow256_init(&yarrow, 0, NULL); yarrow256_seed(&yarrow, 20, random_data);
yarrow256_random(&yarrow, size, (uint8_t *)text);
mpz_init(x);
if (!rsa_encrypt(&key, &yarrow, (nettle_random_func) yarrow256_random, size, (uint8_t *)text, x)) { fprintf(stderr,"RSA_ENCRYPT FAILED for size %d\n",size); return NULL; }; fprintf(stderr,"RSA_ENCRYPT SUCEEDED for size %d\n",size);
rsa_public_key_clear(&key);
int new_size = nettle_mpz_sizeinbase_256_u (x); char * pre_result = (char *) malloc (new_size * sizeof(char)); nettle_mpz_get_str_256(new_size, pre_result, x);
// // Encode using base64: //
int encoded_size = BASE64_ENCODE_LENGTH(new_size); uint8_t * result = (uint8_t *) calloc (encoded_size, sizeof(uint8_t));
struct base64_encode_ctx b64_ctx; base64_encode_init(&b64_ctx);
int done = base64_encode_update(&b64_ctx, result, new_size, pre_result); done += base64_encode_final(&b64_ctx, result);
result = (uint8_t *) realloc (result, done + 1); result[done] = '\0'; free (pre_result); return result; }
char * __cryptengine_nettle_asym_dec (const char *text, const char *prik, const long size, const int keysize) {
// // Decode from base64: //
unsigned decoded_size = BASE64_DECODE_LENGTH(size); uint8_t * decoded_text = (uint8_t *) calloc (decoded_size, sizeof(uint8_t));
struct base64_decode_ctx b64_ctx; base64_decode_init(&b64_ctx); int done = base64_decode_update(&b64_ctx, &decoded_size, decoded_text, size, (uint8_t *)text); base64_decode_final(&b64_ctx);
char * result = (char *) malloc (decoded_size * sizeof(char));
mpz_t x; struct rsa_private_key key; rsa_private_key_init(&key);
if (!rsa_keypair_from_sexp(NULL, &key, 0, keysize, (uint8_t *) prik)) { fprintf(stderr,"Can't read private key\n"); return NULL; };
nettle_mpz_init_set_str_256_u(x, decoded_size, decoded_text); nettle_mpz_set_str_256_u(x, decoded_size, decoded_text);
unsigned length = decoded_size; int res; if (! (res = rsa_decrypt(&key, &length, result, x)) || length != decoded_size) { fprintf(stderr,"Can't decrypt. res = %d, length = %d, dec_size = %d\n",res,length,decoded_size); return NULL; }
return result; }
Jeronimo Pellegrini pellegrini@mpcnet.com.br writes:
I know that the documentation says that RSA encrypt and decrypt functions are not working, but well,
Does the manual say that? Where? I thought these functions just weren't documented at all yet.
I have tried to make that work but rsa-decrypt complains that it can't decrypt the message, and I can't tell exactly how (the rsa-decrypt code may return zero in 4 different situations). Maybe it could set some error variable (like errno) to tell the user what went wrong?
It's always tricky to track down bugs in crypto code, since all intermediary results tend to look like gibberish. Try to isolate the problem, by looking at the binary date before base64 encoding and after decoding, to see that you recover the same data.
It's intentional that the return value doesn't give you any failure mode. If you use such an indication in real use of a program, you can easily leak information to an attacker. And when debugging, well, use the debugger to set a breakpoint on the rsa_decrypt function to see what happens.
BTW, I'm including the programs I was trying to use.
[...]
Is there something obviously wrong in this?
It looks basically right to me. But the call
done += base64_encode_final(&b64_ctx, result);
looks suspicious. It should probably be
done += base64_encode_final(&b64_ctx, result + done);
I'll send you further comments on your code in a private mail.
Regards, /Niels
On Wed, Apr 19, 2006 at 11:11:39PM +0200, Niels Möller wrote:
Jeronimo Pellegrini pellegrini@mpcnet.com.br writes:
I know that the documentation says that RSA encrypt and decrypt functions are not working, but well,
Does the manual say that? Where? I thought these functions just weren't documented at all yet.
Well, it says it's not supported by the library. In Reference -> Public key algorithms, the fifth paragraph says:
|Two important uses for one-way functions with trapdoors are |public-key encryption, and digital signatures. Of these, I won't say |more about public-key encryption, as that isn't yet supported by |Nettle. So the rest of this chapter is about digital signatures.
Maybe you forgot to remove this?
J.
Jeronimo Pellegrini pellegrini@mpcnet.com.br writes:
Well, it says it's not supported by the library. In Reference -> Public key algorithms, the fifth paragraph says:
|Two important uses for one-way functions with trapdoors are |public-key encryption, and digital signatures. Of these, I won't say |more about public-key encryption, as that isn't yet supported by |Nettle. So the rest of this chapter is about digital signatures.
Thanks. I've now changed this to
: Two important uses for one-way functions with trapdoors are public-key : encryption, and digital signatures. The public-key encryption functions : in Nettle are not yet documented; the rest of this chapter is about : digital signatures.
Regards, /Niels
On Thu, Apr 20, 2006 at 02:32:26PM +0200, Niels Möller wrote:
Thanks. I've now changed this to
: Two important uses for one-way functions with trapdoors are public-key : encryption, and digital signatures. The public-key encryption functions : in Nettle are not yet documented; the rest of this chapter is about : digital signatures.
You're welcome. Is that in CVS?
J.
Jeronimo Pellegrini pellegrini@mpcnet.com.br writes:
You're welcome. Is that in CVS?
Yes, now it is.
/Niels
On Fri, Apr 21, 2006 at 09:10:10AM +0200, Niels Möller wrote:
Jeronimo Pellegrini pellegrini@mpcnet.com.br writes:
You're welcome. Is that in CVS?
Yes, now it is.
Ah, I see it there. Did you get the documentation patch that I sent to your private address?
J
Jeronimo Pellegrini pellegrini@mpcnet.com.br writes:
Ah, I see it there. Did you get the documentation patch that I sent to your private address?
I've got it, but I haven't had time to look into it yet.
/Niels
nettle-bugs@lists.lysator.liu.se