1*d0626817SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*d0626817SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*d0626817SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*d0626817SAndrew Rist * distributed with this work for additional information 6*d0626817SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*d0626817SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*d0626817SAndrew Rist * "License"); you may not use this file except in compliance 9*d0626817SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*d0626817SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*d0626817SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*d0626817SAndrew Rist * software distributed under the License is distributed on an 15*d0626817SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*d0626817SAndrew Rist * KIND, either express or implied. See the License for the 17*d0626817SAndrew Rist * specific language governing permissions and limitations 18*d0626817SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*d0626817SAndrew Rist *************************************************************/ 21*d0626817SAndrew Rist 22*d0626817SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir #include <precompiled_xmlsecurity.hxx> 25cdf0e10cSrcweir 26cdf0e10cSrcweir #include <osl/time.h> 27cdf0e10cSrcweir #include <rtl/random.h> 28cdf0e10cSrcweir #include <rtl/ref.hxx> 29cdf0e10cSrcweir 30cdf0e10cSrcweir #include "ciphercontext.hxx" 31cdf0e10cSrcweir 32cdf0e10cSrcweir using namespace ::com::sun::star; 33cdf0e10cSrcweir 34cdf0e10cSrcweir uno::Reference< xml::crypto::XCipherContext > OCipherContext::Create( CK_MECHANISM_TYPE nNSSCipherID, const uno::Sequence< ::sal_Int8 >& aKey, const uno::Sequence< ::sal_Int8 >& aInitializationVector, bool bEncryption, bool bW3CPadding ) 35cdf0e10cSrcweir { 36cdf0e10cSrcweir ::rtl::Reference< OCipherContext > xResult = new OCipherContext; 37cdf0e10cSrcweir 38cdf0e10cSrcweir xResult->m_pSlot = PK11_GetBestSlot( nNSSCipherID, NULL ); 39cdf0e10cSrcweir if ( xResult->m_pSlot ) 40cdf0e10cSrcweir { 41cdf0e10cSrcweir SECItem aKeyItem = { siBuffer, const_cast< unsigned char* >( reinterpret_cast< const unsigned char* >( aKey.getConstArray() ) ), aKey.getLength() }; 42cdf0e10cSrcweir xResult->m_pSymKey = PK11_ImportSymKey( xResult->m_pSlot, nNSSCipherID, PK11_OriginDerive, bEncryption ? CKA_ENCRYPT : CKA_DECRYPT, &aKeyItem, NULL ); 43cdf0e10cSrcweir if ( xResult->m_pSymKey ) 44cdf0e10cSrcweir { 45cdf0e10cSrcweir SECItem aIVItem = { siBuffer, const_cast< unsigned char* >( reinterpret_cast< const unsigned char* >( aInitializationVector.getConstArray() ) ), aInitializationVector.getLength() }; 46cdf0e10cSrcweir xResult->m_pSecParam = PK11_ParamFromIV( nNSSCipherID, &aIVItem ); 47cdf0e10cSrcweir if ( xResult->m_pSecParam ) 48cdf0e10cSrcweir { 49cdf0e10cSrcweir xResult->m_pContext = PK11_CreateContextBySymKey( nNSSCipherID, bEncryption ? CKA_ENCRYPT : CKA_DECRYPT, xResult->m_pSymKey, xResult->m_pSecParam); 50cdf0e10cSrcweir if ( xResult->m_pContext ) 51cdf0e10cSrcweir { 52cdf0e10cSrcweir xResult->m_bEncryption = bEncryption; 53cdf0e10cSrcweir xResult->m_bW3CPadding = bW3CPadding; 54cdf0e10cSrcweir xResult->m_bPadding = bW3CPadding || ( PK11_GetPadMechanism( nNSSCipherID ) == nNSSCipherID ); 55cdf0e10cSrcweir xResult->m_nBlockSize = PK11_GetBlockSize( nNSSCipherID, xResult->m_pSecParam ); 56cdf0e10cSrcweir if ( xResult->m_nBlockSize <= SAL_MAX_INT8 ) 57cdf0e10cSrcweir return xResult.get(); 58cdf0e10cSrcweir } 59cdf0e10cSrcweir } 60cdf0e10cSrcweir } 61cdf0e10cSrcweir } 62cdf0e10cSrcweir 63cdf0e10cSrcweir return uno::Reference< xml::crypto::XCipherContext >(); 64cdf0e10cSrcweir } 65cdf0e10cSrcweir 66cdf0e10cSrcweir void OCipherContext::Dispose() 67cdf0e10cSrcweir { 68cdf0e10cSrcweir ::osl::MutexGuard aGuard( m_aMutex ); 69cdf0e10cSrcweir 70cdf0e10cSrcweir if ( m_pContext ) 71cdf0e10cSrcweir { 72cdf0e10cSrcweir PK11_DestroyContext( m_pContext, PR_TRUE ); 73cdf0e10cSrcweir m_pContext = NULL; 74cdf0e10cSrcweir } 75cdf0e10cSrcweir 76cdf0e10cSrcweir if ( m_pSecParam ) 77cdf0e10cSrcweir { 78cdf0e10cSrcweir SECITEM_FreeItem( m_pSecParam, PR_TRUE ); 79cdf0e10cSrcweir m_pSecParam = NULL; 80cdf0e10cSrcweir } 81cdf0e10cSrcweir 82cdf0e10cSrcweir if ( m_pSymKey ) 83cdf0e10cSrcweir { 84cdf0e10cSrcweir PK11_FreeSymKey( m_pSymKey ); 85cdf0e10cSrcweir m_pSymKey = NULL; 86cdf0e10cSrcweir } 87cdf0e10cSrcweir 88cdf0e10cSrcweir if ( m_pSlot ) 89cdf0e10cSrcweir { 90cdf0e10cSrcweir PK11_FreeSlot( m_pSlot ); 91cdf0e10cSrcweir m_pSlot = NULL; 92cdf0e10cSrcweir } 93cdf0e10cSrcweir 94cdf0e10cSrcweir m_bDisposed = true; 95cdf0e10cSrcweir } 96cdf0e10cSrcweir 97cdf0e10cSrcweir uno::Sequence< ::sal_Int8 > SAL_CALL OCipherContext::convertWithCipherContext( const uno::Sequence< ::sal_Int8 >& aData ) 98cdf0e10cSrcweir throw ( lang::IllegalArgumentException, lang::DisposedException, uno::RuntimeException) 99cdf0e10cSrcweir { 100cdf0e10cSrcweir ::osl::MutexGuard aGuard( m_aMutex ); 101cdf0e10cSrcweir 102cdf0e10cSrcweir if ( m_bBroken ) 103cdf0e10cSrcweir throw uno::RuntimeException(); 104cdf0e10cSrcweir 105cdf0e10cSrcweir if ( m_bDisposed ) 106cdf0e10cSrcweir throw lang::DisposedException(); 107cdf0e10cSrcweir 108cdf0e10cSrcweir uno::Sequence< sal_Int8 > aToConvert; 109cdf0e10cSrcweir if ( aData.getLength() ) 110cdf0e10cSrcweir { 111cdf0e10cSrcweir sal_Int32 nOldLastBlockLen = m_aLastBlock.getLength(); 112cdf0e10cSrcweir OSL_ENSURE( nOldLastBlockLen <= m_nBlockSize, "Unexpected last block size!" ); 113cdf0e10cSrcweir 114cdf0e10cSrcweir sal_Int32 nAvailableData = nOldLastBlockLen + aData.getLength(); 115cdf0e10cSrcweir sal_Int32 nToConvertLen = nAvailableData; 116cdf0e10cSrcweir if ( m_bEncryption || !m_bW3CPadding ) 117cdf0e10cSrcweir { 118cdf0e10cSrcweir if ( nAvailableData % m_nBlockSize == 0 ) 119cdf0e10cSrcweir nToConvertLen = nAvailableData; 120cdf0e10cSrcweir else if ( nAvailableData < m_nBlockSize ) 121cdf0e10cSrcweir nToConvertLen = 0; 122cdf0e10cSrcweir else 123cdf0e10cSrcweir nToConvertLen = nAvailableData - nAvailableData % m_nBlockSize; 124cdf0e10cSrcweir } 125cdf0e10cSrcweir else 126cdf0e10cSrcweir { 127cdf0e10cSrcweir // decryption with W3C padding needs at least one block for finalizing 128cdf0e10cSrcweir if ( nAvailableData < m_nBlockSize * 2 ) 129cdf0e10cSrcweir nToConvertLen = 0; 130cdf0e10cSrcweir else 131cdf0e10cSrcweir nToConvertLen = nAvailableData - nAvailableData % m_nBlockSize - m_nBlockSize; 132cdf0e10cSrcweir } 133cdf0e10cSrcweir 134cdf0e10cSrcweir aToConvert.realloc( nToConvertLen ); 135cdf0e10cSrcweir if ( nToConvertLen == 0 ) 136cdf0e10cSrcweir { 137cdf0e10cSrcweir m_aLastBlock.realloc( nOldLastBlockLen + aData.getLength() ); 138cdf0e10cSrcweir rtl_copyMemory( m_aLastBlock.getArray() + nOldLastBlockLen, aData.getConstArray(), aData.getLength() ); 139cdf0e10cSrcweir // aToConvert stays empty 140cdf0e10cSrcweir } 141cdf0e10cSrcweir else if ( nToConvertLen < nOldLastBlockLen ) 142cdf0e10cSrcweir { 143cdf0e10cSrcweir rtl_copyMemory( aToConvert.getArray(), m_aLastBlock.getConstArray(), nToConvertLen ); 144cdf0e10cSrcweir rtl_copyMemory( m_aLastBlock.getArray(), m_aLastBlock.getConstArray() + nToConvertLen, nOldLastBlockLen - nToConvertLen ); 145cdf0e10cSrcweir m_aLastBlock.realloc( nOldLastBlockLen - nToConvertLen + aData.getLength() ); 146cdf0e10cSrcweir rtl_copyMemory( m_aLastBlock.getArray() + nOldLastBlockLen - nToConvertLen, aData.getConstArray(), aData.getLength() ); 147cdf0e10cSrcweir } 148cdf0e10cSrcweir else 149cdf0e10cSrcweir { 150cdf0e10cSrcweir rtl_copyMemory( aToConvert.getArray(), m_aLastBlock.getConstArray(), nOldLastBlockLen ); 151cdf0e10cSrcweir if ( nToConvertLen > nOldLastBlockLen ) 152cdf0e10cSrcweir rtl_copyMemory( aToConvert.getArray() + nOldLastBlockLen, aData.getConstArray(), nToConvertLen - nOldLastBlockLen ); 153cdf0e10cSrcweir m_aLastBlock.realloc( nAvailableData - nToConvertLen ); 154cdf0e10cSrcweir rtl_copyMemory( m_aLastBlock.getArray(), aData.getConstArray() + nToConvertLen - nOldLastBlockLen, nAvailableData - nToConvertLen ); 155cdf0e10cSrcweir } 156cdf0e10cSrcweir } 157cdf0e10cSrcweir 158cdf0e10cSrcweir uno::Sequence< sal_Int8 > aResult; 159cdf0e10cSrcweir OSL_ENSURE( aToConvert.getLength() % m_nBlockSize == 0, "Unexpected size of the data to encrypt!" ); 160cdf0e10cSrcweir if ( aToConvert.getLength() ) 161cdf0e10cSrcweir { 162cdf0e10cSrcweir int nResultLen = 0; 163cdf0e10cSrcweir aResult.realloc( aToConvert.getLength() + m_nBlockSize ); 164cdf0e10cSrcweir if ( PK11_CipherOp( m_pContext, reinterpret_cast< unsigned char* >( aResult.getArray() ), &nResultLen, aResult.getLength(), const_cast< unsigned char* >( reinterpret_cast< const unsigned char* >( aToConvert.getConstArray() ) ), aToConvert.getLength() ) != SECSuccess ) 165cdf0e10cSrcweir { 166cdf0e10cSrcweir m_bBroken = true; 167cdf0e10cSrcweir Dispose(); 168cdf0e10cSrcweir throw uno::RuntimeException(); 169cdf0e10cSrcweir } 170cdf0e10cSrcweir 171cdf0e10cSrcweir m_nConverted += aToConvert.getLength(); 172cdf0e10cSrcweir aResult.realloc( nResultLen ); 173cdf0e10cSrcweir } 174cdf0e10cSrcweir 175cdf0e10cSrcweir return aResult; 176cdf0e10cSrcweir } 177cdf0e10cSrcweir 178cdf0e10cSrcweir uno::Sequence< ::sal_Int8 > SAL_CALL OCipherContext::finalizeCipherContextAndDispose() 179cdf0e10cSrcweir throw (lang::DisposedException, uno::RuntimeException) 180cdf0e10cSrcweir { 181cdf0e10cSrcweir ::osl::MutexGuard aGuard( m_aMutex ); 182cdf0e10cSrcweir 183cdf0e10cSrcweir if ( m_bBroken ) 184cdf0e10cSrcweir throw uno::RuntimeException(); 185cdf0e10cSrcweir 186cdf0e10cSrcweir if ( m_bDisposed ) 187cdf0e10cSrcweir throw lang::DisposedException(); 188cdf0e10cSrcweir 189cdf0e10cSrcweir OSL_ENSURE( m_nBlockSize <= SAL_MAX_INT8, "Unexpected block size!" ); 190cdf0e10cSrcweir OSL_ENSURE( m_nConverted % m_nBlockSize == 0, "Unexpected amount of bytes is already converted!" ); 191cdf0e10cSrcweir sal_Int32 nSizeForPadding = ( m_nConverted + m_aLastBlock.getLength() ) % m_nBlockSize; 192cdf0e10cSrcweir 193cdf0e10cSrcweir // if it is decryption, the amount of data should be rounded to the block size even in case of padding 194cdf0e10cSrcweir if ( ( !m_bPadding || !m_bEncryption ) && nSizeForPadding ) 195cdf0e10cSrcweir throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "The data should contain complete blocks only." ) ), uno::Reference< uno::XInterface >() ); 196cdf0e10cSrcweir 197cdf0e10cSrcweir if ( m_bW3CPadding && m_bEncryption ) 198cdf0e10cSrcweir { 199cdf0e10cSrcweir // in this case the last block should be smaller than standtard block 200cdf0e10cSrcweir // it will be increased with the padding 201cdf0e10cSrcweir OSL_ENSURE( m_aLastBlock.getLength() < m_nBlockSize, "Unexpected size of cashed incomplete last block!" ); 202cdf0e10cSrcweir 203cdf0e10cSrcweir // W3CPadding handling for encryption 204cdf0e10cSrcweir sal_Int32 nPaddingSize = m_nBlockSize - nSizeForPadding; 205cdf0e10cSrcweir sal_Int32 nOldLastBlockLen = m_aLastBlock.getLength(); 206cdf0e10cSrcweir m_aLastBlock.realloc( nOldLastBlockLen + nPaddingSize ); 207cdf0e10cSrcweir 208cdf0e10cSrcweir if ( nPaddingSize > 1 ) 209cdf0e10cSrcweir { 210cdf0e10cSrcweir TimeValue aTime; 211cdf0e10cSrcweir osl_getSystemTime( &aTime ); 212cdf0e10cSrcweir rtlRandomPool aRandomPool = rtl_random_createPool(); 213cdf0e10cSrcweir rtl_random_addBytes( aRandomPool, &aTime, 8 ); 214cdf0e10cSrcweir rtl_random_getBytes( aRandomPool, m_aLastBlock.getArray() + nOldLastBlockLen, nPaddingSize - 1 ); 215cdf0e10cSrcweir rtl_random_destroyPool ( aRandomPool ); 216cdf0e10cSrcweir } 217cdf0e10cSrcweir m_aLastBlock[m_aLastBlock.getLength() - 1] = static_cast< sal_Int8 >( nPaddingSize ); 218cdf0e10cSrcweir } 219cdf0e10cSrcweir 220cdf0e10cSrcweir // finally should the last block be smaller than two standard blocks 221cdf0e10cSrcweir OSL_ENSURE( m_aLastBlock.getLength() < m_nBlockSize * 2 , "Unexpected size of cashed incomplete last block!" ); 222cdf0e10cSrcweir 223cdf0e10cSrcweir uno::Sequence< sal_Int8 > aResult; 224cdf0e10cSrcweir if ( m_aLastBlock.getLength() ) 225cdf0e10cSrcweir { 226cdf0e10cSrcweir int nPrefResLen = 0; 227cdf0e10cSrcweir aResult.realloc( m_aLastBlock.getLength() + m_nBlockSize ); 228cdf0e10cSrcweir if ( PK11_CipherOp( m_pContext, reinterpret_cast< unsigned char* >( aResult.getArray() ), &nPrefResLen, aResult.getLength(), const_cast< unsigned char* >( reinterpret_cast< const unsigned char* >( m_aLastBlock.getConstArray() ) ), m_aLastBlock.getLength() ) != SECSuccess ) 229cdf0e10cSrcweir { 230cdf0e10cSrcweir m_bBroken = true; 231cdf0e10cSrcweir Dispose(); 232cdf0e10cSrcweir throw uno::RuntimeException(); 233cdf0e10cSrcweir } 234cdf0e10cSrcweir 235cdf0e10cSrcweir aResult.realloc( nPrefResLen ); 236cdf0e10cSrcweir m_aLastBlock.realloc( 0 ); 237cdf0e10cSrcweir } 238cdf0e10cSrcweir 239cdf0e10cSrcweir sal_Int32 nPrefixLen = aResult.getLength(); 240cdf0e10cSrcweir aResult.realloc( nPrefixLen + m_nBlockSize * 2 ); 241cdf0e10cSrcweir unsigned nFinalLen = 0; 242cdf0e10cSrcweir if ( PK11_DigestFinal( m_pContext, reinterpret_cast< unsigned char* >( aResult.getArray() + nPrefixLen ), &nFinalLen, aResult.getLength() - nPrefixLen ) != SECSuccess ) 243cdf0e10cSrcweir { 244cdf0e10cSrcweir m_bBroken = true; 245cdf0e10cSrcweir Dispose(); 246cdf0e10cSrcweir throw uno::RuntimeException(); 247cdf0e10cSrcweir } 248cdf0e10cSrcweir 249cdf0e10cSrcweir aResult.realloc( nPrefixLen + nFinalLen ); 250cdf0e10cSrcweir 251cdf0e10cSrcweir if ( m_bW3CPadding && !m_bEncryption ) 252cdf0e10cSrcweir { 253cdf0e10cSrcweir // W3CPadding handling for decryption 254cdf0e10cSrcweir // aResult should have anough data, since we let m_aLastBlock be big enough in case of decryption 255cdf0e10cSrcweir OSL_ENSURE( aResult.getLength() >= m_nBlockSize, "Not enough data to handle the padding!" ); 256cdf0e10cSrcweir 257cdf0e10cSrcweir sal_Int8 nBytesToRemove = aResult[aResult.getLength() - 1]; 258cdf0e10cSrcweir if ( nBytesToRemove <= 0 || nBytesToRemove > aResult.getLength() ) 259cdf0e10cSrcweir { 260cdf0e10cSrcweir m_bBroken = true; 261cdf0e10cSrcweir Dispose(); 262cdf0e10cSrcweir throw uno::RuntimeException(); 263cdf0e10cSrcweir } 264cdf0e10cSrcweir 265cdf0e10cSrcweir aResult.realloc( aResult.getLength() - nBytesToRemove ); 266cdf0e10cSrcweir } 267cdf0e10cSrcweir 268cdf0e10cSrcweir Dispose(); 269cdf0e10cSrcweir 270cdf0e10cSrcweir return aResult; 271cdf0e10cSrcweir } 272cdf0e10cSrcweir 273