Hi, crypto guys!
I have problem with EVP_PKEY_decrypt() function and 4K RSA private key
decrypting data encrypted with EVP_PKEY_encrypt() and corresponding
public key. Keys generated using openssl CA shell script.
EVP_PKEY_decrypt() just returns -2 saying that this key is not
supported. BUT! RSA_private_decrypt() works just fine with this key and
successfully decrypts data encrypted by EVP_PKEY_encrypt()! Sign and
verify operations works fine with EVP_PKEY_sign() and EVP_PKEY_verify()
with the same keys.
I use openssl 1.0.1c.
The questions are:
1. Is there some meaningful limitation coded into EVP_PKEY_decrypt()
that does not allow decrypt operation?
2. If no such limitations, how I can make it work with 4K RSA keys?
Functions sources below.
--------------------
EVP_PKEY *extract_pub_key(char *pem_key, size_t key_len) {
BIO *bio;
X509 *x509 = NULL;
EVP_PKEY *pkey;
//char *passwd="";
//pem_password_cb *key_passwd_func = &read_pvt_key_pass;
bio = BIO_new_mem_buf(pem_key, key_len);
if (!PEM_read_bio_X509(bio, &x509, NULL, NULL)) {
//error
return NULL;
} else {
//process X.509
pkey = X509_extract_key(x509);
}
X509_free(x509);
BIO_free_all(bio);
return pkey;
}
EVP_PKEY *extract_pvt_key(char *pem_key, size_t key_len) {
EVP_PKEY *pkey = NULL;
BIO *bio;
char *passwd = "\0";
pem_password_cb *key_passwd_func = &read_pvt_key_pass;
//put key into BIO for PEM reading functions
bio = BIO_new_mem_buf(pem_key, key_len);
pkey = PEM_read_bio_PrivateKey(bio, &pkey, key_passwd_func, (void*)
passwd);
BIO_free_all(bio);
return pkey;
}
int encrypt_with_pubk(int handle, char *pem_key, size_t key_len,
unsigned char *plain, int plain_len, unsigned char *encoded, int
*encoded_len) {
EVP_PKEY *pub_key;
EVP_PKEY_CTX *ctx;
size_t outlen;
int res;
pub_key = extract_pub_key(pem_key, key_len);
if (pub_key == NULL) {
crypto_set_err(handle);
return -1;
}
ctx = EVP_PKEY_CTX_new(pub_key, NULL);
if (!ctx) {
crypto_set_err(handle);
res = -1;
} else if ( EVP_PKEY_encrypt_init(ctx) <= 0 ||
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <=0){
crypto_set_err(handle);
res = -1;
} else if (EVP_PKEY_encrypt(ctx, NULL, &outlen, plain, plain_len) <=
0) { /* Determine buffer length */
crypto_set_err(handle);
res = -1;
} else if (outlen>*encoded_len) {
crypto_set_err(handle);
res = -2;
} else if (EVP_PKEY_encrypt(ctx, encoded, &outlen, plain, plain_len)
<= 0) {
crypto_set_err(handle);
res = -1;
} else {
res = outlen;
}
*encoded_len = res;
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pub_key);
return res;
}
/* OLD, works fine with new EVP_encrypt() */
int decrypt_with_pvtk(int handle, char *pem_key, size_t key_len,
unsigned char *plain, int * plain_len, unsigned char *encoded, int
encoded_len) {
EVP_PKEY *pvt_key;
int len;
int rsa_key_len;
int n_pieces;
int i, idx;
pvt_key = extract_pvt_key(pem_key, key_len);
if (pvt_key == NULL) {
crypto_set_err(handle);
return -1;
}
rsa_key_len = RSA_size(pvt_key->pkey.rsa); //we have blocks of this
size in encrypted text
n_pieces = encoded_len / rsa_key_len;
if((encoded_len % rsa_key_len)!=0) n_pieces++;
if ((encoded_len % rsa_key_len) != 0) {
return -2; //we must have n rsa_key_len pieces
}
len = 0;
for (i = 0; i < n_pieces; i++) {
idx = i*rsa_key_len;
len = len + RSA_private_decrypt(rsa_key_len, (unsigned char *)
&(encoded[idx]), &plain[len], pvt_key->pkey.rsa, RSA_PKCS1_PADDING);
}
EVP_PKEY_free(pvt_key);
*plain_len=len;
return len;
}
/* NEW. ATTENTION! This function does not work because
EVP_PKEY_decrypt() returns -2 meaning
"operation not supported for this keytype", though Key is RSA 4K and
"old" function above works with
new EVP_PLEY_encrypt().
*/
int decrypt_with_pvtk(int handle, char *pem_key, size_t key_len,
unsigned char *plain, int * plain_len, unsigned char *encoded, int
encoded_len) {
EVP_PKEY *pvt_key;
EVP_PKEY_CTX *ctx;
int outlen;
int res;
pvt_key = extract_pvt_key(pem_key, key_len);
if (pvt_key == NULL) {
crypto_set_err(handle);
return -1;
}
ctx = EVP_PKEY_CTX_new(pvt_key, NULL);
if (!ctx) {
crypto_set_err(handle);
return -1;
} else if (EVP_PKEY_decrypt_init(ctx) <= 0) {
crypto_set_err(handle);
res = -1;
} else if (EVP_PKEY_decrypt(ctx, NULL, (size_t *) & outlen, encoded,
encoded_len) <= 0) { // Determine buffer length
crypto_set_err(handle);
res = -1;
} else if (outlen>*plain_len) {
crypto_set_err(handle);
res = -2;
} else if ((res=EVP_PKEY_decrypt(ctx, plain, (size_t *) & outlen,
encoded, encoded_len)) <= 0) {
crypto_set_err(handle);
res = -1;
} else {
res = outlen;
}
*plain_len = res;
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pvt_key);
return res;
}
--
SY, Alex Lukin
RIPE NIC HDL: LEXA1-RIPE
______________________________________________________________________
OpenSSL Project http://www.openssl.org
User Support Mailing List [email protected]
Automated List Manager [email protected]