int OpenSSLCryptoSymmetricKey::decryptCtxInit()

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;
}