You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@santuario.apache.org by bl...@apache.org on 2003/10/13 13:07:42 UTC

cvs commit: xml-security/c/src/enc/WinCAPI WinCAPICryptoSymmetricKey.hpp WinCAPICryptoSymmetricKey.cpp

blautenb    2003/10/13 04:07:42

  Added:       c/src/enc/WinCAPI WinCAPICryptoSymmetricKey.hpp
                        WinCAPICryptoSymmetricKey.cpp
  Log:
  Implementation of Symmetric Encryption in WinCAPI
  
  Revision  Changes    Path
  1.1                  xml-security/c/src/enc/WinCAPI/WinCAPICryptoSymmetricKey.hpp
  
  Index: WinCAPICryptoSymmetricKey.hpp
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "<WebSig>" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 2001, Institute for
   * Data Communications Systems, <http://www.nue.et-inf.uni-siegen.de/>.
   * The development of this software was partly funded by the European 
   * Commission in the <WebSig> project in the ISIS Programme. 
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  /*
   * XSEC
   *
   * XSECCryptoSymmetricKey := Bulk encryption algorithms should all be
   *							implemented via this interface
   *
   * Author(s): Berin Lautenbach
   *
   * $Id: WinCAPICryptoSymmetricKey.hpp,v 1.1 2003/10/13 11:07:42 blautenb Exp $
   *
   */
  
  
  
  #ifndef WINCAPICRYPTOSYMMETRICKEY_INCLUDE
  #define WINCAPICRYPTOSYMMETRICKEY_INCLUDE
  
  #include <xsec/framework/XSECDefs.hpp>
  #include <xsec/enc/XSECCryptoSymmetricKey.hpp>
  
  #if defined (HAVE_WINCAPI)
  
  #if !defined(_WIN32_WINNT)
  #	define _WIN32_WINNT 0x0400
  #endif
  
  #include <wincrypt.h>
  
  #define MAX_BLOCK_SIZE		32
  
  /**
   * \ingroup wincapicrypto
   * @{
   */
  
  /**
   * \brief Base interface definition for symmetric key material.
   *
   * This is the implementation for a wrapper of Windows CryptoAPI symmetric
   * crypto functions.
   */
  
  class DSIG_EXPORT WinCAPICryptoSymmetricKey : public XSECCryptoSymmetricKey {
  
  public :
  
  	/** @name Constructors and Destructors */
  	//@{
  	
  	/**
  	 * \brief Constructor
  	 *
  	 * Can only construct a Symmetric key if we know what type it is
  	 *
  	 * @param prov The appropriate provider that supports the required algorithm.
  	 * Can be 0 if the app is going to pass in an octet via setKey, as the library
  	 * will use its own internal key store and handle to CSP.
  	 * @param type The type of key (i.e. algorithm) to create
  	 **/
  
  	WinCAPICryptoSymmetricKey(HCRYPTPROV prov, XSECCryptoSymmetricKey::SymmetricKeyType type);
  
  	/**
  	 * \brief Destructor 
  	 *
  	 * Implementations must ensure that the held key is properly destroyed
  	 * (overwritten) when key objects are deleted.
  	 */
  
  	virtual ~WinCAPICryptoSymmetricKey();
  
  	//@}
  
  	/** @name Basic CryptoKey Interface methods */
  	//@{
  
  	/**
  	 * \brief Returns a string that identifies the crypto owner of this library.
  	 */
  
  	virtual const XMLCh * getProviderName();
  
  	/**
  	 * \brief Clone the key
  	 *
  	 * All keys need to be able to copy themselves and return
  	 * a pointer to the copy.  This allows the library to 
  	 * duplicate keys.
  	 */
  
  	virtual XSECCryptoKey * clone();
  
  	//@}
  
  	/** @name Symmetric key interface methods */
  	//@{
  
  	/**
  	 * \brief What type of symmetric key is this?
  	 *
  	 * There are a number of different types of symmetric key.
  	 * This method allows callers to determine the type of this
  	 * particular key
  	 */
  
  	SymmetricKeyType getSymmetricKeyType(void);
  
  	/**
  	 * \brief Set the key from the provided bytes
  	 *
  	 * Symmetric keys can all be loaded from a buffer containing a series
  	 * of bytes.
  	 *
  	 * @param key The buffer containing the key bytes
  	 * @param keyLen The number of key bytes in the buffer
  	 *
  	 */
  
  	void setKey(const unsigned char * key, unsigned int keyLen);
  
  	/**
  	 * \brief Initialise an decryption process
  	 *
  	 * Setup the key to get ready for a decryption session.
  	 * Callers can pass in an IV.  If one is not provided, 
  	 * then it is assumed that the algorithm will not require one.
  	 *
  	 * @param doPad By default, we perform padding for last block
  	 * @param iv Initialisation Vector to be used.  NULL if one is
  	 * not required.
  	 * @returns true if the initialisation succeeded.
  	 */
  
  	virtual bool decryptInit(bool doPad = true, const unsigned char * iv = NULL);
  
  	/**
  	 * \brief Continue an decrypt operation using this key.
  	 *
  	 * Decryption must have been set up using an encryptInit
  	 * call.  Takes the inBuf and continues a decryption operation,
  	 * writing the output to outBuf.
  	 *
  	 * This function does not have to guarantee that all input
  	 * will be decrypted.  In cases where the input is not a length
  	 * of the block size, the implementation will need to hold back
  	 * cipher-text to be handles during the next operation.
  	 *
  	 * @note While maxOutLength is defined, the OpenSSL libraries will
  	 * not read the value, so the onus is on the caller to ensure the
  	 * buffer is long enough to hold the output!
  	 *
  	 * @param inBuf Octets to be decrypted
  	 * @param plainBuf Buffer to place output in
  	 * @param inLength Number of bytes to decrypt
  	 * @param maxOutLength Maximum number of bytes to place in output 
  	 * buffer
  	 * @returns Bytes placed in output Buffer
  	 */
  
  	virtual unsigned int decrypt(const unsigned char * inBuf, 
  								 unsigned char * plainBuf, 
  								 unsigned int inLength,
  								 unsigned int maxOutLength);
  
  	/**
  	 * \brief Finish a decryption operation
  	 *
  	 * Complete a decryption process.  No cipher text is passed in,
  	 * as this should simply be removing any remaining text from
  	 * the plain storage buffer.
  	 *
  	 * May throw an exception if there is some stored cipher text
  	 * that is not the length of the block size for block algorithms.
  	 *
  	 * @note While maxOutLength is defined, the OpenSSL libraries will
  	 * not read the value, so the onus is on the caller to ensure the
  	 * buffer is long enough to hold the output!
  	 *
  	 * @param plainBuf Buffer to place any remaining plain text in
  	 * @param maxOutLength Maximum number of bytes to pace in output
  	 * @returns Bytes placed in output buffer
  	 */
  
  	virtual unsigned int decryptFinish(unsigned char * plainBuf,
  									   unsigned int maxOutLength);
  
  	/**
  	 * \brief Initialise an encryption process
  	 *
  	 * Setup the key to get ready for a decryption session.
  	 * Callers can pass in an IV.  If one is not provided, 
  	 * but the algorithm requires one (e.g. 3DES_CBC), then
  	 * implementations are required to generate one.
  	 *
  	 * @param doPad By default, we perform padding for last block
  	 * @param iv Initialisation Vector to be used.  NULL if one is
  	 * not required, or if IV is to be generated
  	 * @returns true if the initialisation succeeded.
  	 */
  
  	virtual bool encryptInit(bool doPad = true, const unsigned char * iv = NULL);
  
  	/**
  	 * \brief Continue an encryption operation using this key.
  	 *
  	 * Encryption must have been set up using an encryptInit
  	 * call.  Takes the inBuf and continues a encryption operation,
  	 * writing the output to outBuf.
  	 *
  	 * This function does not have to guarantee that all input
  	 * will be encrypted.  In cases where the input is not a length
  	 * of the block size, the implementation will need to hold back
  	 * plain-text to be handled during the next operation.
  	 *
  	 * @param inBuf Octets to be encrypted
  	 * @param cipherBuf Buffer to place output in
  	 * @param inLength Number of bytes to encrypt
  	 * @param maxOutLength Maximum number of bytes to place in output 
  	 * buffer
  	 * @returns Bytes placed in output Buffer
  	 */
  
  	virtual unsigned int encrypt(const unsigned char * inBuf, 
  								 unsigned char * cipherBuf, 
  								 unsigned int inLength,
  								 unsigned int maxOutLength);
  
  	/**
  	 * \brief Finish a encryption operation
  	 *
  	 * Complete a encryption process.  No plain text is passed in,
  	 * as this should simply be removing any remaining text from
  	 * the plain storage buffer and creating a final padded block.
  	 *
  	 * Padding is performed by taking the remaining block, and
  	 * setting the last byte to equal the number of bytes of
  	 * padding.  If the plain was an exact multiple of the block size,
  	 * then an extra block of padding will be used.  For example, if 
  	 * the block size is 8 bytes, and there were three remaining plain
  	 * text bytes (0x01, 0x02 and 0x03), the final block will be :
  	 *
  	 * 0x010203????????05
  	 *
  	 * @param cipherBuf Buffer to place final block of cipher text in
  	 * @param maxOutLength Maximum number of bytes to pace in output
  	 * @returns Bytes placed in output buffer
  	 */
  
  	virtual unsigned int encryptFinish(unsigned char * plainBuf,
  									   unsigned int maxOutLength);
  
  	//@}
  
  	/** @name Windows utility functions */
  	//@{
  
  	/**
  	 * \brief Create a symmetric key from a octet string
  	 *
  	 * Uses the ApacheKeyStore to wrap an octet string in a public key
  	 * and then load it into the Apache Key Container within the defined 
  	 * CSP
  	 *
  	 * @param key The buffer of bytes to load from
  	 * @param keyLen The number of bytes to load
  	 * @param type The key type to create from the bytes
  	 * @param prov If NULL, ignored.  If non-null, but *prov == 0, the
  	 * function will use an internal handle to a CSP and return the value
  	 * in *prov.  If *prov != 0, use contents of *prov as the provider to
  	 * load the key into.  NOTE - The provider <em>must</em> have a
  	 * AT_KEYEXCHANGE key pair available.
  	 * @returns a pointer to the key or 0 on failure
  	 */
  
  	static HCRYPTKEY createWindowsKey(const unsigned char * key, 
  									  unsigned int keyLen, 
  									  XSECCryptoSymmetricKey::SymmetricKeyType type,
  									  HCRYPTPROV * prov);
  
  
  
  private:
  
  	// Unimplemented constructors
  	
  	WinCAPICryptoSymmetricKey();
  	WinCAPICryptoSymmetricKey(const WinCAPICryptoSymmetricKey &);
  	WinCAPICryptoSymmetricKey & operator= (const WinCAPICryptoSymmetricKey &);
  
  	int decryptCtxInit(const unsigned char * iv);
  	void encryptCtxInit(const unsigned char * iv);
  
  	// Private variables
  	SymmetricKeyType				m_keyType;
  	safeBuffer						m_keyBuf;		// Holder of the key
  	unsigned int					m_keyLen;
  	bool							m_initialised;
  	bool							m_doPad;
  
  	unsigned char					m_lastBlock[MAX_BLOCK_SIZE];
  	unsigned int					m_bytesInLastBlock;
  	unsigned int					m_blockSize;
  	unsigned int					m_ivSize;
  
  	HCRYPTPROV						m_p;
  	HCRYPTKEY						m_k;
  
  };
  
  #endif /* HAVE_WINCAPI */
  #endif /* WINCAPICRYPTOSYMMETRICKEY_INCLUDE */
  
  
  
  1.1                  xml-security/c/src/enc/WinCAPI/WinCAPICryptoSymmetricKey.cpp
  
  Index: WinCAPICryptoSymmetricKey.cpp
  ===================================================================
  /*
   * The Apache Software License, Version 1.1
   *
   *
   * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights 
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer. 
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:  
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "<WebSig>" and "Apache Software Foundation" must
   *    not be used to endorse or promote products derived from this
   *    software without prior written permission. For written 
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation and was
   * originally based on software copyright (c) 2001, Institute for
   * Data Communications Systems, <http://www.nue.et-inf.uni-siegen.de/>.
   * The development of this software was partly funded by the European 
   * Commission in the <WebSig> project in the ISIS Programme. 
   * For more information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  
  /*
   * XSEC
   *
   * XSECCryptoSymmetricKey := Bulk encryption algorithms should all be
   *							implemented via this interface
   *
   * $Id: WinCAPICryptoSymmetricKey.cpp,v 1.1 2003/10/13 11:07:42 blautenb Exp $
   *
   */
  
  #include <xsec/framework/XSECDefs.hpp>
  #include <xsec/utils/XSECPlatformUtils.hpp>
  #include <xsec/enc/WinCAPI/WinCAPICryptoProvider.hpp>
  #include <xsec/enc/WinCAPI/WinCAPICryptoSymmetricKey.hpp>
  #include <xsec/framework/XSECError.hpp>
  #include <xsec/enc/XSECCryptoException.hpp>
  
  #include <xercesc/util/Janitor.hpp>
  
  XERCES_CPP_NAMESPACE_USE
  
  #if defined (HAVE_WINCAPI)
  
  // --------------------------------------------------------------------------------
  //           Constructors and Destructors
  // --------------------------------------------------------------------------------
  
  WinCAPICryptoSymmetricKey::WinCAPICryptoSymmetricKey(
  						HCRYPTPROV prov,
  						XSECCryptoSymmetricKey::SymmetricKeyType type) :
  m_keyType(type),
  m_keyBuf(""),
  m_initialised(false),
  m_doPad(true),
  m_p(prov),
  m_k(0) {
  
  	m_keyBuf.isSensitive();
  
  }
  
  WinCAPICryptoSymmetricKey::~WinCAPICryptoSymmetricKey() {
  
  	if (m_k != 0)
  		CryptDestroyKey(m_k);
  
  }
  
  // --------------------------------------------------------------------------------
  //           Basic Key interface methods
  // --------------------------------------------------------------------------------
  
  XSECCryptoSymmetricKey::SymmetricKeyType WinCAPICryptoSymmetricKey::getSymmetricKeyType() {
  
  	return m_keyType;
  
  }
  
  const XMLCh * WinCAPICryptoSymmetricKey::getProviderName() {
  
  	return DSIGConstants::s_unicodeStrPROVWinCAPI;
  
  }
  
  XSECCryptoKey * WinCAPICryptoSymmetricKey::clone() {
  
  	WinCAPICryptoSymmetricKey * ret;
  
  	XSECnew(ret, WinCAPICryptoSymmetricKey(m_p, m_keyType));
  	ret->m_keyLen = m_keyLen;
  	ret->m_keyBuf = m_keyBuf;
  
  	if (m_k != 0) {
  
  #if (_WIN32_WINNT >= 0x0400)
  		if (CryptDuplicateKey(m_k,
  			 				  0,
  							  0,
  							  &(ret->m_k)) == 0 ) {
  
  			throw XSECCryptoException(XSECCryptoException::SymmetricError,
  				"WinCAPI:KeyHMAC Error attempting to clone key parameters");
  
  		}
  #else
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"Unable to clone keys in Windows NT 4.0 and below");
  #endif
  	}
  	else
  		ret->m_k = 0;
  
  	return ret;
  
  }
  
  // --------------------------------------------------------------------------------
  //           Store the key value
  // --------------------------------------------------------------------------------
  
  void WinCAPICryptoSymmetricKey::setKey(const unsigned char * key, unsigned int keyLen) {
  
  	m_keyBuf.sbMemcpyIn(key, keyLen);
  	m_keyLen = keyLen;
  
  	if (m_k != 0)
  		CryptDestroyKey(m_k);
  	
  	m_p = 0;
  	m_k = createWindowsKey(key, keyLen, m_keyType, &m_p);
  }
  
  // --------------------------------------------------------------------------------
  //           Decrypt
  // --------------------------------------------------------------------------------
  
  int WinCAPICryptoSymmetricKey::decryptCtxInit(const unsigned char * iv) {
  
  	// Returns amount of IV data used (in bytes)
  	// Sets m_initialised iff the key is OK and the IV is OK.
  
  	if (m_initialised)
  		return 0;
  
  	if (m_k == 0) {
  
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Cannot initialise without key"); 
  
  	}
  
  	// Set up the context according to the required cipher type
  	DWORD cryptMode;
  	switch (m_keyType) {
  
  	case (XSECCryptoSymmetricKey::KEY_3DES_CBC_192) :
  
  		// A 3DES CBC key
  
  		if (iv == NULL) {
  
  			return 0;	// Cannot initialise without an IV
  
  		}
  
  		if (!CryptSetKeyParam(m_k, KP_IV, (unsigned char *) iv, 0)) {
  
  			throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Error setting IV"); 
  
  		}
  
  		m_blockSize = 8;
  		m_bytesInLastBlock = 0;
  		m_initialised = true;
  		
  		return 8;	// 3DEC_CBC uses a 64 bit IV
  
  		break;
  
  	case (XSECCryptoSymmetricKey::KEY_AES_ECB_128) :
  
  			// An 128bit AES key in ECB mode
  
  		cryptMode = CRYPT_MODE_ECB;
  
  		if (!CryptSetKeyParam(m_k, KP_MODE, (BYTE *) (&cryptMode), 0)) {
  
  			throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Error setting IV"); 
  
  		}
  
  		m_blockSize = 16;
  		m_bytesInLastBlock = 0;
  		m_initialised = true;
  		
  		return 8;	// 3DEC_CBC uses a 64 bit IV
  
  		break;
  
  	default :
  
  		// Cannot do this without an IV
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Unknown key type"); 
  
  	}
  
  	return 0;
  }
  
  
  bool WinCAPICryptoSymmetricKey::decryptInit(bool doPad, const unsigned char * iv) {
  
  	m_initialised = false;
  	m_doPad = doPad;
  	decryptCtxInit(iv);
  	return true;
  
  }
  
  unsigned int WinCAPICryptoSymmetricKey::decrypt(const unsigned char * inBuf, 
  								 unsigned char * plainBuf, 
  								 unsigned int inLength,
  								 unsigned int maxOutLength) {
  
  
  
  	// NOTE: This won't actually stop WinCAPI blowing the buffer, so the onus is
  	// on the caller.
  
  	unsigned int offset = 0;
  	if (!m_initialised) {
  		offset = decryptCtxInit(inBuf);
  		if (offset > inLength) {
  			throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Not enough data passed in to get IV");
  		}
  	}
  
  	DWORD outl = inLength - offset;
  
  	// Copy in last block
  	if (m_bytesInLastBlock > 0)
  		memcpy(plainBuf, m_lastBlock, m_bytesInLastBlock);
  
  	// Copy out the tail, as we _MUST_ know when we come to the end for decryptFinal
  	unsigned int rounding = (outl % m_blockSize) + m_blockSize;
  	memcpy(&plainBuf[m_bytesInLastBlock], &inBuf[offset], outl - rounding);
  
  	// Copy the tail to m_lastBlock
  	memcpy(m_lastBlock, &inBuf[offset + outl - rounding], rounding);
  	outl = outl - rounding + m_bytesInLastBlock;
  	m_bytesInLastBlock = rounding;
  	
  	if (!CryptDecrypt(m_k,
  				 0,
  				 FALSE,
  				 0,
  				 plainBuf,
  				 &outl)) {
  
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Error during WinCAPI decrypt"); 
  
  	}
  
  	return outl;
  
  }
  
  unsigned int WinCAPICryptoSymmetricKey::decryptFinish(unsigned char * plainBuf,
  													  unsigned int maxOutLength) {
  
  	DWORD outl = m_bytesInLastBlock;
  
  	memcpy(plainBuf, m_lastBlock, outl);
  
  	if (!CryptDecrypt(m_k, 
  					  0, 
  					  FALSE,
  					  0,
  					  plainBuf,
  					  &outl)) {
  
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Error during WinCAPI decrypt finalisation"); 
  
  	}
  
  	if (m_doPad) {
  
  		// Need to do this ourselves, as WinCAPI appears broken
  		if (plainBuf[outl - 1] > 8) {
  			throw XSECCryptoException(XSECCryptoException::SymmetricError,
  				"WinCAPI:SymmetricKey - Bad padding"); 
  		}
  
  		outl -= plainBuf[outl - 1];
  
  	}
  
  	return outl;
  }
  
  // --------------------------------------------------------------------------------
  //           Encrypt
  // --------------------------------------------------------------------------------
  
  void WinCAPICryptoSymmetricKey::encryptCtxInit(const unsigned char * iv) {
  
  
  
  	if (m_initialised == true)
  		return;
  	
  	if (m_keyLen == 0) {
  
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Cannot initialise without key"); 
  
  	}
  
  	m_initialised = true;
  
  	// Set up the context according to the required cipher type
  
  	const unsigned char * usedIV;
  	unsigned char genIV[256];
  
  	// Tell the library that the IV still has to be sent
  
  	switch (m_keyType) {
  
  	case (XSECCryptoSymmetricKey::KEY_3DES_CBC_192) :
  
  		// A 3DES key
  
  		if (iv == NULL) {
  			
  			BOOL res = CryptGenRandom(m_p, 256, genIV);
  			if (res == FALSE) {
  				throw XSECCryptoException(XSECCryptoException::SymmetricError,
  					"WinCAPI:SymmetricKey - Error generating random IV");
  			}
  
  			usedIV = genIV;
  			//return 0;	// Cannot initialise without an IV
  
  		}
  		else
  			usedIV = iv;
  
  		// Set the IV parameter
  		if (!CryptSetKeyParam(m_k, KP_IV, (unsigned char *) usedIV, 0)) {
  
  			throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Error setting IV"); 
  
  		}
  
  		m_blockSize = 8;
  		m_ivSize = 8;
  		memcpy(m_lastBlock, usedIV, m_ivSize);
  		m_bytesInLastBlock = 0;
  
  		break;
  
  	case (XSECCryptoSymmetricKey::KEY_AES_ECB_128) :
  
  		// An AES key
  
  		m_blockSize = 16;
  		m_ivSize = 0;
  		m_bytesInLastBlock = 0;
  
  		break;
  	
  	default :
  
  		// Cannot do this without an IV
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Unknown key type"); 
  
  	}
  
  }
  bool WinCAPICryptoSymmetricKey::encryptInit(bool doPad, const unsigned char * iv) {
  
  	m_doPad = doPad;
  	m_initialised = false;
  	encryptCtxInit(iv);
  	return true;
  
  }
  
  unsigned int WinCAPICryptoSymmetricKey::encrypt(const unsigned char * inBuf, 
  								 unsigned char * cipherBuf, 
  								 unsigned int inLength,
  								 unsigned int maxOutLength) {
  
  	if (m_initialised == false) {
  
  		encryptInit();
  
  	}
  
  	// NOTE: This won't actually stop WinCAPI blowing the buffer, so the onus is
  	// on the caller.
  
  	unsigned int offset = 0;
  	unsigned char * bufPtr;
  	unsigned char * encPtr;	// Ptr to start of block to encrypt
  
  	DWORD outl = 0;
  	
  	if (m_ivSize > 0) {
  
  		memcpy(cipherBuf, m_lastBlock, m_ivSize);
  		offset = m_ivSize;
  		outl += m_ivSize;
  		m_ivSize = 0;
  
  	}
  
  	bufPtr = &cipherBuf[offset];
  	encPtr = bufPtr;
  
  	if (m_bytesInLastBlock > 0) {
  		memcpy(bufPtr, m_lastBlock, m_bytesInLastBlock);
  		bufPtr = &bufPtr[m_bytesInLastBlock];
  		outl += m_bytesInLastBlock;
  	}
  
  	unsigned int rounding = (m_bytesInLastBlock + inLength) % m_blockSize;
  	rounding += m_blockSize;
  
  	outl += inLength - rounding;
  	if (outl > maxOutLength) {
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Not enough space in output buffer for encrypt"); 
  	}
  
  	outl -= offset;
  
  	// Now copy back one block + rounding
  	memcpy(m_lastBlock, &inBuf[inLength - rounding], rounding);
  	m_bytesInLastBlock = rounding;
  
  	// Finally, copy in last of buffer to encrypt
  	memcpy(bufPtr, inBuf, inLength - rounding);
  
  	// Do the enrypt
  	if (!CryptEncrypt(m_k, 0, FALSE, 0, encPtr, &outl, maxOutLength)) {
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Error during WinCAPI encrypt"); 
  	}
  	
  	return outl + offset;
  
  }
  
  unsigned int WinCAPICryptoSymmetricKey::encryptFinish(unsigned char * cipherBuf,
  													  unsigned int maxOutLength) {
  
  	DWORD outl = m_bytesInLastBlock + m_blockSize;
  
  	if (outl > maxOutLength) {
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Not enough space in output buffer for encrypt - NOTE WinCAPI requires an extra block to complete encryption"); 
  	}
  
  	outl = 0;
  
  	if (m_bytesInLastBlock != 0) {
  
  		memcpy(cipherBuf, m_lastBlock, m_bytesInLastBlock);
  		outl = m_bytesInLastBlock;
  
  	}
  
  	if (!CryptEncrypt(m_k, 0, TRUE, 0, cipherBuf, &outl, maxOutLength)) {
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Error during WinCAPI encrypt"); 
  	}
  
  	if (!m_doPad) {
  
  		// It is the responsibility of the caller to ensure they have 
  		// passed in block size num bytes
  
  		if (outl >= m_blockSize)
  			outl -= m_blockSize;
  
  	}
  
  	return outl;
  
  }
  
  
  // --------------------------------------------------------------------------------
  //           Create a windows key
  // --------------------------------------------------------------------------------
  
  HCRYPTKEY WinCAPICryptoSymmetricKey::createWindowsKey(
  								const unsigned char * key, 
  								unsigned int keyLen, 
  								XSECCryptoSymmetricKey::SymmetricKeyType type,
  								HCRYPTPROV * prov) {
  
  	// First get the correct Provider handle to load the key into
  	
  	HCRYPTPROV p;
  	
  	if (prov == NULL || *prov == 0) {
  		WinCAPICryptoProvider * cp = 
  			dynamic_cast<WinCAPICryptoProvider*>(XSECPlatformUtils::g_cryptoProvider);
  
  		p = cp->getApacheKeyStore();
  
  		if (p == 0) {
  
  			throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Unable to retrieve internal key store"); 
  
  		}
  
  		if (prov != NULL)
  			*prov = p;
  	}
  
  	else if (prov != NULL)
  		p = *prov;
  
  	// Get the key wrapping key
  	HCRYPTKEY k;
  	if (!CryptGetUserKey(p, AT_KEYEXCHANGE, &k)) {
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Unable to retrieve internal key pair"); 
  	}
  
  	// Find out how long the output will be
  	DWORD outl = 0;
  	if (!CryptEncrypt(k, 0, TRUE, 0, 0, &outl, keyLen)) {
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Unable to determine space required to encrypt key");
  	}
  
  	// Create the necessary buffer
  	unsigned char * encryptBuf;
  	unsigned int encryptBufSize = outl;
  	XSECnew(encryptBuf, unsigned char[outl]);
  	ArrayJanitor<unsigned char> j_encryptBuf(encryptBuf);
  
  	memcpy(encryptBuf, key, keyLen);
  	outl = keyLen;
  
  	// Do the encrypt
  
  	if (!CryptEncrypt(k, 0, TRUE, 0, encryptBuf, &outl, encryptBufSize)) {
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Unable to encrypt key");
  	}
  
  	// Now we have the encrypted buffer, create a SIMPLEBLOB structure
  
  	unsigned char * simpleBlob;
  	XSECnew(simpleBlob, unsigned char [sizeof (BLOBHEADER) + sizeof (DWORD) +  outl]);
  	ArrayJanitor<unsigned char> j_simpleBlob(simpleBlob);
  
  	BLOBHEADER * blobHeader = (BLOBHEADER *) simpleBlob;
  	blobHeader->bType = SIMPLEBLOB;
  	blobHeader->bVersion = CUR_BLOB_VERSION;
  	blobHeader->reserved = 0;
  
  	unsigned int expectedLength;
  
  	switch (type) {
  
  	case (XSECCryptoSymmetricKey::KEY_3DES_CBC_192) :
  					blobHeader->aiKeyAlg = CALG_3DES;
  					expectedLength = 24;
  					break;
  	case (XSECCryptoSymmetricKey::KEY_AES_ECB_128) :
  					blobHeader->aiKeyAlg = CALG_AES_128;
  					expectedLength = 16;
  					break;
  	default :
  
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey::createWindowsKey - Unknown Symmetric key type");
  
  	}
  
  	// Check key length - otherwise the user could get some very cryptic error messages
  	if (keyLen != expectedLength) {
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey::createWindowsKey - Keylength incorrect for algorithm");
  	}
  
  	DWORD * algId = (DWORD *) (simpleBlob + sizeof(BLOBHEADER));
  	*algId = CALG_RSA_KEYX;
  
  	// Copy in the encrypted data
  	memcpy(&simpleBlob[sizeof(BLOBHEADER) + sizeof(DWORD)], encryptBuf, outl);
  
  	// Now do the import
  
  	HCRYPTKEY k2;
  
  	if (!CryptImportKey(p, simpleBlob, sizeof(BLOBHEADER) + sizeof(DWORD) + outl, k, CRYPT_EXPORTABLE, &k2)) {
  		throw XSECCryptoException(XSECCryptoException::SymmetricError,
  			"WinCAPI:SymmetricKey - Unable to import key");
  	}
  
  	return k2;
  
  }
  
  
  #endif /* HAVE_WINCAPI */