//------------------------------------------------------------------------- // Desc: Encryption/decryption methods for interfacing to NICI. // 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: f_nici.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ //------------------------------------------------------------------------- #include "flaimsys.h" #ifdef FLM_USE_NICI FSTATIC void GetIV( FLMBYTE * pucIV, FLMUINT uiLen); #endif /**************************************************************************** Desc: wrapNiciKey - Save the wrapped key in m_pKey. NOTE: Make sure there is a buffer allocated for the wrapped key (m_pucWrappedKey). ****************************************************************************/ F_CCS::~F_CCS() { if (m_hMutex != F_MUTEX_NULL) { f_mutexDestroy( &m_hMutex); } #ifdef FLM_USE_NICI if ( m_keyHandle) { NICI_CC_HANDLE context = 0; // Create NICI Context if( RC_OK( CCS_CreateContext(0, &context))) { // Get rid of the key handle. CCS_DestroyObject( context, m_keyHandle); CCS_DestroyContext( context); } else { flmAssert( 0); } } #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 = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( ppucWrappedKey); F_UNREFERENCED_PARM( pui32Length); F_UNREFERENCED_PARM( masterWrappingKey); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context =0; NICI_ATTRIBUTE wKey; NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_aes[] = {IDV_AES128CBC}; FLMBYTE oid_3des[] = {IDV_DES_EDE3_CBCPadIV8}; FLMBYTE oid_des[] = {IDV_DES_CBCPadIV8}; NICI_OBJECT_HANDLE wrappingKeyHandle; if( masterWrappingKey) { wrappingKeyHandle = masterWrappingKey; } else { if( RC_BAD( rc = getWrappingKey( &wrappingKeyHandle))) { goto Exit; } } // Create NICI Context if( CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } f_memset( &wKey, 0, sizeof( NICI_ATTRIBUTE)); wKey.type = NICI_A_KEY_TYPE; if( CCS_GetAttributeValue( context, wrappingKeyHandle, &wKey, 1) != 0) { rc = RC_SET( FERR_NICI_ATTRIBUTE_VALUE); goto Exit; } if( !wKey.u.f.hasValue) { rc = RC_SET( FERR_NICI_BAD_ATTRIBUTE); goto ExitCtx; } switch (wKey.u.f.value) { case NICI_K_AES: { algorithm.algorithm = 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; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; break; } case NICI_K_DES3X: { algorithm.algorithm = oid_3des; 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_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; break; } case NICI_K_DES: { // Set up alogrithm now to do DES for encryption algorithm.algorithm = oid_des; 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_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; break; } default: { rc = RC_SET( FERR_NICI_WRAPKEY_FAILED); goto ExitCtx; } } // We should be able to call this with NULL for the wrapped // key, to get the length. if( CCS_WrapKey( context, &algorithm, NICI_KM_UNSPECIFIED, 0, wrappingKeyHandle, m_keyHandle, NULL, (NICI_ULONG *)pui32Length) != 0) { rc = RC_SET( FERR_NICI_WRAPKEY_FAILED); goto Exit; } if( RC_BAD( rc = f_calloc( *pui32Length, ppucWrappedKey))) { goto ExitCtx; } if( CCS_WrapKey( context, &algorithm, NICI_KM_UNSPECIFIED, 0, wrappingKeyHandle, m_keyHandle, *ppucWrappedKey, (NICI_ULONG *)pui32Length) != 0) { rc = RC_SET( FERR_NICI_WRAPKEY_FAILED); goto Exit; } ExitCtx: CCS_DestroyContext(context); #endif Exit: return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::unwrapKey( FLMBYTE * pucWrappedKey, FLMUINT32 ui32WrappedKeyLength, NICI_OBJECT_HANDLE masterWrappingKey) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucWrappedKey); F_UNREFERENCED_PARM( ui32WrappedKeyLength); F_UNREFERENCED_PARM( masterWrappingKey); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_OBJECT_HANDLE wrappingKeyHandle; if( masterWrappingKey) { wrappingKeyHandle = masterWrappingKey; } else { if( RC_BAD( rc = getWrappingKey( &wrappingKeyHandle))) { goto Exit; } } // Create NICI Context if( CCS_CreateContext( 0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } if( CCS_UnwrapKey( context, wrappingKeyHandle, pucWrappedKey, ui32WrappedKeyLength, &m_keyHandle) != 0) { rc = RC_SET_AND_ASSERT( FERR_NICI_UNWRAPKEY_FAILED); goto Exit; } CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::generateEncryptionKey( void) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else switch( m_uiAlgType) { case FLM_NICI_AES: { rc = generateEncryptionKeyAES(); break; } case FLM_NICI_DES3: { rc = generateEncryptionKeyDES3(); break; } case FLM_NICI_DES: { rc = generateEncryptionKeyDES(); break; } default: { rc = RC_SET( FERR_NICI_INVALID_ALGORITHM); goto Exit; } } #endif Exit: return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::generateEncryptionKeyAES( void) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ALGORITHM algorithm; NICI_ATTRIBUTE keyAttr[3]; FLMUINT8 keySizeChanged; FLMBYTE oid_aes[] = {IDV_AES128CBC}; // Create NICI Context if( CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } // Set up algorithm algorithm.algorithm = oid_aes; algorithm.parameterLen = 0; // 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 = 128; 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 key if( CCS_GenerateKey( context, &algorithm, keyAttr, 3, (NICI_BBOOL *)&keySizeChanged, &m_keyHandle, NICI_H_INVALID) != 0) { rc = RC_SET( FERR_NICI_GENKEY_FAILED); goto Exit; } // Generate some IV to use with this key. if( CCS_GetRandom( context, m_pucIV, IV_SZ) != 0) { rc = RC_SET( FERR_NICI_BAD_RANDOM); goto Exit; } CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::generateEncryptionKeyDES3( void) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ALGORITHM algorithm; NICI_ATTRIBUTE keyAttr[3]; FLMUINT8 keySizeChanged; FLMBYTE oid_des3[] = {IDV_DES_EDE3_CBC_IV8}; // Create NICI Context if( CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } // Set up algorithm algorithm.algorithm = oid_des3; algorithm.parameterLen = 0; // 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 = 168; 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( CCS_GenerateKey( context, &algorithm, keyAttr, 3, (NICI_BBOOL *)&keySizeChanged, &m_keyHandle, NICI_H_INVALID) != 0) { rc = RC_SET( FERR_NICI_GENKEY_FAILED); goto Exit; } // Generate some IV to use with this key if( CCS_GetRandom( context, m_pucIV, IV_SZ) != 0) { rc = RC_SET( FERR_NICI_BAD_RANDOM); goto Exit; } CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::generateEncryptionKeyDES( void) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ALGORITHM algorithm; NICI_ATTRIBUTE keyAttr[3]; FLMUINT8 keySizeChanged; FLMBYTE oid_des[] = {IDV_DES_CBC_IV8}; // Create NICI Context if( CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } // Set up AES Algorithm algorithm.algorithm = oid_des; algorithm.parameterLen = 0; // 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 = 56; 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( CCS_GenerateKey( context, &algorithm, keyAttr, 3, (NICI_BBOOL *)&keySizeChanged, &m_keyHandle, NICI_H_INVALID) != 0) { rc = RC_SET( FERR_NICI_GENKEY_FAILED); goto Exit; } // Generate some IV to use with this key. if( CCS_GetRandom( context, m_pucIV, IV_SZ) != 0) { rc = RC_SET( FERR_NICI_BAD_RANDOM); goto Exit; } CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::generateWrappingKey( void) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ALGORITHM algorithm; NICI_ATTRIBUTE keyAttr[6]; FLMUINT8 keySizeChanged; FLMBYTE oid_des3[] = {IDV_DES_EDE3_CBC_IV8}; FLMUINT uiIndx; // Create NICI Context if( CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } // Set up AES Algorithm algorithm.algorithm = oid_des3; algorithm.parameterLen = 0; // Set up 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 = oid_des3; keyAttr[uiIndx].u.v.valueLen = sizeof( oid_des3); 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; 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 = 168; 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; 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; // Generate an AES wrapping key if( CCS_GenerateKey( context, &algorithm, keyAttr, 6, (NICI_BBOOL *)&keySizeChanged, &m_keyHandle, NICI_H_INVALID) != 0) { rc = RC_SET( FERR_NICI_GENKEY_FAILED); goto Exit; } // Generate some IV to use with this key if (CCS_GetRandom( context, m_pucIV, IV_SZ) != 0) { rc = RC_SET( FERR_NICI_BAD_RANDOM); goto Exit; } // If we generated a wrap;ping key, then this object's key handle is // actually a wrapping key. This means that we will us it to wrap // the other keys in the system. m_bKeyIsWrappingKey = TRUE; CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::encryptToStore( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else switch (m_uiAlgType) { case FLM_NICI_AES: { rc = encryptToStoreAES( pucIn, uiInLen, pucOut, puiOutLen); break; } case FLM_NICI_DES3: { rc = encryptToStoreDES3( pucIn, uiInLen, pucOut, puiOutLen); break; } case FLM_NICI_DES: { rc = encryptToStoreDES( pucIn, uiInLen, pucOut, puiOutLen); break; } default: { rc = RC_SET( FERR_NICI_INVALID_ALGORITHM); goto Exit; } } #endif Exit: return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::decryptFromStore( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else switch( m_uiAlgType) { case FLM_NICI_AES: { rc = decryptFromStoreAES( pucIn, uiInLen, pucOut, puiOutLen); break; } case FLM_NICI_DES3: { rc = decryptFromStoreDES3( pucIn, uiInLen, pucOut, puiOutLen); break; } case FLM_NICI_DES: { rc = decryptFromStoreDES( pucIn, uiInLen, pucOut, puiOutLen); break; } default: { rc = RC_SET( FERR_NICI_INVALID_ALGORITHM); goto Exit; } } #endif Exit: return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::encryptToStoreAES( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_aes[] = {IDV_AES128CBC}; // Create NICI Context if( CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } algorithm.algorithm = 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; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; if( CCS_DataEncryptInit(context, &algorithm, m_keyHandle) != 0) { rc = RC_SET( FERR_NICI_ENC_INIT_FAILED); goto Exit; } if( CCS_Encrypt( context, pucIn, uiInLen, pucOut, puiOutLen) != 0) { rc = RC_SET( FERR_NICI_ENCRYPT_FAILED); goto Exit; } CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::decryptFromStoreAES( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_aes[] = {IDV_AES128CBC}; // Create NICI Context if (CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } algorithm.algorithm = 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; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; // Init encryption if (CCS_DataDecryptInit(context, &algorithm, m_keyHandle) != 0) { rc = RC_SET( FERR_NICI_DECRYPT_INIT_FAILED); goto Exit; } if( CCS_Decrypt( context, pucIn, uiInLen, pucOut, puiOutLen) != 0) { rc = RC_SET( FERR_NICI_DECRYPT_FAILED); goto Exit; } CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::encryptToStoreDES3( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_des3[] = {IDV_DES_EDE3_CBC_IV8}; // Create NICI Context if (CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } algorithm.algorithm = 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; algorithm.parameter->parms[0].u.b.len = IV_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; // Init encryption if (CCS_DataEncryptInit(context, &algorithm, m_keyHandle) != 0) { rc = RC_SET( FERR_NICI_ENC_INIT_FAILED); goto Exit; } if( CCS_Encrypt( context, pucIn, uiInLen, pucOut, puiOutLen) != 0) { rc = RC_SET( FERR_NICI_ENCRYPT_FAILED); goto Exit; } CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::decryptFromStoreDES3( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_des3[] = {IDV_DES_EDE3_CBC_IV8}; // Create NICI Context if( CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } // Set up alogrithm now to do triple des decryption algorithm.algorithm = 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; algorithm.parameter->parms[0].u.b.len = IV_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; // Init encryption if( CCS_DataDecryptInit(context, &algorithm, m_keyHandle) != 0) { rc = RC_SET( FERR_NICI_DECRYPT_INIT_FAILED); goto Exit; } if( CCS_Decrypt( context, pucIn, uiInLen, pucOut, puiOutLen) != 0) { rc = RC_SET( FERR_NICI_DECRYPT_FAILED); goto Exit; } CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::encryptToStoreDES( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_des[] = {IDV_DES_CBC_IV8}; // Create NICI Context if (CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } algorithm.algorithm = oid_des; 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_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; // Init encryption if( CCS_DataEncryptInit(context, &algorithm, m_keyHandle) != 0) { rc = RC_SET( FERR_NICI_ENC_INIT_FAILED); goto Exit; } if( CCS_Encrypt(context, pucIn, uiInLen, pucOut, puiOutLen) != 0) { rc = RC_SET( FERR_NICI_ENCRYPT_FAILED); goto Exit; } CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::decryptFromStoreDES( FLMBYTE * pucIn, FLMUINT uiInLen, FLMBYTE * pucOut, FLMUINT * puiOutLen) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucIn); F_UNREFERENCED_PARM( uiInLen); F_UNREFERENCED_PARM( pucOut); F_UNREFERENCED_PARM( puiOutLen); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context = 0; NICI_ALGORITHM algorithm; NICI_PARAMETER_INFO parm[1]; FLMBYTE oid_des[] = {IDV_DES_CBC_IV8}; // Create NICI Context if( CCS_CreateContext( 0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } // Set up alogrithm now to do triple des decryption algorithm.algorithm = oid_des; 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_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; // Init encryption if( CCS_DataDecryptInit(context, &algorithm, m_keyHandle) != 0) { rc = RC_SET( FERR_NICI_DECRYPT_INIT_FAILED); goto Exit; } if( CCS_Decrypt( context, pucIn, uiInLen, pucOut, puiOutLen) != 0) { rc = RC_SET( FERR_NICI_DECRYPT_FAILED); goto Exit; } CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE F_CCS::init( FLMBOOL bKeyIsWrappingKey, FLMUINT uiAlgType) { RCODE rc = FERR_OK; if (m_bInitCalled) { flmAssert(0); goto Exit; } m_bKeyIsWrappingKey = bKeyIsWrappingKey; if (uiAlgType != FLM_NICI_AES && uiAlgType != FLM_NICI_DES3 && uiAlgType != FLM_NICI_DES) { rc = RC_SET( FERR_NICI_INVALID_ALGORITHM); goto Exit; } if (RC_BAD( rc = f_mutexCreate( &m_hMutex))) { goto Exit; } m_uiAlgType = uiAlgType; m_bInitCalled = TRUE; Exit: return( rc); } /**************************************************************************** Desc: Pick a wrapping key that we can use to wrap and unwrap the encryption key with. ****************************************************************************/ RCODE F_CCS::getWrappingKey( NICI_OBJECT_HANDLE * pWrappingKeyHandle) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pWrappingKeyHandle); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ATTRIBUTE find[2]; NICI_CC_HANDLE context =0; FLMUINT uiCount; // Create NICI Context if( CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_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_AV_STORAGE; find[1].u.f.valueInfo = 0; if( CCS_FindObjectsInit(context, find, 2) != 0) { rc = RC_SET( FERR_NICI_FIND_INIT); goto Exit; } uiCount = 1; if (CCS_FindObjects(context, pWrappingKeyHandle, &uiCount) != 0) { rc = RC_SET( FERR_NICI_FIND_OBJECT); goto Exit; } if (uiCount < 1) { rc = RC_SET( FERR_NICI_WRAPKEY_NOT_FOUND); goto ExitCtx; } ExitCtx: CCS_DestroyContext(context); #endif Exit: return(rc); } /**************************************************************************** Desc: Function used to obtain the key information in the format that will be stored on disk. ****************************************************************************/ RCODE F_CCS::getKeyToStore( FLMBYTE ** ppucKeyInfo, FLMUINT32 * pui32BufLen, const char * pszEncKeyPasswd, F_CCS * pWrappingCcs, FLMBOOL bBase64Encode) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( ppucKeyInfo); F_UNREFERENCED_PARM( pui32BufLen); F_UNREFERENCED_PARM( pszEncKeyPasswd); F_UNREFERENCED_PARM( pWrappingCcs); F_UNREFERENCED_PARM( bBase64Encode); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else FLMBYTE * pucTmp = NULL; FLMBYTE * pucPtr = NULL; void * pvB64Buffer = NULL; FLMUINT32 ui32PaddedLength; NICI_CC_HANDLE context = 0; IF_PosIStream * pBufferIStream = NULL; IF_IStream * pB64Encoder = NULL; FLMBYTE * pucWrappedKey = NULL; FLMUINT32 ui32WrappedKeyLen = 0; char * pszFormattedEncKeyPasswd = NULL; NICI_OBJECT_HANDLE wrappingKeyHandle = 0; FLMUINT uiB64Length; *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( FLMUINT32) + 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 (CCS_CreateContext( 0, &context)) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } pucPtr = pucTmp; // Save a flag indicating whether the key is wrapped or encoded in // a password. UD2FBA( (pszEncKeyPasswd && pszEncKeyPasswd[0]) ? 1 : 0, pucPtr); pucPtr += sizeof( FLMUINT32); // Copy the key length. UD2FBA(ui32WrappedKeyLen, pucPtr); pucPtr += sizeof( FLMUINT32); // Copy the IV too. f_memcpy( pucPtr, m_pucIV, 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( context, pucPtr, ((FLMUINT)pucTmp + ui32PaddedLength) - (FLMUINT)pucPtr)) { rc = RC_SET( FERR_NICI_BAD_RANDOM); goto Exit; } if( bBase64Encode) { // The resulting length will not be more than doubled. uiB64Length = (FLMUINT)(ui32PaddedLength * 2); if( RC_BAD( rc = f_calloc( uiB64Length, &pvB64Buffer))) { goto ExitCtx; } if( RC_BAD( rc = FlmOpenBufferIStream( (const char *)pucTmp, ui32PaddedLength, &pBufferIStream))) { goto Exit; } if( RC_BAD( rc = FlmOpenBase64EncoderIStream( pBufferIStream, FALSE, &pB64Encoder))) { goto Exit; } if (RC_BAD( rc = pB64Encoder->read( pvB64Buffer, 0xFFFFFFFF, &uiB64Length))) { if( rc != NE_FLM_EOF_HIT) { goto ExitCtx; } rc = NE_FLM_OK; } flmAssert( uiB64Length < (FLMUINT)(ui32PaddedLength * 2)); ((FLMBYTE *)pvB64Buffer)[ uiB64Length] = '\0'; *ppucKeyInfo = (FLMBYTE *)pvB64Buffer; pvB64Buffer = NULL; *pui32BufLen = (FLMUINT32)uiB64Length; } else { pucTmp[ ui32PaddedLength] = '\0'; *ppucKeyInfo = pucTmp; *pui32BufLen = ui32PaddedLength; pucTmp = NULL; } ExitCtx: CCS_DestroyContext( context); #endif Exit: #ifdef FLM_USE_NICI if (pucTmp) { f_free(&pucTmp); } if (pvB64Buffer) { f_free(&pvB64Buffer); } if (pB64Encoder) { pB64Encoder->Release(); } if (pBufferIStream) { pBufferIStream->Release(); } if (pucWrappedKey) { f_free( &pucWrappedKey); } if (pszFormattedEncKeyPasswd) { f_free( &pszFormattedEncKeyPasswd); } #endif return( rc); } /**************************************************************************** Desc: Function used to set the key info using the binary key stored on the disk. ****************************************************************************/ RCODE F_CCS::setKeyFromStore( FLMBYTE * pucKeyInfo, FLMUINT32 ui32BufLen, const char * pszEncKeyPasswd, F_CCS * pWrappingCcs, FLMBOOL bBase64Encoded) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucKeyInfo); F_UNREFERENCED_PARM( ui32BufLen); F_UNREFERENCED_PARM( pszEncKeyPasswd); F_UNREFERENCED_PARM( pWrappingCcs); F_UNREFERENCED_PARM( bBase64Encoded); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else FLMBYTE * pTmpKey = pucKeyInfo; FLMBYTE * pucTmp; FLMBYTE * pucBuffer = NULL; FLMBOOL bShrouded = FALSE; FLMUINT uiLength; FLMBYTE * pucKeyBuf = NULL; char * pszFormattedEncKeyPasswd = NULL; NICI_OBJECT_HANDLE wrappingKeyHandle = 0; if (pWrappingCcs) { flmAssert(m_bKeyIsWrappingKey == FALSE); wrappingKeyHandle = pWrappingCcs->m_keyHandle; } if (bBase64Encoded) { F_BufferIStream bufferStream; { F_Base64DecoderIStream B64Decoder; // Need a temporary buffer to translate the Base64 encoded buffer into if (RC_BAD( rc = f_alloc( ui32BufLen, &pucKeyBuf))) { goto Exit; } if (RC_BAD( rc = bufferStream.open( (const char *)pTmpKey, ui32BufLen))) { goto Exit; } if (RC_BAD( rc = B64Decoder.open( &bufferStream))) { goto Exit; } // Buffer is Base64 encoded. We must first decode it. // Decode the buffer if( RC_BAD( rc = B64Decoder.read( (void *)pucKeyBuf, ui32BufLen, &uiLength))) { goto Exit; } pucTmp = pucKeyBuf; } } else { // Buffer is not base 64 encoded pucTmp = pTmpKey; } // Extract the fields from the buffer bShrouded = FB2UD( pucTmp); pucTmp += sizeof( FLMUINT32); // Actual length - note that the passed buffer is padded to 16 byte boundary. uiLength = FB2UD( pucTmp); pucTmp += sizeof( FLMUINT32); // Get the IV f_memcpy( m_pucIV, pucTmp, IV_SZ); pucTmp += IV_SZ; // Need another temporary buffer to hold the encrypted / shrouded key. if (RC_BAD( rc = f_alloc( uiLength, &pucBuffer))) { goto Exit; } f_memcpy( pucBuffer, pucTmp, uiLength); if (bShrouded) { if (pszEncKeyPasswd == NULL) { rc = RC_SET( FERR_REQUIRE_PASSWD); 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, (FLMUINT32)uiLength, (FLMUNICODE *)pszFormattedEncKeyPasswd))) { goto Exit; } } else { if (pszEncKeyPasswd) { flmAssert( pszEncKeyPasswd[0] == '\0'); } // Unwrap the key. The Key handle is always store in m_keyHandle. if (RC_BAD( rc = unwrapKey( pucBuffer, (FLMUINT32)uiLength, 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; } EXTRACTED_KEY; /**************************************************************************** Desc: 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 = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( ppucExtractedKey); F_UNREFERENCED_PARM( pui32Length); F_UNREFERENCED_PARM( puzEncKeyPasswd); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context =0; 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; // Create NICI Context if (CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); 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 (CCS_GetAttributeValue(context, m_keyHandle, &attr[0], 2) != 0) { rc = RC_SET( FERR_NICI_ATTRIBUTE_VALUE); goto Exit; } if (!attr[0].u.f.hasValue) { rc = RC_SET( FERR_NICI_BAD_ATTRIBUTE); goto ExitCcs; } 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; keyAttr[uiIndx].u.v.valueLen = 16; 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: default: { rc = RC_SET( FERR_NICI_INVALID_ALGORITHM); goto ExitCcs; } } // Make one allocation that we can then use to hold several different things uiBufferSize = sizeof( EXTRACTED_KEY) + attr[1].u.v.valueLen + keyAttr[0].u.v.valueLen + sizeof (ucDigest); uiAllocSize = uiBufferSize + SALT_SZ + (sizeof( NICI_PARAMETER_DATA) * 2) + sizeof( FLMUINT32); // 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 ExitCcs; } keyAttr[1].u.v.valuePtr = (FLMBYTE *)&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 (CCS_ExtractKey( context, m_keyHandle, &keyAttr[0], 2) != 0) { rc = RC_SET( FERR_EXTRACT_KEY_FAILED); goto Exit; } // Calculate a SHA1 checksum. algorithm.algorithm = oid_sha1; algorithm.parameter = NULL; algorithm.parameterLen = 0; if (CCS_DigestInit( context, &algorithm) != 0) { rc = RC_SET( FERR_DIGEST_INIT_FAILED); goto Exit; } if( CCS_Digest( context, pucFormat, keyAttr[0].u.v.valueLen + attr[1].u.v.valueLen, ucDigest, &uiDigestLen) != 0) { rc = RC_SET( FERR_DIGEST_FAILED); goto Exit; } flmAssert( uiDigestLen == sizeof( ucDigest)); pucTempPtr = (FLMBYTE *)pExtractedKey; UD2FBA( attr[0].u.f.value, pucTempPtr); pucTempPtr += 4; UD2FBA( attr[1].u.v.valueLen, pucTempPtr); pucTempPtr += 4; UD2FBA( keyAttr[0].u.v.valueLen, pucTempPtr); // Point to the digest ... pTemp = (FLMBYTE *)&pExtractedKey[1] + attr[1].u.v.valueLen + keyAttr[0].u.v.valueLen; f_memcpy( pTemp, ucDigest, uiDigestLen); // Generate some salt. if (CCS_GetRandom( context, pucSalt, SALT_SZ) != 0) { rc = RC_SET( FERR_NICI_BAD_RANDOM); 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 ExitCcs; } // Now to encrypt the buffer. algorithm.algorithm = oid_pbe; pParmInfo->count = 2; pParmInfo->parms[0].parmType = NICI_P_SALT; pParmInfo->parms[0].u.b.len = SALT_SZ; pParmInfo->parms[0].u.b.ptr = 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( CCS_pbeEncrypt( context, &algorithm, puzEncKeyPasswd, (FLMBYTE *)pExtractedKey, uiBufferSize, pTemp, &uiEncLen) != 0) { rc = RC_SET( FERR_PBE_ENCRYPT_FAILED); 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; ExitCcs: CCS_DestroyContext(context); #endif Exit: #ifdef FLM_USE_NICI if (pTemp) { f_free( &pTemp); } if (pucKey) { f_free( &pExtractedKey); } #endif return(rc); } /**************************************************************************** Desc: Inject the encrypting key using the supplied password. ****************************************************************************/ RCODE F_CCS::injectKey( FLMBYTE * pszExtractedKey, FLMUINT32 ui32Length, FLMUNICODE * puzEncKeyPasswd) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pszExtractedKey); F_UNREFERENCED_PARM( ui32Length); F_UNREFERENCED_PARM( puzEncKeyPasswd); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_CC_HANDLE context =0; 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; FLMUINT uiKeyType; FLMUINT uiFormatLen; FLMUINT uiKeyLen; // 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); // Create NICI context if( CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; } // Now to decrypt the buffer. algorithm.algorithm = oid_pbe; pParmInfo->count = 2; pParmInfo->parms[0].parmType = NICI_P_SALT; pParmInfo->parms[0].u.b.len = SALT_SZ; pParmInfo->parms[0].u.b.ptr = 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( CCS_pbeDecrypt( context, &algorithm, puzEncKeyPasswd, pszExtractedKey, ui32Length, pucBuffer, &uiEncLen) != 0) { rc = RC_SET( FERR_PBE_DECRYPT_FAILED); 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; uiKeyType = FB2UD( pucTempPtr); pucTempPtr += 4; pExtractedKey->uiKeyType = uiKeyType; uiFormatLen = FB2UD( pucTempPtr); pucTempPtr += 4; pExtractedKey->uiFormatLen = uiFormatLen; uiKeyLen = FB2UD( pucTempPtr); pExtractedKey->uiKeyLen = uiKeyLen; // Calculate a SHA1 checksum. algorithm.algorithm = oid_sha1; algorithm.parameter = NULL; algorithm.parameterLen = 0; if (CCS_DigestInit( context, &algorithm) != 0) { rc = RC_SET( FERR_DIGEST_INIT_FAILED); goto Exit; } pTemp = (FLMBYTE *)&pExtractedKey[1]; if( CCS_Digest( context, pTemp, pExtractedKey->uiFormatLen + pExtractedKey->uiKeyLen, ucDigest, &uiDigestLen) != 0) { rc = RC_SET( FERR_DIGEST_FAILED); 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( FERR_INVALID_CRC); goto ExitCcs; } pucFormat = (FLMBYTE *)&pExtractedKey[1]; pKey = pucFormat + pExtractedKey->uiFormatLen; uiIndx = 0; f_memset( &keyAttr[0], 0, sizeof(NICI_ATTRIBUTE) * 7); switch (pExtractedKey->uiKeyType) { case NICI_K_AES: { 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; 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 = 128; 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: { 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; 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 = 168; 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_DES: default: { rc = RC_SET( FERR_NICI_INVALID_ALGORITHM); goto ExitCcs; } } if (CCS_InjectKey( context, &keyAttr[0], 7, &m_keyHandle) != 0) { rc = RC_SET( FERR_INJECT_KEY_FAILED); goto Exit; } ExitCcs: CCS_DestroyContext(context); #endif Exit: #ifdef FLM_USE_NICI if (pucBuffer) { f_free( &pucBuffer); } #endif return(rc); } /**************************************************************************** Desc: flmDecryptBuffer - assumes aes ****************************************************************************/ RCODE flmDecryptBuffer( FLMBYTE * pucBuffer, FLMUINT * puiBufLen) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucBuffer); F_UNREFERENCED_PARM( puiBufLen); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ATTRIBUTE find[2]; NICI_CC_HANDLE context =0; 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( CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_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 (CCS_FindObjectsInit(context, find, 2) != 0) { rc = RC_SET( FERR_NICI_FIND_INIT); goto Exit; } uiCount = 1; if (CCS_FindObjects(context, &serverKeyHdl, &uiCount) != 0) { rc = RC_SET( FERR_NICI_FIND_OBJECT); goto Exit; } if (uiCount < 1) { rc = RC_SET( FERR_NICI_KEY_NOT_FOUND); goto ExitCtx; } // Set up alogrithm now to do AES and pading for encryption algorithm.algorithm = 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; algorithm.parameter->parms[0].u.b.ptr = pucIV; // Init encryption if( CCS_DataDecryptInit(context, &algorithm, serverKeyHdl) != 0) { rc = RC_SET( FERR_NICI_DECRYPT_INIT_FAILED); goto Exit; } if( CCS_Decrypt( context, pucBuffer, *puiBufLen, pucBuffer, puiBufLen) != 0) { rc = RC_SET( FERR_NICI_DECRYPT_FAILED); goto Exit; } ExitCtx: CCS_DestroyContext(context); #endif Exit: return( rc); } /**************************************************************************** Desc: ****************************************************************************/ RCODE flmEncryptBuffer( FLMBYTE * pucBuffer, FLMUINT * puiBufLen) { RCODE rc = FERR_OK; #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pucBuffer); F_UNREFERENCED_PARM( puiBufLen); rc = RC_SET( FERR_UNSUPPORTED_FEATURE); goto Exit; #else NICI_ATTRIBUTE find[2]; NICI_CC_HANDLE context =0; 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 (CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_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 (CCS_FindObjectsInit(context, find, 2) != 0) { rc = RC_SET( FERR_NICI_FIND_INIT); goto Exit; } uiCount = 1; if (CCS_FindObjects(context, &serverKeyHdl, &uiCount) != 0) { rc = RC_SET( FERR_NICI_FIND_OBJECT); goto Exit; } if (uiCount < 1) { rc = RC_SET( FERR_NICI_KEY_NOT_FOUND); goto ExitCtx; } algorithm.algorithm = 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; algorithm.parameter->parms[0].u.b.ptr = pucIV; GetIV(pucIV, IV_SZ); // Init encryption if (CCS_DataEncryptInit(context, &algorithm, serverKeyHdl) != 0) { rc = RC_SET( FERR_NICI_ENC_INIT_FAILED); goto Exit; } if (CCS_Encrypt(context, pucBuffer, *puiBufLen, pucBuffer, puiBufLen) != 0) { rc = RC_SET( FERR_NICI_ENCRYPT_FAILED); goto Exit; } ExitCtx: CCS_DestroyContext( context); #endif Exit: return( rc); } /***************************************************************************** Desc: *****************************************************************************/ #ifdef FLM_USE_NICI FSTATIC void GetIV( FLMBYTE * pucIV, FLMUINT //uiLen ) { FLMUINT uiLoop; FLMUINT uiLoop2; f_strcpy( (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 /***************************************************************************** Desc: *****************************************************************************/ #if defined( FLM_USE_NICI) && !defined( FLM_UNIX) int CCSX_SetNewIV( int , // MODULEID, FLMUINT32 , // hContext, pnuint8 , // IV, nuint32) // IVLen { return( NICI_E_FUNCTION_NOT_SUPPORTED); } #endif