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 [EMAIL PROTECTED]
   *
   * 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 [EMAIL PROTECTED]
   *
   * 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 */
  
  
  

Reply via email to