2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 // Licensed under the Apache License, Version 2.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 * @file FIo_SecureRegistry.cpp
19 * @brief This is the implementation file for _SecureRegistry class.
21 #include <unique_ptr.h>
22 #include <FBaseInteger.h>
23 #include <FBaseDouble.h>
24 #include <FBaseFloat.h>
25 #include <FBaseUuId.h>
26 #include <FBaseByteBuffer.h>
27 #include <FBaseColIEnumerator.h>
28 #include <FBaseUtilStringTokenizer.h>
29 #include <FBaseResult.h>
31 #include <FIoRegistry.h>
32 #include <FIo_SecureRegistry.h>
33 #include <FBase_StringConverter.h>
34 #include <FBaseSysLog.h>
35 #include <FIo_FileImpl.h>
36 #include <FIo_SecureIoUtil.h>
39 using namespace Tizen::Base;
40 using namespace Tizen::Base::Utility;
41 using namespace Tizen::Base::Collection;
43 namespace Tizen { namespace Io
46 static const wchar_t* _CIPHER_INFORMATRION = L"CBC/128/PKCS7PADDING";
49 _SaveLengthOfFile(void* pFileSecure)
52 byte legnthOfFile[SECURE_IO_LOF_SIZE] = {0, 0, 0, 0};
53 _FileImpl* pFile = reinterpret_cast< _FileImpl* >(pFileSecure);
54 result r = pFile->Seek(FILESEEKPOSITION_END, 0);
56 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
58 length = pFile->Tell();
59 SysTryReturn(NID_IO, length != -1, r = GetLastResult(), GetLastResult(), "[%s] Tell file has failed.", GetErrorMessage(GetLastResult()));
61 r = pFile->Seek(FILESEEKPOSITION_BEGIN, SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_10_BYTES);
62 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
64 if (sizeof(length) != SECURE_IO_LOF_SIZE)
66 memcpy(legnthOfFile + SECURE_IO_LOF_SIZE - sizeof(length), &length, sizeof(length));
70 memcpy(legnthOfFile, &length, SECURE_IO_LOF_SIZE);
73 r = pFile->Write(legnthOfFile, SECURE_IO_LOF_SIZE);
74 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Write file has failed.", GetErrorMessage(r));
79 _SecureRegistry::_SecureRegistry(void)
84 _SecureRegistry::~_SecureRegistry(void)
86 if (_write == true && _FileImpl::IsFileExist(_regPath) == true && _update == true)
91 _sectionList.RemoveAll(true);
98 _SecureRegistry::Construct(const String& regPath, const char* pOpenMode, const ByteBuffer* pSecretKey)
100 SysAssertf(_constructed == false, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class\n");
101 SysTryReturnResult(NID_IO, !(pSecretKey != null && (pSecretKey->GetRemaining() <= 0)), E_INVALID_ARG,
102 "A key is not valid to encrypt or decrypt a registry file");
104 bool isValidOpenMode = this->VerifyRegistryOpenMode(pOpenMode);
105 SysTryReturnResult(NID_IO, isValidOpenMode == true, E_INVALID_ARG, "The specified openMode is invalid. (%s)", pOpenMode);
108 byte* pRegCont = null;
109 ByteBuffer registryContent;
110 unique_ptr< ByteBuffer > pDecryptedRegBuffer(null);
111 result r = Load(regPath, pOpenMode);
113 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Registry file read is failed.", GetErrorMessage(r));
115 unique_ptr< ByteBuffer > pKey(_SecureIoUtil::GetSecureKeyN(pSecretKey));
116 SysTryReturnResult(NID_IO, !(pKey != null && (pKey->GetRemaining() < ONE_BLOCK_SIZE)), E_INVALID_ARG, "Failed to get a key.");
118 if (_pBuffer == null)
121 //Save registry file path and file open mode
123 _regPath.Append(regPath);
124 __pSecretKey = pKey.release();
128 r = _SecureIoUtil::CheckSecureRegistryHeader(&_pBuffer, &_length, regPath, true);
129 SysTryCatch(NID_IO, (!IsFailed(r)), , r, "[%s] Failed to check registry header.", GetErrorMessage(r));
134 pRegCont = pRegCont + SECURE_REG_HEADER_SIZE_V1;
135 length -= SECURE_REG_HEADER_SIZE_V1;
137 SysTryReturnResult(NID_IO, length > 0, E_SUCCESS, "Only header, no data to parse.");
139 r = registryContent.Construct(length);
140 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to construct byte buffer.", GetErrorMessage(r));
142 r = registryContent.SetArray((byte*) pRegCont, 0, length);
143 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set array elements.", GetErrorMessage(r));
145 registryContent.Flip();
147 pDecryptedRegBuffer = unique_ptr< ByteBuffer >(_SecureIoUtil::DoCipherAesN(_CIPHER_INFORMATRION, registryContent, *pKey.get(), Tizen::Security::Crypto::CIPHER_DECRYPT));
148 SysTryCatch(NID_IO, pDecryptedRegBuffer != null, r = E_IO, E_IO, "[E_IO] Failed to decrypt registry data.");
154 length = pDecryptedRegBuffer->GetRemaining();
156 _pBuffer = new (std::nothrow) byte[length + 1];
157 SysTryCatch(NID_IO, _pBuffer, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
159 r = pDecryptedRegBuffer->GetArray(_pBuffer, 0, length);
160 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to get array elements.", GetErrorMessage(r));
162 _pBuffer[length] = 0;
166 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to parse registry.", GetErrorMessage(r));
169 //Save registry file path and file open mode
171 _regPath.Append(regPath);
173 __pSecretKey = pKey.release();
191 _SecureRegistry::Flush(void)
193 SysAssertf(_constructed == true, "Not yet constructed. Construct() should be called before use.\n");
194 SysAssertf(!(__pSecretKey == null || (__pSecretKey != null && __pSecretKey->GetRemaining() < ONE_BLOCK_SIZE)),
195 "_SecureRegistry is not constructed.");
200 byte regHeader[SECURE_REG_HEADER_SIZE_V1];
201 byte reservedValue[SECURE_IO_STATIC_BIN_LEN] = {0xCA, 0xFE, 0xBE, 0xBE, 0xDA, 0xEF, 0xEB, 0xEB};
202 ByteBuffer regBuffer;
203 String replicaFileName;
204 String fileOpenMode(L"w+");
205 bool fileExists = false;
206 result r = PrepareToWrite();
207 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Registry data make is failed.", GetErrorMessage(r));
209 SysTryReturnResult(NID_IO, (_pBuffer && _length > 0), E_SUCCESS, "Buffer length 0, Nothing to write, so success!");
211 fileExists = _FileImpl::IsFileExist(_regPath);
213 replicaFileName = _SecureIoUtil::MakeRegistryReplica(_regPath, &nameIndex);
214 SysTryReturn(NID_IO, GetLastResult() == E_SUCCESS, GetLastResult(), GetLastResult(), "[%s] Failed to make registry replica.", GetErrorMessage(GetLastResult()));
216 unique_ptr< _FileImpl > pFileImpl(new (std::nothrow) _FileImpl());
217 SysTryReturnResult(NID_IO, pFileImpl != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
219 r = pFileImpl->Construct(_regPath, fileOpenMode, false, null);
220 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Constructing the file has failed.", GetErrorMessage(r));
222 if (fileExists && _SecureIoUtil::IsEmpty(_regPath) == false)
224 r = _SecureIoUtil::SetRegistryFlag(pFileImpl.get(), FLAG_STATE_CTF);
225 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in registry header.", GetErrorMessage(r));
227 r = pFileImpl->Truncate(SECURE_REG_HEADER_SIZE_V1);
228 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to trucate registry file.", GetErrorMessage(r));
233 r = regBuffer.Construct(length);
234 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Propagated.", GetErrorMessage(r));
236 r = regBuffer.SetArray((byte*) _pBuffer, 0, length);
237 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Propagated.", GetErrorMessage(r));
241 unique_ptr< ByteBuffer > pEncryptedData(_SecureIoUtil::DoCipherAesN(_CIPHER_INFORMATRION, regBuffer, *__pSecretKey, Tizen::Security::Crypto::CIPHER_ENCRYPT));
242 SysTryReturn(NID_IO, pEncryptedData != null, E_IO, E_IO, "[E_IO] Failed to encrypt data.");
244 r = pFileImpl->Seek(FILESEEKPOSITION_BEGIN, 0);
245 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
247 memcpy(regHeader, SECURE_REG_HEADER_STRING, SECURE_REG_HEADER_STRING_SIZE);
248 memcpy(regHeader + SECURE_REG_HEADER_STRING_SIZE, reservedValue, SECURE_IO_STATIC_BIN_LEN);
249 regHeader[SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN] = 1;
250 regHeader[SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN + 1] = nameIndex;
251 memset(regHeader + SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN + SECURE_IO_2_BYTES, 0, SECURE_IO_LOF_SIZE);
252 memset(regHeader + SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN + SECURE_IO_2_BYTES + SECURE_IO_LOF_SIZE, 0, SECURE_IO_LOF_SIZE);
254 r = pFileImpl->Write(regHeader, SECURE_REG_HEADER_SIZE_V1);
255 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to write secure header to registry file!", GetErrorMessage(r));
257 r = pFileImpl->Write(*pEncryptedData);
258 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to write secure header to registry file!", GetErrorMessage(r));
260 r = pFileImpl->Flush();
261 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to flush the registry.", GetErrorMessage(r));
263 pFileImpl.reset(null);
265 //reopen file to update LOF and replica flag.
266 pFileImpl = unique_ptr< _FileImpl >(new (std::nothrow) _FileImpl());
267 SysTryReturnResult(NID_IO, pFileImpl != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
269 r = pFileImpl->Construct(_regPath, L"r+", false, null);
270 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Constructing the file has failed.", GetErrorMessage(r));
272 r = _SecureIoUtil::SetRegistryFlag(pFileImpl.get(), FLAG_STATE_CVF_CTF);
273 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags to registry header.", GetErrorMessage(r));
275 r = _SaveLengthOfFile(pFileImpl.get());
276 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set length to registry header.", GetErrorMessage(r));
278 r = pFileImpl->Seek(FILESEEKPOSITION_BEGIN, 0);
279 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
281 memset(regHeader, 0, sizeof(regHeader));
282 dataSize = pFileImpl->Read(regHeader, SECURE_REG_HEADER_SIZE_V1);
284 if (dataSize < SECURE_REG_HEADER_SIZE_V1)
287 SysLog(NID_IO, "[%s]Failed to read secure header", GetErrorMessage(r));
291 if (_FileImpl::IsFileExist(replicaFileName))
293 r = _FileImpl::Remove(replicaFileName);
294 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s]Failed to delete replica file.", GetErrorMessage(r));
297 r = _SecureIoUtil::DeleteRegistryReplica(regHeader, _regPath);
298 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to delete replica file.", GetErrorMessage(r));
300 r = _SecureIoUtil::SetRegistryFlag(pFileImpl.get(), FLAG_STATE_CVF);
301 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in registry file.", GetErrorMessage(r));