//------------------------------------------------------------------------------ // Desc: This file contains the functions needed for the NICI interface // functions. Adapted from ss_crypto.c written by Cameron Mashayekhi. // // Tabs: 3 // // Copyright (c) 2004-2006 Novell, Inc. All Rights Reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of version 2 of the GNU General Public // License as published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, contact Novell, Inc. // // To contact Novell about this file by physical or electronic mail, // you may find current contact information at www.novell.com // // $Id$ //------------------------------------------------------------------------------ #include "flaimsys.h" #ifdef FLM_USE_NICI FSTATIC void GetIV( FLMBYTE * pucIV, FLMUINT uiLen); #endif /*----------------------------------------------------------------------------- * Desc: DTOR - Destroy an F_CCS object. *---------------------------------------------------------------------------*/ F_CCS::~F_CCS() { #ifdef FLM_USE_NICI if( m_keyHandle) { if( !m_hContext) { if( RC_BAD( CCS_CreateContext(0, &m_hContext))) { flmAssert( 0); } } // Get rid of the key handle. if ( m_hContext) { CCS_DestroyObject( m_hContext, m_keyHandle); CCS_DestroyContext( m_hContext); } } if (m_hMutex != F_MUTEX_NULL) { f_mutexDestroy( &m_hMutex); } #endif } /*----------------------------------------------------------------------------- * Desc: wrapNiciKey - Save the wrapped key in m_pKey. NOTE: Make sure * there is a buffer allocated for the wrapped key (m_pucWrappedKey). *---------------------------------------------------------------------------*/ RCODE F_CCS::wrapKey( FLMBYTE ** ppucWrappedKey, FLMUINT32 * pui32Length, NICI_OBJECT_HANDLE masterWrappingKey) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( ppucWrappedKey); F_UNREFERENCED_PARM( pui32Length); F_UNREFERENCED_PARM( masterWrappingKey); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ATTRIBUTE wKey[2]; NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_aes128[] = {IDV_NOV_AES128CBCPad}; FLMBYTE oid_aes192[] = {IDV_NOV_AES192CBCPad}; FLMBYTE oid_aes256[] = {IDV_NOV_AES256CBCPad}; FLMBYTE oid_3des[] = {IDV_DES_EDE3_CBCPadIV8}; NICI_OBJECT_HANDLE wrappingKeyHandle; FLMBOOL bLocked = FALSE; if (masterWrappingKey) { wrappingKeyHandle = masterWrappingKey; } else { if (RC_BAD( rc = getWrappingKey( &wrappingKeyHandle))) { goto Exit; } } f_mutexLock( m_hMutex); bLocked = TRUE; /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } f_memset( &wKey, 0, sizeof(NICI_ATTRIBUTE) * 2); wKey[0].type = NICI_A_KEY_TYPE; wKey[1].type = NICI_A_KEY_SIZE; if (RC_BAD( rc = CCS_GetAttributeValue( m_hContext, wrappingKeyHandle, &wKey[0], 2))) { rc = RC_SET( NE_SFLM_NICI_ATTRIBUTE_VALUE); m_hContext = 0; // Context has been destroyed goto Exit; } if (!wKey[0].u.f.hasValue || !wKey[1].u.f.hasValue) { rc = RC_SET( NE_SFLM_NICI_BAD_ATTRIBUTE); goto Exit; } switch (wKey[0].u.f.value) { case NICI_K_AES: { switch (wKey[1].u.f.value) { case SFLM_AES128_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes128; break; } case SFLM_AES192_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes192; break; } case SFLM_AES256_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes256; break; } default: { rc = RC_SET( NE_SFLM_INVALID_ENC_KEY_SIZE); goto Exit; } } algorithm.parameter = parm; algorithm.parameterLen = sizeof(algorithm.parameter->parms[0])+ sizeof(algorithm.parameter->count); algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; algorithm.parameter->parms[0].u.b.len = IV_SZ; /* 16-byte IV */ algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)m_ucIV; break; } case NICI_K_DES3X: { algorithm.algorithm = (nuint8 *)oid_3des; algorithm.parameter = parm; algorithm.parameterLen = sizeof(algorithm.parameter->parms[0])+ sizeof(algorithm.parameter->count); algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; algorithm.parameter->parms[0].u.b.len = IV_SZ8; /* 8-byte IV */ algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)m_ucIV; break; } default: { rc = RC_SET( NE_SFLM_NICI_WRAPKEY_FAILED); goto Exit; } } // We should be able to call this with NULL for the wrapped key, to get the length. if (RC_BAD( rc = CCS_WrapKey( m_hContext, &algorithm, NICI_KM_UNSPECIFIED, 0, wrappingKeyHandle, m_keyHandle, (nuint8 *)NULL, (pnuint32)pui32Length))) { rc = RC_SET( NE_SFLM_NICI_WRAPKEY_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } if (RC_BAD( rc = f_calloc( *pui32Length, ppucWrappedKey))) { goto Exit; } if (RC_BAD( rc = CCS_WrapKey( m_hContext, &algorithm, NICI_KM_UNSPECIFIED, 0, wrappingKeyHandle, m_keyHandle, (nuint8 *)*ppucWrappedKey, (pnuint32)pui32Length))) { rc = RC_SET( NE_SFLM_NICI_WRAPKEY_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } #endif Exit: #ifdef FLM_USE_NICI if (bLocked) { f_mutexUnlock( m_hMutex); } #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: - unwrapKey *---------------------------------------------------------------------------*/ RCODE F_CCS::unwrapKey( FLMBYTE * pucWrappedKey, FLMUINT32 ui32WrappedKeyLength, NICI_OBJECT_HANDLE masterWrappingKey) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucWrappedKey); F_UNREFERENCED_PARM( ui32WrappedKeyLength); F_UNREFERENCED_PARM( masterWrappingKey); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ATTRIBUTE wKey; NICI_OBJECT_HANDLE wrappingKeyHandle; FLMBOOL bLocked = FALSE; if (masterWrappingKey) { wrappingKeyHandle = masterWrappingKey; } else { if (RC_BAD( rc = getWrappingKey( &wrappingKeyHandle))) { goto Exit; } } f_mutexLock( m_hMutex); bLocked = TRUE; /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } if (RC_BAD( rc = CCS_UnwrapKey( m_hContext, wrappingKeyHandle, (nuint8 *)pucWrappedKey, ui32WrappedKeyLength, &m_keyHandle))) { rc = RC_SET( NE_SFLM_NICI_UNWRAPKEY_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } // We need to get the key size... f_memset( &wKey, 0, sizeof(NICI_ATTRIBUTE)); wKey.type = NICI_A_KEY_SIZE; if (RC_BAD( rc = CCS_GetAttributeValue( m_hContext, m_keyHandle, &wKey, 1))) { rc = RC_SET( NE_SFLM_NICI_ATTRIBUTE_VALUE); m_hContext = 0; // Context has been destroyed goto Exit; } if (!wKey.u.f.hasValue) { rc = RC_SET( NE_SFLM_NICI_BAD_ATTRIBUTE); goto Exit; } m_uiEncKeySize = wKey.u.f.value; #endif Exit: #ifdef FLM_USE_NICI if (bLocked) { f_mutexUnlock( m_hMutex); } #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: generateEncryptionKey *---------------------------------------------------------------------------*/ RCODE F_CCS::generateEncryptionKey( FLMUINT uiEncKeySize ) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( uiEncKeySize); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else switch( m_eEncAlgorithm) { case SFLM_AES_ENCRYPTION: { rc = generateEncryptionKeyAES( uiEncKeySize); break; } case SFLM_DES3_ENCRYPTION: { rc = generateEncryptionKeyDES3( uiEncKeySize); break; } default: { flmAssert( 0); rc = RC_SET( NE_SFLM_NICI_INVALID_ALGORITHM); goto Exit; } } #endif Exit: return rc; } /*----------------------------------------------------------------------------- * Desc: generateEncryptionKey *---------------------------------------------------------------------------*/ RCODE F_CCS::generateEncryptionKeyAES( FLMUINT uiEncKeySize ) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( uiEncKeySize); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ALGORITHM algorithm; NICI_ATTRIBUTE keyAttr[3]; nbool8 keySizeChanged; FLMBYTE oid_aes128[] = {IDV_AES128CBC}; FLMBYTE oid_aes192[] = {IDV_AES192CBC}; FLMBYTE oid_aes256[] = {IDV_AES256CBC}; f_mutexLock( m_hMutex); /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } /* Set up AES Algorithm*/ switch (uiEncKeySize) { case SFLM_AES128_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes128; break; } case SFLM_AES192_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes192; break; } case SFLM_AES256_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes256; break; } default: { rc = RC_SET( NE_SFLM_INVALID_ENC_KEY_SIZE); goto Exit; } } algorithm.parameterLen = 0; algorithm.parameter = NULL; /* Set up key attributes */ keyAttr[0].type = NICI_A_KEY_USAGE; keyAttr[0].u.f.hasValue = 1; keyAttr[0].u.f.value = NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT | NICI_F_EXTRACT; keyAttr[0].u.f.valueInfo = 0; keyAttr[1].type = NICI_A_KEY_SIZE; keyAttr[1].u.f.hasValue = 1; keyAttr[1].u.f.value = uiEncKeySize; keyAttr[1].u.f.valueInfo = 0; keyAttr[2].type = NICI_A_GLOBAL; keyAttr[2].u.f.hasValue = 1; keyAttr[2].u.f.value = N_TRUE; keyAttr[2].u.f.valueInfo = 0; /*Generate a AES key */ if (RC_BAD( rc = CCS_GenerateKey( m_hContext, &algorithm, keyAttr, 3, &keySizeChanged, &m_keyHandle, NICI_H_INVALID))) { rc = RC_SET( NE_SFLM_NICI_GENKEY_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } // Generate some IV to use with this key. if (RC_BAD( rc = CCS_GetRandom( m_hContext, (nuint8 *)m_ucIV, IV_SZ))) { rc = RC_SET( NE_SFLM_NICI_BAD_RANDOM); m_hContext = 0; // Context has been destroyed goto Exit; } m_uiEncKeySize = uiEncKeySize; #endif Exit: #ifdef FLM_USE_NICI f_mutexUnlock( m_hMutex); #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: generateEncryptionKey - DES3 *---------------------------------------------------------------------------*/ RCODE F_CCS::generateEncryptionKeyDES3( FLMUINT uiEncKeySize ) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( uiEncKeySize); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ALGORITHM algorithm; NICI_ATTRIBUTE keyAttr[3]; nbool8 keySizeChanged; FLMBYTE oid_des3[] = {IDV_DES_EDE3_CBC_IV8}; f_mutexLock( m_hMutex); // Only one DES3 key size supported. if (uiEncKeySize != SFLM_DES3_168_KEY_SIZE) { rc = RC_SET( NE_SFLM_INVALID_ENC_KEY_SIZE); goto Exit; } /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } /* Set up AES Algorithm*/ algorithm.algorithm = (nuint8 *)oid_des3; algorithm.parameterLen = 0; algorithm.parameter = NULL; /* Set up key attributes */ keyAttr[0].type = NICI_A_KEY_USAGE; keyAttr[0].u.f.hasValue = 1; keyAttr[0].u.f.value = NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT | NICI_F_EXTRACT; keyAttr[0].u.f.valueInfo = 0; keyAttr[1].type = NICI_A_KEY_SIZE; keyAttr[1].u.f.hasValue = 1; keyAttr[1].u.f.value = uiEncKeySize; keyAttr[1].u.f.valueInfo = 0; keyAttr[2].type = NICI_A_GLOBAL; keyAttr[2].u.f.hasValue = 1; keyAttr[2].u.f.value = N_TRUE; keyAttr[2].u.f.valueInfo = 0; /*Generate a AES key */ if (RC_BAD( rc = CCS_GenerateKey( m_hContext, &algorithm, keyAttr, 3, &keySizeChanged, &m_keyHandle, NICI_H_INVALID))) { rc = RC_SET( NE_SFLM_NICI_GENKEY_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } // Generate some IV to use with this key. if (RC_BAD( rc = CCS_GetRandom( m_hContext, (nuint8 *)m_ucIV, IV_SZ))) { rc = RC_SET( NE_SFLM_NICI_BAD_RANDOM); m_hContext = 0; // Context has been destroyed goto Exit; } m_uiEncKeySize = uiEncKeySize; #endif Exit: #ifdef FLM_USE_NICI f_mutexUnlock( m_hMutex); #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: generateWrappingKey *---------------------------------------------------------------------------*/ RCODE F_CCS::generateWrappingKey( FLMUINT uiEncKeySize ) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( uiEncKeySize); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else switch( m_eEncAlgorithm) { case SFLM_AES_ENCRYPTION: { rc = generateWrappingKeyAES( uiEncKeySize); break; } case SFLM_DES3_ENCRYPTION: { rc = generateWrappingKeyDES3( uiEncKeySize); break; } default: { flmAssert( 0); rc = RC_SET( NE_SFLM_NICI_INVALID_ALGORITHM); goto Exit; } } #endif Exit: return rc; } /*----------------------------------------------------------------------------- * Desc: generateWrappingKeyAES - generates an AES wrapping key *---------------------------------------------------------------------------*/ RCODE F_CCS::generateWrappingKeyAES( FLMUINT uiEncKeySize) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( uiEncKeySize); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ALGORITHM algorithm; NICI_ATTRIBUTE keyAttr[6]; nbool8 keySizeChanged; FLMBYTE oid_aes128[] = {IDV_AES128CBC}; FLMBYTE oid_aes192[] = {IDV_AES192CBC}; FLMBYTE oid_aes256[] = {IDV_AES256CBC}; f_mutexLock( m_hMutex); /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } /* Set up AES Algorithm*/ switch (uiEncKeySize) { case SFLM_AES128_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes128; keyAttr[1].u.v.valuePtr = oid_aes128; keyAttr[1].u.v.valueLen = (nuint32)sizeof( oid_aes128); break; } case SFLM_AES192_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes192; keyAttr[1].u.v.valuePtr = oid_aes192; keyAttr[1].u.v.valueLen = (nuint32)sizeof( oid_aes192); break; } case SFLM_AES256_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes256; keyAttr[1].u.v.valuePtr = oid_aes256; keyAttr[1].u.v.valueLen = (nuint32)sizeof( oid_aes256); break; } default: { rc = RC_SET( NE_SFLM_INVALID_ENC_KEY_SIZE); goto Exit; } } algorithm.parameterLen = 0; algorithm.parameter = NULL; /* Set up key attributes */ keyAttr[0].type = NICI_A_KEY_TYPE; keyAttr[0].u.f.hasValue = 1; keyAttr[0].u.f.value = NICI_K_AES; keyAttr[0].u.f.valueInfo = 0; keyAttr[1].type = NICI_A_KEY_FORMAT; keyAttr[1].u.v.valueInfo = 0; keyAttr[2].type = NICI_A_KEY_USAGE; keyAttr[2].u.f.hasValue = 1; keyAttr[2].u.f.value = NICI_F_WRAP | NICI_F_UNWRAP | NICI_F_KM_ENCRYPT | NICI_F_KM_DECRYPT | NICI_F_EXTRACT | NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT; keyAttr[2].u.f.valueInfo = 0; keyAttr[3].type = NICI_A_KEY_SIZE; keyAttr[3].u.f.hasValue = 1; keyAttr[3].u.f.value = uiEncKeySize; keyAttr[3].u.f.valueInfo = 0; keyAttr[4].type = NICI_A_GLOBAL; keyAttr[4].u.f.hasValue = 1; keyAttr[4].u.f.value = N_TRUE; keyAttr[4].u.f.valueInfo = 0; keyAttr[5].type = NICI_A_CLASS; keyAttr[5].u.f.hasValue = 1; keyAttr[5].u.f.value = NICI_O_SECRET_KEY; keyAttr[5].u.f.valueInfo = 0; /*Generate an AES wrapping key */ if (RC_BAD( rc = CCS_GenerateKey( m_hContext, &algorithm, keyAttr, 6, &keySizeChanged, &m_keyHandle, NICI_H_INVALID))) { rc = RC_SET( NE_SFLM_NICI_GENKEY_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } // Generate some IV to use with this key. if (RC_BAD( rc = CCS_GetRandom( m_hContext, (nuint8 *)m_ucIV, IV_SZ))) { rc = RC_SET( NE_SFLM_NICI_BAD_RANDOM); m_hContext = 0; // Context has been destroyed goto Exit; } // If we generated a wrapping key, then this object's key handle is actually a // wrapping key. This means that we will use it to wrap the other keys in the // system. m_bKeyIsWrappingKey = TRUE; m_uiEncKeySize = uiEncKeySize; #endif Exit: #ifdef FLM_USE_NICI f_mutexUnlock( m_hMutex); #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: generateWrappingKeyDES3 - generates a triple DES (DES3) wrapping key *---------------------------------------------------------------------------*/ RCODE F_CCS::generateWrappingKeyDES3( FLMUINT uiEncKeySize) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( uiEncKeySize); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ALGORITHM algorithm; NICI_ATTRIBUTE keyAttr[6]; nbool8 keySizeChanged; FLMBYTE oid_des3[] = {IDV_DES_EDE3_CBC_IV8}; f_mutexLock( m_hMutex); if (uiEncKeySize != SFLM_DES3_168_KEY_SIZE) { rc = RC_SET( NE_SFLM_INVALID_ENC_KEY_SIZE); goto Exit; } /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } /* Set up AES Algorithm*/ algorithm.algorithm = (nuint8 *)oid_des3; algorithm.parameterLen = 0; algorithm.parameter = NULL; /* Set up key attributes */ keyAttr[0].type = NICI_A_KEY_TYPE; keyAttr[0].u.f.hasValue = 1; keyAttr[0].u.f.value = NICI_K_DES3X; keyAttr[0].u.f.valueInfo = 0; keyAttr[1].type = NICI_A_KEY_FORMAT; keyAttr[1].u.v.valuePtr = oid_des3; keyAttr[1].u.v.valueLen = (nuint32)sizeof( oid_des3); keyAttr[1].u.v.valueInfo = 0; keyAttr[2].type = NICI_A_KEY_USAGE; keyAttr[2].u.f.hasValue = 1; keyAttr[2].u.f.value = NICI_F_WRAP | NICI_F_UNWRAP | NICI_F_KM_ENCRYPT | NICI_F_KM_DECRYPT | NICI_F_EXTRACT | NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT; keyAttr[2].u.f.valueInfo = 0; keyAttr[3].type = NICI_A_KEY_SIZE; keyAttr[3].u.f.hasValue = 1; keyAttr[3].u.f.value = uiEncKeySize; keyAttr[3].u.f.valueInfo = 0; keyAttr[4].type = NICI_A_GLOBAL; keyAttr[4].u.f.hasValue = 1; keyAttr[4].u.f.value = N_TRUE; keyAttr[4].u.f.valueInfo = 0; keyAttr[5].type = NICI_A_CLASS; keyAttr[5].u.f.hasValue = 1; keyAttr[5].u.f.value = NICI_O_SECRET_KEY; keyAttr[5].u.f.valueInfo = 0; /*Generate an AES wrapping key */ if (RC_BAD( rc = CCS_GenerateKey( m_hContext, &algorithm, keyAttr, 6, &keySizeChanged, &m_keyHandle, NICI_H_INVALID))) { rc = RC_SET( NE_SFLM_NICI_GENKEY_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } // Generate some IV to use with this key. if (RC_BAD( rc = CCS_GetRandom( m_hContext, (nuint8 *)m_ucIV, IV_SZ))) { rc = RC_SET( NE_SFLM_NICI_BAD_RANDOM); m_hContext = 0; // Context has been destroyed goto Exit; } // If we generated a wrapping key, then this object's key handle is actually a // wrapping key. This means that we will use it to wrap the other keys in the // system. m_bKeyIsWrappingKey = TRUE; m_uiEncKeySize = uiEncKeySize; #endif Exit: #ifdef FLM_USE_NICI f_mutexUnlock( m_hMutex); #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: encryptToStore (public) *---------------------------------------------------------------------------*/ RCODE F_CCS::encryptToStore( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen, FLMBYTE * pucIV) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); F_UNREFERENCED_PARM( pucIV); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else switch (m_eEncAlgorithm) { case SFLM_AES_ENCRYPTION: { rc = encryptToStoreAES( pucIn, uiInLen, pucOut, puiOutLen, pucIV); break; } case SFLM_DES3_ENCRYPTION: { rc = encryptToStoreDES3( pucIn, uiInLen, pucOut, puiOutLen, pucIV); break; } default: { flmAssert( 0); rc = RC_SET( NE_SFLM_NICI_INVALID_ALGORITHM); goto Exit; } } #endif Exit: return rc; } /*----------------------------------------------------------------------------- * Desc: decryptFromStore (public) *---------------------------------------------------------------------------*/ RCODE F_CCS::decryptFromStore( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen, FLMBYTE * pucIV) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); F_UNREFERENCED_PARM( pucIV); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else switch( m_eEncAlgorithm) { case SFLM_AES_ENCRYPTION: { rc = decryptFromStoreAES( pucIn, uiInLen, pucOut, puiOutLen, pucIV); break; } case SFLM_DES3_ENCRYPTION: { rc = decryptFromStoreDES3( pucIn, uiInLen, pucOut, puiOutLen, pucIV); break; } default: { flmAssert( 0); rc = RC_SET( NE_SFLM_NICI_INVALID_ALGORITHM); goto Exit; } } #endif Exit: return rc; } /*----------------------------------------------------------------------------- * Desc: encryptToStore - Using AES *---------------------------------------------------------------------------*/ RCODE F_CCS::encryptToStoreAES( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen, FLMBYTE * pucIV) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); F_UNREFERENCED_PARM( pucIV); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_aes128[] = {IDV_AES128CBC}; FLMBYTE oid_aes192[] = {IDV_AES192CBC}; FLMBYTE oid_aes256[] = {IDV_AES256CBC}; f_mutexLock( m_hMutex); /* Create NICI Context*/ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } switch (m_uiEncKeySize) { case SFLM_AES128_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes128; break; } case SFLM_AES192_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes192; break; } case SFLM_AES256_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes256; break; } default: { rc = RC_SET( NE_SFLM_INVALID_ENC_KEY_SIZE); goto Exit; } } algorithm.parameterLen = sizeof(algorithm.parameter->parms[0])+ sizeof(algorithm.parameter->count); algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; if (pucIV) { algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)pucIV; } else { algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)m_ucIV; } algorithm.parameter->parms[0].u.b.len = IV_SZ; /* init encryption */ if (RC_BAD( rc = CCS_DataEncryptInit( m_hContext, &algorithm, m_keyHandle))) { rc = RC_SET_AND_ASSERT( NE_SFLM_NICI_ENC_INIT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } if (RC_BAD( rc = CCS_Encrypt( m_hContext, (nuint8 *)pucIn, uiInLen, (nuint8 *)pucOut, puiOutLen))) { rc = RC_SET( NE_SFLM_NICI_ENCRYPT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } #endif Exit: #ifdef FLM_USE_NICI f_mutexUnlock( m_hMutex); #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: decryptFromStore - using the AES algorithm *---------------------------------------------------------------------------*/ RCODE F_CCS::decryptFromStoreAES( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen, FLMBYTE * pucIV) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); F_UNREFERENCED_PARM( pucIV); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_aes128[] = {IDV_AES128CBC}; FLMBYTE oid_aes192[] = {IDV_AES192CBC}; FLMBYTE oid_aes256[] = {IDV_AES256CBC}; f_mutexLock( m_hMutex); /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } switch (m_uiEncKeySize) { case SFLM_AES128_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes128; break; } case SFLM_AES192_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes192; break; } case SFLM_AES256_KEY_SIZE: { algorithm.algorithm = (nuint8 *)oid_aes256; break; } default: { rc = RC_SET( NE_SFLM_INVALID_ENC_KEY_SIZE); goto Exit; } } algorithm.parameterLen = sizeof(algorithm.parameter->parms[0])+ sizeof(algorithm.parameter->count); algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; if (pucIV) { algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)pucIV; } else { algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)m_ucIV; } algorithm.parameter->parms[0].u.b.len = IV_SZ; /* 16-byte IV */ /* init encryption */ if (RC_BAD( rc = CCS_DataDecryptInit( m_hContext, &algorithm, m_keyHandle))) { rc = RC_SET( NE_SFLM_NICI_DECRYPT_INIT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } if (RC_BAD( rc = CCS_Decrypt( m_hContext, (nuint8 *)pucIn, uiInLen, (nuint8 *)pucOut, puiOutLen))) { rc = RC_SET( NE_SFLM_NICI_DECRYPT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } #endif Exit: #ifdef FLM_USE_NICI f_mutexUnlock( m_hMutex); #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: encryptToStore - Using DES3 *---------------------------------------------------------------------------*/ RCODE F_CCS::encryptToStoreDES3( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen, FLMBYTE * pucIV) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); F_UNREFERENCED_PARM( pucIV); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_des3[] = {IDV_DES_EDE3_CBC_IV8}; f_mutexLock( m_hMutex); /* Create NICI Context*/ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } algorithm.algorithm = (nuint8 *)oid_des3; algorithm.parameterLen = sizeof(algorithm.parameter->parms[0])+ sizeof(algorithm.parameter->count); algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; if (pucIV) { algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)pucIV; } else { algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)m_ucIV; } algorithm.parameter->parms[0].u.b.len = IV_SZ8; /* 8-byte IV */ /* init encryption */ if (RC_BAD( rc = CCS_DataEncryptInit(m_hContext, &algorithm, m_keyHandle))) { rc = RC_SET_AND_ASSERT( NE_SFLM_NICI_ENC_INIT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } if (RC_BAD( rc = CCS_Encrypt( m_hContext, (nuint8 *)pucIn, uiInLen, (nuint8 *)pucOut, puiOutLen))) { rc = RC_SET( NE_SFLM_NICI_ENCRYPT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } #endif Exit: #ifdef FLM_USE_NICI f_mutexUnlock( m_hMutex); #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: decryptFromStore - using the Triple DES (DES3) algorithm *---------------------------------------------------------------------------*/ RCODE F_CCS::decryptFromStoreDES3( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen, FLMBYTE * pucIV) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); F_UNREFERENCED_PARM( pucIV); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_des3[] = {IDV_DES_EDE3_CBC_IV8}; f_mutexLock( m_hMutex); /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } /*Set up alogrithm now to do triple des decryption */ algorithm.algorithm = (nuint8 *)oid_des3; algorithm.parameterLen = sizeof(algorithm.parameter->parms[0])+ sizeof(algorithm.parameter->count); algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; if (pucIV) { algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)pucIV; } else { algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)m_ucIV; } algorithm.parameter->parms[0].u.b.len = IV_SZ8; /* 8-byte IV */ /* init encryption */ if (RC_BAD( rc = CCS_DataDecryptInit( m_hContext, &algorithm, m_keyHandle))) { rc = RC_SET( NE_SFLM_NICI_DECRYPT_INIT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } if (RC_BAD( rc = CCS_Decrypt( m_hContext, (nuint8 *)pucIn, uiInLen, (nuint8 *)pucOut, puiOutLen))) { rc = RC_SET( NE_SFLM_NICI_DECRYPT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } #endif Exit: #ifdef FLM_USE_NICI f_mutexUnlock( m_hMutex); #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: init - Initialize the context. *---------------------------------------------------------------------------*/ RCODE F_CCS::init( FLMBOOL bKeyIsWrappingKey, eEncAlgorithm eEncAlg) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( bKeyIsWrappingKey); F_UNREFERENCED_PARM( eEncAlg); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else FLMBOOL bLocked = FALSE; if (m_bInitCalled) { rc = RC_SET_AND_ASSERT( NE_SFLM_ILLEGAL_OP); goto Exit; } m_bKeyIsWrappingKey = bKeyIsWrappingKey; if (eEncAlg != SFLM_AES_ENCRYPTION && eEncAlg != SFLM_DES3_ENCRYPTION) { flmAssert( 0); rc = RC_SET( NE_SFLM_INVALID_ENC_ALGORITHM); goto Exit; } m_eEncAlgorithm = eEncAlg; // Create a mutex to control access to the nici operations. if (RC_BAD( rc = f_mutexCreate( &m_hMutex))) { goto Exit; } f_mutexLock( m_hMutex); bLocked = TRUE; // Create NICI Context if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } else { flmAssert( 0); // Should not have a context yet! } // Generate the Random IV if (RC_BAD( rc = CCS_GetRandom( m_hContext, (nuint8 *)&m_ucRndIV, IV_SZ))) { rc = RC_SET( NE_SFLM_NICI_BAD_RANDOM); m_hContext = 0; // Context has been destroyed goto Exit; } // Generate an adjustment factor for the IV if (RC_BAD( rc = CCS_GetRandom( m_hContext, (nuint8 *)&m_uiIVFactor, sizeof(FLMUINT)))) { rc = RC_SET( NE_SFLM_NICI_BAD_RANDOM); m_hContext = 0; // Context has been destroyed goto Exit; } m_bInitCalled = TRUE; #endif Exit: #ifdef FLM_USE_NICI if (bLocked) { f_mutexUnlock( m_hMutex); } #endif return rc; } /*----------------------------------------------------------------------------- * Desc: selectWrappingKey - pick a wrapping key that we can use to wrap & * unwrap the encryption key with. *---------------------------------------------------------------------------*/ RCODE F_CCS::getWrappingKey( NICI_OBJECT_HANDLE * pWrappingKeyHandle) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pWrappingKeyHandle); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ATTRIBUTE find[2]; FLMUINT uiCount; f_mutexLock( m_hMutex); /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } find[0].type = NICI_A_GLOBAL; find[0].u.f.hasValue = 1; find[0].u.f.value = 1; find[0].u.f.valueInfo = 0; find[1].type = NICI_A_FEATURE; find[1].u.f.hasValue = 1; find[1].u.f.value = NICI_AV_STORAGE; find[1].u.f.valueInfo = 0; if (RC_BAD( rc = CCS_FindObjectsInit(m_hContext, find, 2))) { rc = RC_SET( NE_SFLM_NICI_FIND_INIT); m_hContext = 0; // Context has been destroyed goto Exit; } uiCount = 1; if (RC_BAD( rc = CCS_FindObjects( m_hContext, pWrappingKeyHandle, &uiCount))) { rc = RC_SET( NE_SFLM_NICI_FIND_OBJECT); m_hContext = 0; // Context has been destroyed goto Exit; } if (uiCount < 1) { rc = RC_SET( NE_SFLM_NICI_WRAPKEY_NOT_FOUND); goto Exit; } #endif Exit: #ifdef FLM_USE_NICI f_mutexUnlock( m_hMutex); #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: getKeyToStore - Function used to obtain the key information in the * format that will be stored on disk. A buffer will be allocated by this * function that **MUST** be freed when no longer needed. *---------------------------------------------------------------------------*/ RCODE F_CCS::getKeyToStore( FLMBYTE ** ppucKeyInfo, FLMUINT32 * pui32BufLen, FLMBYTE * pszEncKeyPasswd, F_CCS * pWrappingCcs) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( ppucKeyInfo); F_UNREFERENCED_PARM( pui32BufLen); F_UNREFERENCED_PARM( pszEncKeyPasswd); F_UNREFERENCED_PARM( pWrappingCcs); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else FLMBYTE * pucTmp = NULL; FLMBYTE * pucPtr = NULL; FLMUINT32 ui32PaddedLength; FLMBYTE * pucWrappedKey = NULL; FLMUINT32 ui32WrappedKeyLen = 0; FLMBYTE * pszFormattedEncKeyPasswd = NULL; NICI_OBJECT_HANDLE wrappingKeyHandle = 0; *ppucKeyInfo = NULL; *pui32BufLen = 0; if (pWrappingCcs) { flmAssert(m_bKeyIsWrappingKey == FALSE); wrappingKeyHandle = pWrappingCcs->m_keyHandle; } else if (!pszEncKeyPasswd) { flmAssert( m_bKeyIsWrappingKey); } // Either extract the key or wrap the key. if (pszEncKeyPasswd && pszEncKeyPasswd[0]) { // The password that is passed in to CCS_pbeEncrypt is NOT actually // unicode. It must be treated as a sequence of bytes that that is // terminated with 2 nulls and has an even length. If we treat it // as unicode, then we'll have endian issues if we move the database // to machines with different byte ordering. if (RC_BAD( rc = f_calloc( f_strlen(pszEncKeyPasswd) + (f_strlen(pszEncKeyPasswd) % 2) + 2, &pszFormattedEncKeyPasswd))) { goto Exit; } f_strcpy( pszFormattedEncKeyPasswd, pszEncKeyPasswd); if (RC_BAD( rc = extractKey( &pucWrappedKey, &ui32WrappedKeyLen, (FLMUNICODE *)pszFormattedEncKeyPasswd))) { goto Exit; } } else { if (RC_BAD( rc = wrapKey( &pucWrappedKey, &ui32WrappedKeyLen, wrappingKeyHandle))) { goto Exit; } } // The shrouded or wrapped key will be stored in m_pKey. ui32PaddedLength = (ui32WrappedKeyLen + sizeof( FLMBOOL) + sizeof (FLMUINT32) + IV_SZ ); // Make sure our buffer size is padded to a 16 byte boundary. if ((ui32PaddedLength % 16) != 0) { ui32PaddedLength += (16 - (ui32PaddedLength % 16)); } // Add one extra byte for a NULL terminator if (RC_BAD(rc = f_alloc( ui32PaddedLength + 1, &pucTmp))) { goto Exit; } if ( !m_hContext) { if (CCS_CreateContext( 0, &m_hContext)) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } pucPtr = pucTmp; // Save a flag indicating whether the key is wrapped or encoded in // a password. UD2FBA( (pszEncKeyPasswd && pszEncKeyPasswd[0]) ? (FLMUINT)TRUE : (FLMUINT)FALSE, pucPtr); pucPtr += sizeof(FLMBOOL); // Copy the key length. UD2FBA(ui32WrappedKeyLen, pucPtr); pucPtr += sizeof(FLMUINT32); // Copy the IV too. f_memcpy( pucPtr, m_ucIV, IV_SZ); pucPtr += IV_SZ; // Copy the wrapped key value f_memcpy( pucPtr, pucWrappedKey, ui32WrappedKeyLen); pucPtr += ui32WrappedKeyLen; // Fill the remainder of the buffer with random data. if (CCS_GetRandom(m_hContext, (nuint8 *)pucPtr, ((FLMUINT)pucTmp + ui32PaddedLength) - (FLMUINT)pucPtr)) { rc = RC_SET( NE_SFLM_NICI_BAD_RANDOM); m_hContext = 0; // Context has been destroyed goto Exit; } pucTmp[ ui32PaddedLength] = '\0'; *ppucKeyInfo = pucTmp; *pui32BufLen = ui32PaddedLength; pucTmp = NULL; #endif Exit: #ifdef FLM_USE_NICI if (pucTmp) { f_free(&pucTmp); } if (pucWrappedKey) { f_free( &pucWrappedKey); } if (pszFormattedEncKeyPasswd) { f_free( &pszFormattedEncKeyPasswd); } #endif return rc; } /*----------------------------------------------------------------------------- * Desc: setKeyFromStore - Function used to set the key info using the binary * key stored on the disk. *---------------------------------------------------------------------------*/ RCODE F_CCS::setKeyFromStore( FLMBYTE * pucKeyInfo, FLMBYTE * pszEncKeyPasswd, F_CCS * pWrappingCcs) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucKeyInfo); F_UNREFERENCED_PARM( pszEncKeyPasswd); F_UNREFERENCED_PARM( pWrappingCcs); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else FLMBYTE * pucTmp = pucKeyInfo; FLMBYTE * pucBuffer = NULL; FLMBOOL bShrouded = FALSE; FLMUINT32 ui32Length; FLMBYTE * pucKeyBuf = NULL; FLMBYTE * pszFormattedEncKeyPasswd = NULL; NICI_OBJECT_HANDLE wrappingKeyHandle = 0; if (pWrappingCcs) { flmAssert(m_bKeyIsWrappingKey == FALSE); wrappingKeyHandle = pWrappingCcs->m_keyHandle; } // Extract the fields from the buffer // Is the key shrouded? bShrouded = FB2UD( pucTmp); pucTmp += sizeof(FLMUINT); // Actual length - note that the passed buffer is padded to 16 byte boundary. ui32Length = FB2UD( pucTmp); pucTmp += sizeof(FLMUINT32); // Get the IV f_memcpy( m_ucIV, pucTmp, IV_SZ); pucTmp += IV_SZ; // Need another temporary buffer to hold the encrypted / shrouded key. if (RC_BAD( rc = f_alloc( ui32Length, &pucBuffer))) { goto Exit; } f_memcpy( pucBuffer, pucTmp, ui32Length); if (bShrouded) { if (pszEncKeyPasswd == NULL || pszEncKeyPasswd[0] == '\0') { rc = RC_SET( NE_SFLM_EXPECTING_PASSWORD); goto Exit; } // The password that is passed in to CCS_pbeDecrypt is NOT actually // unicode. It must be treated as a sequence of bytes that that is // terminated with 2 nulls and has an even length. If we treat it // as unicode, then we'll have endian issues if we move the database // to machines with different byte ordering. if (RC_BAD( rc = f_calloc( f_strlen(pszEncKeyPasswd) + (f_strlen(pszEncKeyPasswd) % 2) + 2, &pszFormattedEncKeyPasswd))) { goto Exit; } f_strcpy( pszFormattedEncKeyPasswd, pszEncKeyPasswd); // Unshroud the key using the password. // Key handle is always kept in m_keyHandle. if (RC_BAD( rc = injectKey( pucBuffer, ui32Length, (FLMUNICODE *)pszFormattedEncKeyPasswd))) { goto Exit; } } else { if (pszEncKeyPasswd) { if ( pszEncKeyPasswd[0] != '\0') { rc = RC_SET( NE_SFLM_NOT_EXPECTING_PASSWORD); goto Exit; } } // Unwrap the key. The Key handle is always store in m_keyHandle. if (RC_BAD( rc = unwrapKey( pucBuffer, ui32Length, wrappingKeyHandle))) { goto Exit; } } m_bKeyVerified = TRUE; #endif Exit: #ifdef FLM_USE_NICI if (pucBuffer) { f_free( &pucBuffer); } if (pucKeyBuf) { f_free( &pucKeyBuf); } if (pszFormattedEncKeyPasswd) { f_free( &pszFormattedEncKeyPasswd); } #endif return rc; } typedef struct { FLMUINT uiKeyType; FLMUINT uiFormatLen; FLMUINT uiKeyLen; FLMUINT uiKeySize; } EXTRACTED_KEY; /*----------------------------------------------------------------------------- * Desc: extractKey - Extract the key by encrypting it in a supplied password. The * buffer ppucExtractedKey buffer is allocated and returned, thus *MUST* be released * after it is no longer needed. *---------------------------------------------------------------------------*/ RCODE F_CCS::extractKey( FLMBYTE ** ppucExtractedKey, FLMUINT32 * pui32Length, FLMUNICODE * puzEncKeyPasswd) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( ppucExtractedKey); F_UNREFERENCED_PARM( pui32Length); F_UNREFERENCED_PARM( puzEncKeyPasswd); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ALGORITHM algorithm; NICI_ATTRIBUTE keyAttr[2]; NICI_ATTRIBUTE attr[2]; FLMBYTE oid_sha1[] = {IDV_SHA1}; FLMBYTE oid_pbe[] = {IDV_pbeWithSHA1And3Key3xDES_CBC}; FLMBYTE ucDigest[ 20]; FLMUINT uiDigestLen = sizeof(ucDigest); FLMUINT uiBufferSize; FLMBYTE * pucKey = NULL; FLMBYTE * pucFormat = NULL; EXTRACTED_KEY * pExtractedKey = NULL; FLMUINT uiEncLen; FLMBYTE * pTemp = NULL; NICI_PARAMETER_INFO * pParmInfo; FLMBYTE * pucSalt; FLMUINT uiAllocSize; FLMUINT uiIndx; FLMBYTE * pucTempPtr; f_mutexLock( m_hMutex); /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } f_memset( &attr[0], 0, sizeof(NICI_ATTRIBUTE) * 2); attr[0].type = NICI_A_KEY_TYPE; attr[1].type = NICI_A_KEY_FORMAT; if (RC_BAD( rc = CCS_GetAttributeValue( m_hContext, m_keyHandle, &attr[0], 2))) { rc = RC_SET( NE_SFLM_NICI_ATTRIBUTE_VALUE); m_hContext = 0; // Context has been destroyed goto Exit; } if (!attr[0].u.f.hasValue) { rc = RC_SET( NE_SFLM_NICI_BAD_ATTRIBUTE); goto Exit; } f_memset( &keyAttr[0], 0, sizeof(NICI_ATTRIBUTE) * 2); switch (attr[0].u.f.value) { case NICI_K_AES: { uiIndx = 0; keyAttr[uiIndx].type = NICI_A_KEY_VALUE; switch (m_uiEncKeySize) { case SFLM_AES128_KEY_SIZE: { keyAttr[uiIndx].u.v.valueLen = 16; break; } case SFLM_AES192_KEY_SIZE: { keyAttr[uiIndx].u.v.valueLen = 24; break; } case SFLM_AES256_KEY_SIZE: { keyAttr[uiIndx].u.v.valueLen = 32; break; } } uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_FORMAT; keyAttr[uiIndx].u.v.valueLen = attr[1].u.v.valueLen; break; } case NICI_K_DES3X: { uiIndx = 0; keyAttr[uiIndx].type = NICI_A_KEY_VALUE; keyAttr[uiIndx].u.v.valueLen = 24; uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_FORMAT; keyAttr[uiIndx].u.v.valueLen = attr[1].u.v.valueLen; break; } case NICI_K_DES: { uiIndx = 0; keyAttr[uiIndx].type = NICI_A_KEY_VALUE; keyAttr[uiIndx].u.v.valueLen = 8; uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_FORMAT; keyAttr[uiIndx].u.v.valueLen = attr[1].u.v.valueLen; break; } default: { flmAssert( 0); rc = RC_SET( NE_SFLM_NICI_INVALID_ALGORITHM); goto Exit; } } // Make one allocation that we can then use to hold several different things. uiBufferSize = sizeof( EXTRACTED_KEY) + // pExtractedKey attr[1].u.v.valueLen + // pucFormat keyAttr[0].u.v.valueLen + // pucKey sizeof (ucDigest); // pucDigest uiAllocSize = uiBufferSize + SALT_SZ + // Salt (not encrypted) (sizeof(NICI_PARAMETER_DATA) * 2) + sizeof(FLMUINT32); // Parameter data (not encrypted) // Make sure the allocation size is on a 8 byte boundary if( (uiAllocSize % 8) != 0) { uiAllocSize += (8 - (uiAllocSize % 8)); } if (RC_BAD( rc = f_calloc( uiAllocSize, &pExtractedKey))) { goto Exit; } keyAttr[1].u.v.valuePtr = &pExtractedKey[1]; pucFormat = (FLMBYTE *)keyAttr[1].u.v.valuePtr; keyAttr[0].u.v.valuePtr = pucFormat + attr[1].u.v.valueLen; pucKey = (FLMBYTE *)keyAttr[0].u.v.valuePtr; pucSalt = (FLMBYTE *)pExtractedKey + uiBufferSize; pParmInfo = (NICI_PARAMETER_INFO *)(pucSalt + SALT_SZ); // Make sure that pParmInfo is 8 byte alligned. if ((FLMUINT)pParmInfo % 8) { FLMBYTE * pucTemp = (FLMBYTE *)pParmInfo + (8 - ((FLMUINT)pParmInfo % 8)); pParmInfo = (NICI_PARAMETER_INFO *)pucTemp; } // Extracted the key value now if (RC_BAD( rc = CCS_ExtractKey( m_hContext, m_keyHandle, &keyAttr[0], 2))) { rc = RC_SET( NE_SFLM_EXTRACT_KEY_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } // Calculate a SHA1 checksum. algorithm.algorithm = (nuint8 *)oid_sha1; algorithm.parameter = NULL; algorithm.parameterLen = 0; if (RC_BAD( rc = CCS_DigestInit( m_hContext, &algorithm))) { rc = RC_SET( NE_SFLM_DIGEST_INIT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } if (RC_BAD( rc = CCS_Digest( m_hContext, (nuint8 *)pucFormat, keyAttr[0].u.v.valueLen + attr[1].u.v.valueLen, (nuint8 *)ucDigest, &uiDigestLen))) { rc = RC_SET( NE_SFLM_DIGEST_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } flmAssert( uiDigestLen == sizeof( ucDigest)); pucTempPtr = (FLMBYTE *)pExtractedKey; UD2FBA( attr[0].u.f.value, pucTempPtr); //pExtractedKey->uiKeyType = attr[0].u.f.value; pucTempPtr += 4; UD2FBA( attr[1].u.v.valueLen, pucTempPtr); //pExtractedKey->uiFormatLen = attr[1].u.v.valueLen; pucTempPtr += 4; UD2FBA( keyAttr[0].u.v.valueLen, pucTempPtr); //pExtractedKey->uiKeyLen = keyAttr[0].u.v.valueLen; pucTempPtr += 4; UD2FBA( m_uiEncKeySize, pucTempPtr); // pEncKey->uiKeySize = m_uiEncKeySize; // Point to the Digest... pTemp = (FLMBYTE *)&pExtractedKey[1] + attr[1].u.v.valueLen + // Format length keyAttr[0].u.v.valueLen; // Key length f_memcpy( pTemp, ucDigest, uiDigestLen); // Generate some salt. if (RC_BAD( rc = CCS_GetRandom( m_hContext, (nuint8 *)pucSalt, SALT_SZ))) { rc = RC_SET( NE_SFLM_NICI_BAD_RANDOM); m_hContext = 0; // Context has been destroyed pTemp = NULL; // don't want this to be freed goto Exit; } // This buffer needs to be a separate allocation because it is returned to the caller. We will // be returning the value of the SALT with the encrypted key. The call to CCS_pbeEncrypt // may return an extra 8 bytes. if (RC_BAD( rc = f_alloc( uiBufferSize + SALT_SZ + 8, &pTemp))) { goto Exit; } // Now to encrypt the buffer. algorithm.algorithm = (nuint8 *)oid_pbe; pParmInfo->count = 2; // Two parameters pParmInfo->parms[0].parmType = NICI_P_SALT; pParmInfo->parms[0].u.b.len = SALT_SZ; pParmInfo->parms[0].u.b.ptr = (nuint8 *)pucSalt; pParmInfo->parms[1].parmType = NICI_P_COUNT; pParmInfo->parms[1].u.value = SALT_COUNT; algorithm.parameter = pParmInfo; algorithm.parameterLen = sizeof(NICI_PARAMETER_DATA) * 2 + sizeof(FLMUINT32); uiEncLen = uiBufferSize + 8; if (RC_BAD( rc = CCS_pbeEncrypt( m_hContext, &algorithm, puzEncKeyPasswd, (nuint8 *)pExtractedKey, uiBufferSize, (nuint8 *)pTemp, &uiEncLen))) { rc = RC_SET( NE_SFLM_PBE_ENCRYPT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } *ppucExtractedKey = pTemp; // Now add the salt to the end of the buffer. pTemp += uiEncLen; f_memcpy( pTemp, pucSalt, SALT_SZ); pTemp = NULL; *pui32Length = uiEncLen + SALT_SZ; #endif Exit: #ifdef FLM_USE_NICI if (pTemp) { f_free( &pTemp); } if (pucKey) { f_free( &pExtractedKey); } f_mutexUnlock( m_hMutex); #endif return(rc); } /*----------------------------------------------------------------------------- * Desc: injectKey - Inject the encrypting key using the supplied password. *---------------------------------------------------------------------------*/ RCODE F_CCS::injectKey( FLMBYTE * pszExtractedKey, FLMUINT32 ui32Length, FLMUNICODE * puzEncKeyPasswd) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pszExtractedKey); F_UNREFERENCED_PARM( ui32Length); F_UNREFERENCED_PARM( puzEncKeyPasswd); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ALGORITHM algorithm; NICI_ATTRIBUTE keyAttr[7]; FLMBYTE oid_sha1[] = {IDV_SHA1}; FLMBYTE oid_pbe[] = {IDV_pbeWithSHA1And3Key3xDES_CBC}; FLMUINT uiIndx; FLMBYTE ucDigest[ 20]; FLMUINT uiDigestLen = sizeof(ucDigest); FLMBYTE * pKey; FLMBYTE * pucFormat; EXTRACTED_KEY * pExtractedKey; FLMUINT uiEncLen; FLMBYTE * pTemp; FLMBYTE * pucBuffer = NULL; FLMBYTE * pucSalt; FLMUINT uiAllocSize; NICI_PARAMETER_INFO * pParmInfo = NULL; FLMBYTE * pucTempPtr; f_mutexLock( m_hMutex); /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } // Extract the SALT from the key buffer. pucSalt = pszExtractedKey + (ui32Length - SALT_SZ); ui32Length -= SALT_SZ; // Make one allocation and point into it for the different buffers we need. uiAllocSize = ui32Length + sizeof(NICI_PARAMETER_DATA) * 2 + sizeof(FLMUINT32); if (RC_BAD( rc = f_calloc( uiAllocSize, &pucBuffer))) { goto Exit; } pParmInfo = (NICI_PARAMETER_INFO *)(pucBuffer + ui32Length); // Now to decrypt the buffer. algorithm.algorithm = (nuint8 *)oid_pbe; pParmInfo->count = 2; // Two parameters pParmInfo->parms[0].parmType = NICI_P_SALT; pParmInfo->parms[0].u.b.len = SALT_SZ; pParmInfo->parms[0].u.b.ptr = (nuint8 *)pucSalt; pParmInfo->parms[1].parmType = NICI_P_COUNT; pParmInfo->parms[1].u.value = SALT_COUNT; algorithm.parameter = pParmInfo; algorithm.parameterLen = sizeof(NICI_PARAMETER_DATA) * 2 + sizeof(FLMUINT32); uiEncLen = ui32Length; if (RC_BAD( rc = CCS_pbeDecrypt( m_hContext, &algorithm, puzEncKeyPasswd, (nuint8 *)pszExtractedKey, ui32Length, (nuint8 *)pucBuffer, &uiEncLen))) { rc = RC_SET( NE_SFLM_PBE_DECRYPT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } // For cross platform compatibility, we need to first extract the KeyType, // FormatLen and KeyLen values then we will set them back again. They are // stored in a specific byte order, which may not match the native order for // referencing integers on the local platform. pExtractedKey = (EXTRACTED_KEY *)pucBuffer; pucTempPtr = pucBuffer; pExtractedKey->uiKeyType = FB2UD( pucTempPtr); pucTempPtr += 4; pExtractedKey->uiFormatLen = FB2UD( pucTempPtr); pucTempPtr += 4; pExtractedKey->uiKeyLen = FB2UD( pucTempPtr); pucTempPtr += 4; m_uiEncKeySize = FB2UD( pucTempPtr); // Calculate a SHA1 checksum. algorithm.algorithm = (nuint8 *)oid_sha1; algorithm.parameter = NULL; algorithm.parameterLen = 0; if (RC_BAD( rc = CCS_DigestInit( m_hContext, &algorithm))) { rc = RC_SET( NE_SFLM_DIGEST_INIT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } pTemp = (FLMBYTE *)&pExtractedKey[ 1]; if (RC_BAD( rc = CCS_Digest( m_hContext, (nuint8 *)pTemp, pExtractedKey->uiFormatLen + pExtractedKey->uiKeyLen, (nuint8 *)ucDigest, &uiDigestLen))) { rc = RC_SET( NE_SFLM_DIGEST_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } flmAssert( uiDigestLen == sizeof( ucDigest)); // Now compare the two digests. They must be equal! pTemp += pExtractedKey->uiKeyLen + pExtractedKey->uiFormatLen; if (f_memcmp( pTemp, ucDigest, uiDigestLen)) { rc = RC_SET( NE_SFLM_INVALID_ENCKEY_CRC); goto Exit; } pucFormat = (FLMBYTE *)&pExtractedKey[1]; // Point to the format pKey = pucFormat + pExtractedKey->uiFormatLen; // Point to the key. uiIndx = 0; f_memset( &keyAttr[0], 0, sizeof(NICI_ATTRIBUTE) * 7); switch (pExtractedKey->uiKeyType) { case NICI_K_AES: { /* Set key attributes */ uiIndx = 0; keyAttr[uiIndx].type = NICI_A_KEY_TYPE; keyAttr[uiIndx].u.f.hasValue = 1; keyAttr[uiIndx].u.f.value = NICI_K_AES; keyAttr[uiIndx].u.f.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_FORMAT; keyAttr[uiIndx].u.v.valuePtr = pucFormat; keyAttr[uiIndx].u.v.valueLen = pExtractedKey->uiFormatLen; keyAttr[uiIndx].u.v.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_USAGE; keyAttr[uiIndx].u.f.hasValue = 1; keyAttr[uiIndx].u.f.value = NICI_F_WRAP | NICI_F_UNWRAP | NICI_F_KM_ENCRYPT | NICI_F_KM_DECRYPT | NICI_F_EXTRACT | NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT; keyAttr[uiIndx].u.f.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_SIZE; keyAttr[uiIndx].u.f.hasValue = 1; keyAttr[uiIndx].u.f.value = m_uiEncKeySize; keyAttr[uiIndx].u.f.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_VALUE; keyAttr[uiIndx].u.v.valuePtr = pKey; keyAttr[uiIndx].u.v.valueLen = pExtractedKey->uiKeyLen; keyAttr[uiIndx].u.v.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_CLASS; keyAttr[uiIndx].u.f.hasValue = 1; keyAttr[uiIndx].u.f.value = NICI_O_SECRET_KEY; keyAttr[uiIndx].u.f.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_GLOBAL; keyAttr[uiIndx].u.f.hasValue = 1; keyAttr[uiIndx].u.f.value = N_TRUE; keyAttr[uiIndx].u.f.valueInfo = 0; break; } case NICI_K_DES3X: { /* Set key attributes */ uiIndx = 0; keyAttr[uiIndx].type = NICI_A_KEY_TYPE; keyAttr[uiIndx].u.f.hasValue = 1; keyAttr[uiIndx].u.f.value = NICI_K_DES3X; keyAttr[uiIndx].u.f.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_FORMAT; keyAttr[uiIndx].u.v.valuePtr = pucFormat; keyAttr[uiIndx].u.v.valueLen = pExtractedKey->uiFormatLen; keyAttr[uiIndx].u.v.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_USAGE; keyAttr[uiIndx].u.f.hasValue = 1; keyAttr[uiIndx].u.f.value = NICI_F_WRAP | NICI_F_UNWRAP | NICI_F_KM_ENCRYPT | NICI_F_KM_DECRYPT | NICI_F_EXTRACT | NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT; keyAttr[uiIndx].u.f.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_SIZE; keyAttr[uiIndx].u.f.hasValue = 1; keyAttr[uiIndx].u.f.value = m_uiEncKeySize; keyAttr[uiIndx].u.f.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_KEY_VALUE; keyAttr[uiIndx].u.v.valuePtr = pKey; keyAttr[uiIndx].u.v.valueLen = pExtractedKey->uiKeyLen; keyAttr[uiIndx].u.v.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_CLASS; keyAttr[uiIndx].u.f.hasValue = 1; keyAttr[uiIndx].u.f.value = NICI_O_SECRET_KEY; keyAttr[uiIndx].u.f.valueInfo = 0; uiIndx++; keyAttr[uiIndx].type = NICI_A_GLOBAL; keyAttr[uiIndx].u.f.hasValue = 1; keyAttr[uiIndx].u.f.value = N_TRUE; keyAttr[uiIndx].u.f.valueInfo = 0; break; } default: { flmAssert( 0); rc = RC_SET( NE_SFLM_NICI_INVALID_ALGORITHM); goto Exit; } } if (RC_BAD( rc = CCS_InjectKey( m_hContext, &keyAttr[0], 7, &m_keyHandle))) { rc = RC_SET( NE_SFLM_INJECT_KEY_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } #endif Exit: #ifdef FLM_USE_NICI if (pucBuffer) { f_free( &pucBuffer); } f_mutexUnlock( m_hMutex); #endif return(rc); } /**************************************************************************** Desc: getIVLen returns the correct length of the IV for the type of algorithm. ****************************************************************************/ FLMUINT F_CCS::getIVLen() { #ifndef FLM_USE_NICI return 0; #else switch (m_eEncAlgorithm) { case SFLM_AES_ENCRYPTION: return IV_SZ; case SFLM_DES3_ENCRYPTION: return IV_SZ8; default: return 0; } #endif } /**************************************************************************** Desc: generateIV will generate a random set of bytes to be used as IV. ****************************************************************************/ RCODE F_CCS::generateIV( FLMUINT uiIVLen, FLMBYTE * pucIV) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( uiIVLen); F_UNREFERENCED_PARM( pucIV); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else FLMUINT uiLoop; NICI_ALGORITHM algorithm; FLMBYTE oid_sha1[] = {IDV_SHA1}; FLMBOOL bLocked = FALSE; FLMBYTE * pucIVPtr = m_ucRndIV; FLMBYTE ucIVBuffer[ IV_SZ * 2]; FLMUINT uiIVBufferLen = sizeof(ucIVBuffer); if (!uiIVLen) { goto Exit; } f_mutexLock( m_hMutex); bLocked = TRUE; /* Create NICI Context */ if ( !m_hContext) { if (RC_BAD( rc = CCS_CreateContext(0, &m_hContext))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); m_hContext = 0; goto Exit; } } // See if it is time to reinitialize the Random IV. if ((m_uiIVFactor & 0x07FF) == 0) { // Generate the Random IV if (RC_BAD( rc = CCS_GetRandom( m_hContext, (nuint8 *)&m_ucRndIV, IV_SZ))) { rc = RC_SET( NE_SFLM_NICI_BAD_RANDOM); m_hContext = 0; // Context has been destroyed goto Exit; } // Generate an adjustment factor for the IV if (RC_BAD( rc = CCS_GetRandom( m_hContext, (nuint8 *)&m_uiIVFactor, sizeof(FLMUINT)))) { rc = RC_SET( NE_SFLM_NICI_BAD_RANDOM); m_hContext = 0; // Context has been destroyed goto Exit; } } // Increment each byte of the IV by the IV Factor for( uiLoop = 0; uiLoop < IV_SZ; uiLoop++) { (*pucIVPtr) += (FLMBYTE)m_uiIVFactor; pucIVPtr++; } // Now run the resulting IV through a SHA1 digest. algorithm.algorithm = (nuint8 *)oid_sha1; algorithm.parameter = NULL; algorithm.parameterLen = 0; if (RC_BAD( rc = CCS_DigestInit( m_hContext, &algorithm))) { rc = RC_SET( NE_SFLM_DIGEST_INIT_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } if (RC_BAD( rc = CCS_Digest( m_hContext, (nuint8 *)m_ucRndIV, uiIVLen, (nuint8 *)ucIVBuffer, &uiIVBufferLen))) { rc = RC_SET( NE_SFLM_DIGEST_FAILED); m_hContext = 0; // Context has been destroyed goto Exit; } // Return the new IV! f_memcpy( pucIV, ucIVBuffer, uiIVLen); m_uiIVFactor++; #endif Exit: #ifdef FLM_USE_NICI if (bLocked) { f_mutexUnlock( m_hMutex); } #endif return rc; } /**************************************************************************** Desc: flmDecryptBuffer - assumes aes ****************************************************************************/ RCODE flmDecryptBuffer( FLMBYTE * pucBuffer, FLMUINT * puiBufLen) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucBuffer); F_UNREFERENCED_PARM( puiBufLen); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ATTRIBUTE find[2]; NICI_OBJECT_HANDLE serverKeyHdl = 0; FLMUINT uiCount; NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_aes[] = {IDV_AES128CBC}; FLMBYTE pucIV[ IV_SZ]; /* Create NICI Context */ if (RC_BAD( rc = CCS_CreateContext(0, &context))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); goto Exit; } find[0].type = NICI_A_GLOBAL; find[0].u.f.hasValue = 1; find[0].u.f.value = 1; find[0].u.f.valueInfo = 0; find[1].type = NICI_A_FEATURE; find[1].u.f.hasValue = 1; find[1].u.f.value = NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT; find[1].u.f.valueInfo = 0; if (RC_BAD( rc = CCS_FindObjectsInit(context, find, 2))) { rc = RC_SET( NE_SFLM_NICI_FIND_INIT); goto Exit; } uiCount = 1; if (RC_BAD( rc = CCS_FindObjects( context, &serverKeyHdl, &uiCount))) { rc = RC_SET( NE_SFLM_NICI_FIND_OBJECT); goto Exit; } if (uiCount < 1) { rc = RC_SET( NE_SFLM_NICI_KEY_NOT_FOUND); goto ExitCtx; } /*Set up alogrithm now to do AES and pading for encryption */ algorithm.algorithm = (nuint8 *)oid_aes; algorithm.parameterLen = sizeof(algorithm.parameter->parms[0])+ sizeof(algorithm.parameter->count); algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; algorithm.parameter->parms[0].u.b.len = IV_SZ; /* 16-byte IV */ algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)pucIV; /* init encryption */ if (RC_BAD( rc = CCS_DataDecryptInit( context, &algorithm, serverKeyHdl))) { rc = RC_SET( NE_SFLM_NICI_DECRYPT_INIT_FAILED); goto Exit; } if (RC_BAD( rc = CCS_Decrypt( context, (nuint8 *)pucBuffer, *puiBufLen, (nuint8 *)pucBuffer, puiBufLen))) { rc = RC_SET( NE_SFLM_NICI_DECRYPT_FAILED); goto Exit; } ExitCtx: CCS_DestroyContext( context); #endif Exit: return rc; } /**************************************************************************** Desc: flmEncryptBuffer - assumes aes ****************************************************************************/ RCODE flmEncryptBuffer( FLMBYTE * pucBuffer, FLMUINT * puiBufLen) { RCODE rc = NE_SFLM_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucBuffer); F_UNREFERENCED_PARM( puiBufLen); rc = RC_SET( NE_SFLM_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ATTRIBUTE find[2]; NICI_OBJECT_HANDLE serverKeyHdl = 0; FLMUINT uiCount; NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_aes[] = {IDV_AES128CBC}; FLMBYTE pucIV[ IV_SZ]; /* Create NICI Context */ if (RC_BAD( rc = CCS_CreateContext(0, &context))) { rc = RC_SET( NE_SFLM_NICI_CONTEXT); goto Exit; } find[0].type = NICI_A_GLOBAL; find[0].u.f.hasValue = 1; find[0].u.f.value = 1; find[0].u.f.valueInfo = 0; find[1].type = NICI_A_FEATURE; find[1].u.f.hasValue = 1; find[1].u.f.value = NICI_F_DATA_ENCRYPT | NICI_F_DATA_DECRYPT; find[1].u.f.valueInfo = 0; if (RC_BAD( rc = CCS_FindObjectsInit(context, find, 2))) { rc = RC_SET( NE_SFLM_NICI_FIND_INIT); goto Exit; } uiCount = 1; if (RC_BAD( rc = CCS_FindObjects( context, &serverKeyHdl, &uiCount))) { rc = RC_SET( NE_SFLM_NICI_FIND_OBJECT); goto Exit; } if (uiCount < 1) { rc = RC_SET( NE_SFLM_NICI_KEY_NOT_FOUND); goto ExitCtx; } algorithm.algorithm = (nuint8 *)oid_aes; algorithm.parameterLen = sizeof(algorithm.parameter->parms[0])+ sizeof(algorithm.parameter->count); algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; algorithm.parameter->parms[0].u.b.len = IV_SZ; /* 16-byte IV */ algorithm.parameter->parms[0].u.b.ptr = (nuint8 *)pucIV; GetIV(pucIV, IV_SZ); /* init encryption */ if (RC_BAD( rc = CCS_DataEncryptInit( context, &algorithm, serverKeyHdl))) { rc = RC_SET_AND_ASSERT( NE_SFLM_NICI_ENC_INIT_FAILED); goto Exit; } if (RC_BAD( rc = CCS_Encrypt( context, (nuint8 *)pucBuffer, *puiBufLen, (nuint8 *)pucBuffer, puiBufLen))) { rc = RC_SET( NE_SFLM_NICI_ENCRYPT_FAILED); goto Exit; } ExitCtx: CCS_DestroyContext( context); #endif Exit: return rc; } #ifdef FLM_USE_NICI FSTATIC void GetIV( FLMBYTE * pucIV, FLMUINT //uiLen ) { FLMUINT uiLoop; FLMUINT uiLoop2; f_sprintf( (char *)pucIV, "3587903781145935"); for (uiLoop = 0; uiLoop < 100; uiLoop++) { for ( uiLoop2 = 0; uiLoop2 < IV_SZ; uiLoop2++) { pucIV[IV_SZ - uiLoop2] ^= pucIV[ uiLoop2]; pucIV[IV_SZ - uiLoop2] += pucIV[ uiLoop2]; pucIV[IV_SZ - uiLoop2] ^= pucIV[ uiLoop2]; } } } #endif #ifdef FLM_USE_NICI #ifndef FLM_UNIX int CCSX_SetNewIV( int ,//MODULEID, FLMUINT32 ,//hContext, pnuint8 ,//IV, nuint32 //IVLen ) { return(NICI_E_FUNCTION_NOT_SUPPORTED); } #endif #endif