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