Files
mars-flaim/flaim/src/f_nici.cpp

2432 lines
53 KiB
C++

//-------------------------------------------------------------------------
// 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