in xsec/enc/OpenSSL/OpenSSLCryptoSymmetricKey.cpp [130:394]
int OpenSSLCryptoSymmetricKey::decryptCtxInit(const unsigned char* iv, const unsigned char* tag, unsigned taglen) {
// Returns amount of IV data used (in bytes)
// Sets m_initialised iff the key is OK and the IV is OK.
// GCM modes will leave this unset until the second call with the iv
if (m_initialised)
return 0;
if (m_keyLen == 0) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Cannot initialise without key");
}
else if (m_keyMode == MODE_NONE) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Cannot initialise without mode");
}
// Set up the context according to the required cipher type
switch (m_keyType) {
case (KEY_3DES_192) :
// A 3DES key
if (m_keyMode == MODE_CBC) {
if (iv == NULL) {
return 0; // Cannot initialise without an IV
}
/* Do not use "_ex" calls yet - as want backwards compatibility
with 0.9.6 */
#if defined(XSEC_OPENSSL_CONST_BUFFERS)
EVP_DecryptInit(mp_ctx, EVP_des_ede3_cbc(),m_keyBuf.rawBuffer(), iv);
#else
EVP_DecryptInit(mp_ctx, EVP_des_ede3_cbc(),(unsigned char *) m_keyBuf.rawBuffer(), (unsigned char *) iv);
#endif
m_ivSize = 8;
}
else if (m_keyMode == MODE_ECB) {
#if defined(XSEC_OPENSSL_CONST_BUFFERS)
EVP_DecryptInit(mp_ctx, EVP_des_ecb(), m_keyBuf.rawBuffer(), NULL);
#else
EVP_DecryptInit(mp_ctx, EVP_des_ecb(), (unsigned char *) m_keyBuf.rawBuffer(), NULL);
#endif
m_ivSize = 0;
}
else {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Unsupported DES3 cipher mode");
}
m_blockSize = 8;
break;
#if defined (XSEC_OPENSSL_HAVE_AES)
case (KEY_AES_128) :
// An AES key
if (m_keyMode == MODE_CBC) {
if (iv == NULL) {
return 0; // Cannot initialise without an IV
}
EVP_DecryptInit_ex(mp_ctx, EVP_aes_128_cbc(), NULL, m_keyBuf.rawBuffer(), iv);
}
#if defined (XSEC_OPENSSL_HAVE_GCM)
else if (m_keyMode == MODE_GCM) {
if (tag != NULL && taglen != 16) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Invalid authentication tag");
}
if (iv == NULL) {
// Just save off tag for later.
m_tagBuf.sbMemcpyIn(tag, taglen);
return 0;
}
if (m_tagBuf.sbRawBufferSize() == 0) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Authentication tag not set");
}
// We have everything, so we can fully init.
EVP_CipherInit_ex(mp_ctx, EVP_aes_128_gcm(), NULL, NULL, NULL, 0);
EVP_CIPHER_CTX_ctrl(mp_ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL);
EVP_CIPHER_CTX_ctrl(mp_ctx, EVP_CTRL_GCM_SET_TAG, 16, (void*)m_tagBuf.rawBuffer());
EVP_CipherInit_ex(mp_ctx, NULL, NULL, m_keyBuf.rawBuffer(), iv, 0);
}
#endif
else if (m_keyMode == MODE_ECB) {
EVP_DecryptInit_ex(mp_ctx, EVP_aes_128_ecb(), NULL, m_keyBuf.rawBuffer(), NULL);
}
else {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Unsupported AES cipher mode");
}
m_blockSize = 16;
break;
case (KEY_AES_192) :
// An AES key
if (m_keyMode == MODE_CBC) {
if (iv == NULL) {
return 0; // Cannot initialise without an IV
}
EVP_DecryptInit_ex(mp_ctx, EVP_aes_192_cbc(), NULL, m_keyBuf.rawBuffer(), iv);
}
#if defined (XSEC_OPENSSL_HAVE_GCM)
else if (m_keyMode == MODE_GCM) {
if (tag != NULL && taglen != 16) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Invalid authentication tag");
}
if (iv == NULL) {
// Just save off tag for later.
m_tagBuf.sbMemcpyIn(tag, taglen);
return 0;
}
if (m_tagBuf.sbRawBufferSize() == 0) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Authentication tag not set");
}
// We have everything, so we can fully init.
EVP_CipherInit_ex(mp_ctx, EVP_aes_192_gcm(), NULL, NULL, NULL, 0);
EVP_CIPHER_CTX_ctrl(mp_ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL);
EVP_CIPHER_CTX_ctrl(mp_ctx, EVP_CTRL_GCM_SET_TAG, 16, (void*)m_tagBuf.rawBuffer());
EVP_CipherInit_ex(mp_ctx, NULL, NULL, m_keyBuf.rawBuffer(), iv, 0);
}
#endif
else if (m_keyMode == MODE_ECB) {
EVP_DecryptInit_ex(mp_ctx, EVP_aes_192_ecb(), NULL, m_keyBuf.rawBuffer(), NULL);
}
else {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Unsupported AES cipher mode");
}
m_blockSize = 16;
break;
case (KEY_AES_256) :
// An AES key
if (m_keyMode == MODE_CBC) {
if (iv == NULL) {
return 0; // Cannot initialise without an IV
}
EVP_DecryptInit_ex(mp_ctx, EVP_aes_256_cbc(), NULL, m_keyBuf.rawBuffer(), iv);
}
#if defined (XSEC_OPENSSL_HAVE_GCM)
else if (m_keyMode == MODE_GCM) {
if (tag != NULL && taglen != 16) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Invalid authentication tag");
}
if (iv == NULL) {
// Just save off tag for later.
m_tagBuf.sbMemcpyIn(tag, taglen);
return 0;
}
if (m_tagBuf.sbRawBufferSize() == 0) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Authentication tag not set");
}
// We have everything, so we can fully init.
EVP_CipherInit_ex(mp_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL, 0);
EVP_CIPHER_CTX_ctrl(mp_ctx, EVP_CTRL_GCM_SET_IVLEN, 12, NULL);
EVP_CIPHER_CTX_ctrl(mp_ctx, EVP_CTRL_GCM_SET_TAG, 16, (void*)m_tagBuf.rawBuffer());
EVP_CipherInit_ex(mp_ctx, NULL, NULL, m_keyBuf.rawBuffer(), iv, 0);
}
#endif
else if (m_keyMode == MODE_ECB) {
EVP_DecryptInit_ex(mp_ctx, EVP_aes_256_ecb(), NULL, m_keyBuf.rawBuffer(), NULL);
}
else {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Unsupported AES cipher mode");
}
m_blockSize = 16;
break;
#else
case (KEY_AES_128) :
case (KEY_AES_192) :
case (KEY_AES_256) :
throw XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm,
"OpenSSL:SymmetricKey - AES not supported in this version of OpenSSL");
#endif /* XSEC_OPENSSL_HAVE_AES */
default :
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"OpenSSL:SymmetricKey - Unknown key type");
}
// Setup ivSize
switch (m_keyMode) {
case MODE_CBC:
m_ivSize = m_blockSize;
break;
case MODE_GCM:
m_ivSize = 12;
break;
default:
m_ivSize = 0;
}
// Reset some parameters
m_initialised = true;
m_bytesInLastBlock = 0;
// Disable OpenSSL padding - The interop samples have broken PKCS padding - AARGHH
#if defined (XSEC_OPENSSL_CANSET_PADDING)
EVP_CIPHER_CTX_set_padding(mp_ctx, 0);
#endif
// Return number of bytes chewed up by IV
return m_ivSize;
}