blob: 52b93fe47394b3215c39347c64034b617e3fc822 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* XSEC
*
* OpenSSLCryptoKeyRSA := RSA Keys
*
* Author(s): Berin Lautenbach
*
* $Id$
*
*/
#include <xsec/framework/XSECDefs.hpp>
#if defined (XSEC_HAVE_OPENSSL)
#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
#include <xsec/enc/OpenSSL/OpenSSLCryptoBase64.hpp>
#include <xsec/enc/OpenSSL/OpenSSLSupport.hpp>
#include <xsec/enc/XSECCryptoException.hpp>
#include <xsec/enc/XSECCryptoUtils.hpp>
#include <xsec/framework/XSECError.hpp>
#include "../../utils/XSECAlgorithmSupport.hpp"
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <xercesc/util/Janitor.hpp>
XSEC_USING_XERCES(ArrayJanitor);
#include <memory.h>
namespace {
// This code is modified from OpenSSL to implement SHA-2 hashing with OAEP.
// The MGF code is limited to SHA-1 in accordance with the XML Encryption spec.
// 0.9.8+ has a public MGF routine to call, this is a copy of it for older versions.
#ifndef XSEC_OPENSSL_HAVE_MGF1
int PKCS1_MGF1(unsigned char *mask, long len,
const unsigned char *seed, long seedlen, const EVP_MD *dgst)
{
long i, outlen = 0;
unsigned char cnt[4];
EVP_MD_CTX c;
unsigned char md[EVP_MAX_MD_SIZE];
int mdlen;
int rv = -1;
EVP_MD_CTX_init(&c);
mdlen = EVP_MD_size(dgst);
if (mdlen < 0)
goto err;
for (i = 0; outlen < len; i++)
{
cnt[0] = (unsigned char)((i >> 24) & 255);
cnt[1] = (unsigned char)((i >> 16) & 255);
cnt[2] = (unsigned char)((i >> 8)) & 255;
cnt[3] = (unsigned char)(i & 255);
if (!EVP_DigestInit_ex(&c,dgst, NULL)
|| !EVP_DigestUpdate(&c, seed, seedlen)
|| !EVP_DigestUpdate(&c, cnt, 4))
goto err;
if (outlen + mdlen <= len)
{
if (!EVP_DigestFinal_ex(&c, mask + outlen, NULL))
goto err;
outlen += mdlen;
}
else
{
if (!EVP_DigestFinal_ex(&c, md, NULL))
goto err;
memcpy(mask + outlen, md, len - outlen);
outlen = len;
}
}
rv = 0;
err:
EVP_MD_CTX_cleanup(&c);
return rv;
}
#endif
static int MGF1(unsigned char *mask, long len, const unsigned char *seed, long seedlen, const EVP_MD* digest)
{
return PKCS1_MGF1(mask, len, seed, seedlen, digest);
}
int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen,
const unsigned char *from, int flen,
const unsigned char *param, int plen,
const EVP_MD* digest,
const EVP_MD* mgf_digest)
{
int i, digestlen = EVP_MD_size(digest), emlen = tlen - 1;
unsigned char *db, *seed;
unsigned char *dbmask, seedmask[EVP_MAX_MD_SIZE]; // accomodate largest hash size
if (flen > emlen - 2 * digestlen - 1)
{
RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP,
RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
return 0;
}
if (emlen < 2 * digestlen + 1)
{
RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
to[0] = 0;
seed = to + 1;
db = to + digestlen + 1;
if (!EVP_Digest((void *)param, plen, db, NULL, digest, NULL))
return 0;
memset(db + digestlen, 0,
emlen - flen - 2 * digestlen - 1);
db[emlen - flen - digestlen - 1] = 0x01;
memcpy(db + emlen - flen - digestlen, from, (unsigned int) flen);
if (RAND_bytes(seed, digestlen) <= 0)
return 0;
dbmask = (unsigned char*) OPENSSL_malloc(emlen - digestlen);
if (dbmask == NULL)
{
RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, ERR_R_MALLOC_FAILURE);
return 0;
}
if (MGF1(dbmask, emlen - digestlen, seed, digestlen, mgf_digest) < 0)
return 0;
for (i = 0; i < emlen - digestlen; i++)
db[i] ^= dbmask[i];
if (MGF1(seedmask, digestlen, db, emlen - digestlen, mgf_digest) < 0)
return 0;
for (i = 0; i < digestlen; i++)
seed[i] ^= seedmask[i];
OPENSSL_free(dbmask);
return 1;
}
int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen,
const unsigned char *from, int flen, int num,
const unsigned char *param, int plen,
const EVP_MD* digest,
const EVP_MD* mgf_digest)
{
int i, digestlen = EVP_MD_size(digest), dblen, mlen = -1;
const unsigned char *maskeddb;
int lzero;
unsigned char *db = NULL, seed[EVP_MAX_MD_SIZE], phash[EVP_MAX_MD_SIZE];
unsigned char *padded_from;
int bad = 0;
if (--num < 2 * digestlen + 1)
/* 'num' is the length of the modulus, i.e. does not depend on the
* particular ciphertext. */
goto decoding_err;
lzero = num - flen;
if (lzero < 0)
{
/* signalling this error immediately after detection might allow
* for side-channel attacks (e.g. timing if 'plen' is huge
* -- cf. James H. Manger, "A Chosen Ciphertext Attack on RSA Optimal
* Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001),
* so we use a 'bad' flag */
bad = 1;
lzero = 0;
flen = num; /* don't overflow the memcpy to padded_from */
}
dblen = num - digestlen;
db = (unsigned char*) OPENSSL_malloc(dblen + num);
if (db == NULL)
{
RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, ERR_R_MALLOC_FAILURE);
return -1;
}
/* Always do this zero-padding copy (even when lzero == 0)
* to avoid leaking timing info about the value of lzero. */
padded_from = db + dblen;
memset(padded_from, 0, lzero);
memcpy(padded_from + lzero, from, flen);
maskeddb = padded_from + digestlen;
if (MGF1(seed, digestlen, maskeddb, dblen, mgf_digest))
return -1;
for (i = 0; i < digestlen; i++)
seed[i] ^= padded_from[i];
if (MGF1(db, dblen, seed, digestlen, mgf_digest))
return -1;
for (i = 0; i < dblen; i++)
db[i] ^= maskeddb[i];
if (!EVP_Digest((void *)param, plen, phash, NULL, digest, NULL))
return -1;
if (memcmp(db, phash, digestlen) != 0 || bad)
goto decoding_err;
else
{
for (i = digestlen; i < dblen; i++)
if (db[i] != 0x00)
break;
if (i == dblen || db[i] != 0x01)
goto decoding_err;
else
{
/* everything looks OK */
mlen = dblen - ++i;
if (tlen < mlen)
{
RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, RSA_R_DATA_TOO_LARGE);
mlen = -1;
}
else
memcpy(to, db + i, mlen);
}
}
OPENSSL_free(db);
return mlen;
decoding_err:
/* to avoid chosen ciphertext attacks, the error message should not reveal
* which kind of decoding error happened */
RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, RSA_R_OAEP_DECODING_ERROR);
if (db != NULL) OPENSSL_free(db);
return -1;
}
};
const EVP_MD* getDigestFromHashType(XSECCryptoHash::HashType type) {
const EVP_MD* evp_md = NULL;
switch (type) {
case XSECCryptoHash::HASH_SHA1:
evp_md = EVP_get_digestbyname("SHA1");
break;
case XSECCryptoHash::HASH_SHA224:
evp_md = EVP_get_digestbyname("SHA224");
break;
case XSECCryptoHash::HASH_SHA256:
evp_md = EVP_get_digestbyname("SHA256");
break;
case XSECCryptoHash::HASH_SHA384:
evp_md = EVP_get_digestbyname("SHA384");
break;
case XSECCryptoHash::HASH_SHA512:
evp_md = EVP_get_digestbyname("SHA512");
break;
default:
;
}
return evp_md;
}
OpenSSLCryptoKeyRSA::OpenSSLCryptoKeyRSA() :
mp_rsaKey(NULL),
mp_accumE(NULL),
mp_accumN(NULL)
{
};
OpenSSLCryptoKeyRSA::~OpenSSLCryptoKeyRSA() {
// If we have a RSA, delete it (OpenSSL will clear the memory)
if (mp_rsaKey)
RSA_free(mp_rsaKey);
if (mp_accumE)
BN_free(mp_accumE);
if (mp_accumN)
BN_free(mp_accumN);
};
const XMLCh* OpenSSLCryptoKeyRSA::getProviderName() const {
return DSIGConstants::s_unicodeStrPROVOpenSSL;
}
// Generic key functions
XSECCryptoKey::KeyType OpenSSLCryptoKeyRSA::getKeyType() const {
// Find out what we have
if (mp_rsaKey == NULL)
return KEY_NONE;
const BIGNUM *n, *d;
RSA_get0_key(mp_rsaKey, &n, NULL, &d);
if (n != NULL && d != NULL)
return KEY_RSA_PAIR;
if (d != NULL)
return KEY_RSA_PRIVATE;
if (n != NULL)
return KEY_RSA_PUBLIC;
return KEY_NONE;
}
void OpenSSLCryptoKeyRSA::loadPublicModulusBase64BigNums(const char* b64, unsigned int len) {
setNBase(OpenSSLCryptoBase64::b642BN((char *) b64, len));
}
void OpenSSLCryptoKeyRSA::setNBase(BIGNUM *nBase) {
if (mp_rsaKey == NULL)
mp_rsaKey = RSA_new();
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
mp_rsaKey->n = nBase;
#else
if (mp_accumN)
BN_free(mp_accumN);
mp_accumN = nBase;
commitEN();
#endif
}
void OpenSSLCryptoKeyRSA::loadPublicExponentBase64BigNums(const char* b64, unsigned int len) {
setEBase(OpenSSLCryptoBase64::b642BN((char *) b64, len));
}
void OpenSSLCryptoKeyRSA::setEBase(BIGNUM *eBase) {
if (mp_rsaKey == NULL)
mp_rsaKey = RSA_new();
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
mp_rsaKey->e = eBase;
#else
if (mp_accumE)
BN_free(mp_accumE);
mp_accumE = eBase;
commitEN();
#endif
}
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
void OpenSSLCryptoKeyRSA::commitEN() {
if (NULL == mp_accumN || NULL == mp_accumE)
return;
RSA_set0_key(mp_rsaKey, mp_accumN, mp_accumE, NULL);
mp_accumN = NULL;
mp_accumE = NULL;
}
#endif
// "Hidden" OpenSSL functions
OpenSSLCryptoKeyRSA::OpenSSLCryptoKeyRSA(EVP_PKEY *k) :
mp_rsaKey(NULL),
mp_accumE(NULL),
mp_accumN(NULL)
{
// Create a new key to be loaded as we go
mp_rsaKey = RSA_new();
if (k == NULL || EVP_PKEY_id(k) != EVP_PKEY_RSA)
return; // Nothing to do with us
const RSA *rsa = EVP_PKEY_get0_RSA(k);
const BIGNUM *n=NULL, *e=NULL, *d=NULL;
RSA_get0_key(rsa, &n, &e, &d);
if (n && e) // Do not dup unless setter will work
RSA_set0_key(mp_rsaKey, DUP_NON_NULL(n), DUP_NON_NULL(e), DUP_NON_NULL(d));
const BIGNUM *p=NULL, *q=NULL;
RSA_get0_factors(rsa, &p, &q);
if (p && q)
RSA_set0_factors(mp_rsaKey, DUP_NON_NULL(p), DUP_NON_NULL(q));
const BIGNUM *dmp1=NULL, *dmq1=NULL, *iqmp=NULL;
RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
if (dmp1 && dmq1 && iqmp)
RSA_set0_crt_params(mp_rsaKey, DUP_NON_NULL(dmp1), DUP_NON_NULL(dmq1), DUP_NON_NULL(iqmp));
}
// --------------------------------------------------------------------------------
// Verify a signature encoded as a Base64 string
// --------------------------------------------------------------------------------
bool OpenSSLCryptoKeyRSA::verifySHA1PKCS1Base64Signature(
const unsigned char* hashBuf,
unsigned int hashLen,
const char * base64Signature,
unsigned int sigLen,
XSECCryptoHash::HashType type) const {
// Use the currently loaded key to validate the Base64 encoded signature
if (mp_rsaKey == NULL) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - Attempt to validate signature with empty key");
}
XSECCryptoKey::KeyType keyType = getKeyType();
if (keyType != KEY_RSA_PAIR && keyType != KEY_RSA_PUBLIC) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - Attempt to validate signature without public key");
}
char* cleanedBase64Signature;
unsigned int cleanedBase64SignatureLen = 0;
cleanedBase64Signature =
XSECCryptoBase64::cleanBuffer(base64Signature, sigLen, cleanedBase64SignatureLen);
ArrayJanitor<char> j_cleanedBase64Signature(cleanedBase64Signature);
int sigValLen;
unsigned char* sigVal = new unsigned char[sigLen + 1];
ArrayJanitor<unsigned char> j_sigVal(sigVal);
EvpEncodeCtxRAII dctx;
if (!dctx.of()) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - allocation fail during Context Creation");
}
EVP_DecodeInit(dctx.of());
int rc = EVP_DecodeUpdate(dctx.of(),
sigVal,
&sigValLen,
(unsigned char *) cleanedBase64Signature,
cleanedBase64SignatureLen);
if (rc < 0) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - Error during Base64 Decode");
}
int t = 0;
EVP_DecodeFinal(dctx.of(), &sigVal[sigValLen], &t);
sigValLen += t;
// OpenSSL allows the signature size to be less than the key size.
// Java does not and the spec requires that this fail, so we have to
// perform this check.
int keySize = RSA_size(mp_rsaKey);
if (keySize != sigValLen) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - Signature size does not match key size");
}
// Now decrypt
unsigned char* decryptBuf;
// Decrypt will always be longer than (RSA_len(key) - 11)
decryptBuf = new unsigned char[RSA_size(mp_rsaKey)];
ArrayJanitor<unsigned char> j_decryptBuf(decryptBuf);
// Note at this time only supports PKCS1 padding
// As that is what is defined in the standard.
// If this ever changes we will need to pass some paramaters
// into this function to allow it to determine what the
// padding should be and what the message digest OID should
// be.
int decryptSize = RSA_public_decrypt(sigValLen,
sigVal,
decryptBuf,
mp_rsaKey,
RSA_PKCS1_PADDING);
if (decryptSize < 0) {
// Really - this is a failed signature check, not an exception!
return false;
}
/* Check the OID */
int oidLen = 0;
unsigned char * oid = getRSASigOID(type, oidLen);
if (oid == NULL) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA::verify() - Unsupported HASH algorithm for RSA");
}
if (decryptSize != (int) (oidLen + hashLen) || hashLen != oid[oidLen-1]) {
return false;
}
for (t = 0; t < oidLen; ++t) {
if (oid[t] != decryptBuf[t]) {
return false;
}
}
for (;t < decryptSize; ++t) {
if (hashBuf[t-oidLen] != decryptBuf[t]) {
return false;
}
}
// All OK
return true;
}
// --------------------------------------------------------------------------------
// Sign and encode result as a Base64 string
// --------------------------------------------------------------------------------
unsigned int OpenSSLCryptoKeyRSA::signSHA1PKCS1Base64Signature(
unsigned char* hashBuf,
unsigned int hashLen,
char * base64SignatureBuf,
unsigned int base64SignatureBufLen,
XSECCryptoHash::HashType type) const {
// Sign a pre-calculated hash using this key
if (mp_rsaKey == NULL) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - Attempt to sign data with empty key");
}
KeyType keyType = getKeyType();
if (keyType != KEY_RSA_PAIR && keyType != KEY_RSA_PRIVATE) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - Attempt to sign data without private key");
}
// Build the buffer to be encrypted by prepending the SHA1 OID to the hash
unsigned char* encryptBuf;
unsigned char* preEncryptBuf;
unsigned char* oid;
int oidLen;
int encryptLen;
int preEncryptLen;
oid = getRSASigOID(type, oidLen);
if (oid == NULL) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA::sign() - Unsupported HASH algorithm for RSA");
}
if (hashLen != oid[oidLen-1]) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA::sign() - hashLen incorrect for hash type");
}
preEncryptLen = hashLen + oidLen;
preEncryptBuf = new unsigned char[preEncryptLen];
encryptBuf = new unsigned char[RSA_size(mp_rsaKey)];
memcpy(preEncryptBuf, oid, oidLen);
memcpy(&preEncryptBuf[oidLen], hashBuf, hashLen);
// Now encrypt
encryptLen = RSA_private_encrypt(preEncryptLen,
preEncryptBuf,
encryptBuf,
mp_rsaKey,
RSA_PKCS1_PADDING);
delete[] preEncryptBuf;
if (encryptLen < 0) {
delete[] encryptBuf;
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA::sign() - Error encrypting hash");
}
// Now convert to Base 64
BIO * b64 = BIO_new(BIO_f_base64());
BIO * bmem = BIO_new(BIO_s_mem());
BIO_set_mem_eof_return(bmem, 0);
b64 = BIO_push(b64, bmem);
// Translate signature to Base64
BIO_write(b64, encryptBuf, encryptLen);
BIO_flush(b64);
unsigned int sigValLen = BIO_read(bmem, base64SignatureBuf, base64SignatureBufLen);
BIO_free_all(b64);
delete[] encryptBuf;
if (sigValLen <= 0) {
throw XSECCryptoException(XSECCryptoException::DSAError,
"OpenSSL:RSA - Error base64 encoding signature");
}
return sigValLen;
}
// --------------------------------------------------------------------------------
// decrypt a buffer
// --------------------------------------------------------------------------------
unsigned int OpenSSLCryptoKeyRSA::privateDecrypt(
const unsigned char* inBuf,
unsigned char* plainBuf,
unsigned int inLength,
unsigned int maxOutLength,
PaddingType padding,
const XMLCh* hashURI,
const XMLCh* mgfURI,
unsigned char* params,
unsigned int paramslen) const {
// Perform a decrypt
if (mp_rsaKey == NULL) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - Attempt to decrypt data with empty key");
}
#if 0
/* normally commented out code to determine endian problems */
unsigned int i;
unsigned char e[2048];
unsigned char * inBuf1 = (unsigned char *) inBuf;
if (inLength < 2048) {
memcpy(e, inBuf, inLength);
for (i = 0; i < inLength;++i) {
inBuf1[i] = e[inLength - 1 - i];
}
}
#endif
int decryptSize;
switch (padding) {
case XSECCryptoKeyRSA::PAD_PKCS_1_5 :
decryptSize = RSA_private_decrypt(inLength,
#if defined(XSEC_OPENSSL_CONST_BUFFERS)
inBuf,
#else
(unsigned char *) inBuf,
#endif
plainBuf,
mp_rsaKey,
RSA_PKCS1_PADDING);
if (decryptSize < 0) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA privateKeyDecrypt - Error Decrypting PKCS1_5 padded RSA encrypt");
}
break;
case XSECCryptoKeyRSA::PAD_OAEP :
{
const EVP_MD* evp_md = getDigestFromHashType(XSECAlgorithmSupport::getHashType(hashURI));
if (evp_md == NULL) {
throw XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm,
"OpenSSL:RSA - OAEP digest algorithm not supported");
}
const EVP_MD* mgf_md = getDigestFromHashType(XSECAlgorithmSupport::getMGF1HashType(mgfURI));
if (mgf_md == NULL) {
throw XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm,
"OpenSSL:RSA - OAEP MGF algorithm not supported");
}
unsigned char * tBuf;
int num = RSA_size(mp_rsaKey);
XSECnew(tBuf, unsigned char[num]);
ArrayJanitor<unsigned char> j_tBuf(tBuf);
decryptSize = RSA_private_decrypt(inLength,
#if defined(XSEC_OPENSSL_CONST_BUFFERS)
inBuf,
#else
(unsigned char *) inBuf,
#endif
tBuf,
mp_rsaKey,
RSA_NO_PADDING);
if (decryptSize < 0) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA privateKeyDecrypt - Error doing raw decrypt of RSA encrypted data");
}
// Clear out the "0"s at the front
int i;
for (i = 0; i < num && tBuf[i] == 0; ++i)
--decryptSize;
decryptSize = RSA_padding_check_PKCS1_OAEP(plainBuf,
maxOutLength,
&tBuf[i],
decryptSize,
num,
params,
paramslen,
evp_md,
mgf_md);
if (decryptSize < 0) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA privateKeyDecrypt - Error removing OAEPadding");
}
}
break;
default :
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - Unknown padding method");
}
#if 0
/* normally commented out code to determine endian problems */
int i;
unsigned char t[512];
if (decryptSize < 512) {
memcpy(t, plainBuf, decryptSize);
for (i = 0; i < decryptSize;++i) {
plainBuf[i] = t[decryptSize - 1 - i];
}
}
#endif
return decryptSize;
}
// --------------------------------------------------------------------------------
// encrypt a buffer
// --------------------------------------------------------------------------------
unsigned int OpenSSLCryptoKeyRSA::publicEncrypt(
const unsigned char* inBuf,
unsigned char* cipherBuf,
unsigned int inLength,
unsigned int maxOutLength,
PaddingType padding,
const XMLCh* hashURI,
const XMLCh* mgfURI,
unsigned char* params,
unsigned int paramslen) const {
// Perform an encrypt
if (mp_rsaKey == NULL) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - Attempt to encrypt data with empty key");
}
int encryptSize;
switch (padding) {
case XSECCryptoKeyRSA::PAD_PKCS_1_5 :
encryptSize = RSA_public_encrypt(inLength,
#if defined(XSEC_OPENSSL_CONST_BUFFERS)
inBuf,
#else
(unsigned char *) inBuf,
#endif
cipherBuf,
mp_rsaKey,
RSA_PKCS1_PADDING);
if (encryptSize < 0) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA publicKeyEncrypt - Error performing PKCS1_5 padded RSA encrypt");
}
break;
case XSECCryptoKeyRSA::PAD_OAEP :
{
unsigned char * tBuf;
unsigned int num = RSA_size(mp_rsaKey);
if (maxOutLength < num) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA publicKeyEncrypt - Not enough space in cipherBuf");
}
const EVP_MD* evp_md = getDigestFromHashType(XSECAlgorithmSupport::getHashType(hashURI));
if (evp_md == NULL) {
throw XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm,
"OpenSSL:RSA - OAEP digest algorithm not supported");
}
const EVP_MD* mgf_md = getDigestFromHashType(XSECAlgorithmSupport::getMGF1HashType(mgfURI));
if (mgf_md == NULL) {
throw XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm,
"OpenSSL:RSA - OAEP MGF algorithm not supported");
}
XSECnew(tBuf, unsigned char[num]);
ArrayJanitor<unsigned char> j_tBuf(tBuf);
// First add the padding
encryptSize = RSA_padding_add_PKCS1_OAEP(tBuf,
num,
//#if defined(XSEC_OPENSSL_CONST_BUFFERS)
inBuf,
//#else
// (unsigned char *) inBuf,
//#endif
inLength,
params,
paramslen,
evp_md,
mgf_md);
if (encryptSize <= 0) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA publicKeyEncrypt - Error adding OAEPadding");
}
encryptSize = RSA_public_encrypt(num,
tBuf,
cipherBuf,
mp_rsaKey,
RSA_NO_PADDING);
if (encryptSize < 0) {
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA publicKeyEncrypt - Error encrypting padded data");
}
}
break;
default :
throw XSECCryptoException(XSECCryptoException::RSAError,
"OpenSSL:RSA - Unknown padding method");
}
return encryptSize;
}
// --------------------------------------------------------------------------------
// Size in bytes
// --------------------------------------------------------------------------------
unsigned int OpenSSLCryptoKeyRSA::getLength() const {
if (mp_rsaKey != NULL)
return RSA_size(mp_rsaKey);
return 0;
}
// --------------------------------------------------------------------------------
// Clone this key
// --------------------------------------------------------------------------------
XSECCryptoKey * OpenSSLCryptoKeyRSA::clone() const {
OpenSSLCryptoKeyRSA * ret;
XSECnew(ret, OpenSSLCryptoKeyRSA);
ret->mp_rsaKey = RSA_new();
// Duplicate parameters
const BIGNUM *n=NULL, *e=NULL, *d=NULL;
RSA_get0_key(mp_rsaKey, &n, &e, &d);
if (n && e) // Do not dup unless setter will work
RSA_set0_key(ret->mp_rsaKey, DUP_NON_NULL(n), DUP_NON_NULL(e), DUP_NON_NULL(d));
const BIGNUM *p=NULL, *q=NULL;
RSA_get0_factors(mp_rsaKey, &p, &q);
if (p && q)
RSA_set0_factors(ret->mp_rsaKey, DUP_NON_NULL(p), DUP_NON_NULL(q));
const BIGNUM *dmp1=NULL, *dmq1=NULL, *iqmp=NULL;
RSA_get0_crt_params(mp_rsaKey, &dmp1, &dmq1, &iqmp);
if (dmp1 && dmq1 && iqmp)
RSA_set0_crt_params(ret->mp_rsaKey, DUP_NON_NULL(dmp1), DUP_NON_NULL(dmq1), DUP_NON_NULL(iqmp));
return ret;
}
#endif /* XSEC_HAVE_OPENSSL */