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                    openssl-users@openssl.org
Automated List Manager                           majord...@openssl.org

Reply via email to