2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 * @file FIo_SecureRegistry.cpp
20 * @brief This is the implementation file for _SecureRegistry class.
22 #include <unique_ptr.h>
23 #include <FBaseInteger.h>
24 #include <FBaseDouble.h>
25 #include <FBaseFloat.h>
26 #include <FBaseUuId.h>
27 #include <FBaseByteBuffer.h>
28 #include <FBaseColIEnumerator.h>
29 #include <FBaseUtilStringTokenizer.h>
30 #include <FBaseResult.h>
32 #include <FIoRegistry.h>
33 #include <FIo_SecureRegistry.h>
34 #include <FBase_StringConverter.h>
35 #include <FBaseSysLog.h>
36 #include <FIo_FileImpl.h>
37 #include <FIo_SecureIoUtil.h>
40 using namespace Tizen::Base;
41 using namespace Tizen::Base::Utility;
42 using namespace Tizen::Base::Collection;
44 namespace Tizen { namespace Io
47 static const wchar_t* _CIPHER_INFORMATRION = L"CBC/128/PKCS7PADDING";
50 _SaveLengthOfFile(void* pFileSecure)
53 byte legnthOfFile[SECURE_IO_LOF_SIZE] = {0, 0, 0, 0};
54 _FileImpl* pFile = reinterpret_cast< _FileImpl* >(pFileSecure);
55 result r = pFile->Seek(FILESEEKPOSITION_END, 0);
57 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
59 length = pFile->Tell();
60 SysTryReturn(NID_IO, length != -1, r = GetLastResult(), GetLastResult(), "[%s] Tell file has failed.", GetErrorMessage(GetLastResult()));
62 r = pFile->Seek(FILESEEKPOSITION_BEGIN, SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_10_BYTES);
63 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
65 if (sizeof(length) != SECURE_IO_LOF_SIZE)
67 memcpy(legnthOfFile + SECURE_IO_LOF_SIZE - sizeof(length), &length, sizeof(length));
71 memcpy(legnthOfFile, &length, SECURE_IO_LOF_SIZE);
74 r = pFile->Write(legnthOfFile, SECURE_IO_LOF_SIZE);
75 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Write file has failed.", GetErrorMessage(r));
80 _SecureRegistry::_SecureRegistry(void)
85 _SecureRegistry::~_SecureRegistry(void)
87 if (_write == true && _FileImpl::IsFileExist(_regPath) == true)
92 _sectionList.RemoveAll(true);
99 _SecureRegistry::Construct(const String& regPath, const char* pOpenMode, const ByteBuffer* pSecretKey)
101 SysAssertf(_constructed == false, "Already constructed. Calling Construct() twice or more on a same instance is not allowed for this class\n");
102 SysTryReturnResult(NID_IO, !(pSecretKey != null && (pSecretKey->GetRemaining() <= 0)), E_INVALID_ARG,
103 "A key is not valid to encrypt or decrypt a registry file");
105 bool isValidOpenMode = this->VerifyRegistryOpenMode(pOpenMode);
106 SysTryReturnResult(NID_IO, isValidOpenMode == true, E_INVALID_ARG, "The specified openMode is invalid. (%s)", pOpenMode);
109 byte* pRegCont = null;
110 ByteBuffer registryContent;
111 unique_ptr< ByteBuffer > pDecryptedRegBuffer(null);
112 result r = Load(regPath, pOpenMode);
114 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Registry file read is failed.", GetErrorMessage(r));
116 unique_ptr< ByteBuffer > pKey(_SecureIoUtil::GetSecureKeyN(pSecretKey));
117 SysTryReturnResult(NID_IO, !(pKey != null && (pKey->GetRemaining() < ONE_BLOCK_SIZE)), E_INVALID_ARG, "Failed to get a key.");
119 if (_pBuffer == null)
122 //Save registry file path and file open mode
124 _regPath.Append(regPath);
125 __pSecretKey = pKey.release();
129 r = _SecureIoUtil::CheckSecureRegistryHeader(&_pBuffer, &_length, regPath, true);
130 SysTryCatch(NID_IO, (!IsFailed(r)), , r, "[%s] Failed to check registry header.", GetErrorMessage(r));
135 pRegCont = pRegCont + SECURE_REG_HEADER_SIZE_V1;
136 length -= SECURE_REG_HEADER_SIZE_V1;
138 SysTryReturnResult(NID_IO, length > 0, E_SUCCESS, "Only header, no data to parse.");
140 r = registryContent.Construct(length);
141 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to construct byte buffer.", GetErrorMessage(r));
143 r = registryContent.SetArray((byte*) pRegCont, 0, length);
144 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to set array elements.", GetErrorMessage(r));
146 registryContent.Flip();
148 pDecryptedRegBuffer = unique_ptr< ByteBuffer >(_SecureIoUtil::DoCipherAesN(_CIPHER_INFORMATRION, registryContent, *pKey.get(), Tizen::Security::Crypto::CIPHER_DECRYPT));
149 SysTryCatch(NID_IO, pDecryptedRegBuffer != null, r = E_IO, E_IO, "[E_IO] Failed to decrypt registry data.");
155 length = pDecryptedRegBuffer->GetRemaining();
157 _pBuffer = new (std::nothrow) byte[length + 1];
158 SysTryCatch(NID_IO, _pBuffer, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
160 r = pDecryptedRegBuffer->GetArray(_pBuffer, 0, length);
161 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to get array elements.", GetErrorMessage(r));
163 _pBuffer[length] = 0;
167 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Failed to parse registry.", GetErrorMessage(r));
170 //Save registry file path and file open mode
172 _regPath.Append(regPath);
174 __pSecretKey = pKey.release();
192 _SecureRegistry::Flush(void)
194 SysAssertf(_constructed == true, "Not yet constructed. Construct() should be called before use.\n");
195 SysAssertf(!(__pSecretKey == null || (__pSecretKey != null && __pSecretKey->GetRemaining() < ONE_BLOCK_SIZE)),
196 "_SecureRegistry is not constructed.");
201 byte regHeader[SECURE_REG_HEADER_SIZE_V1];
202 byte reservedValue[SECURE_IO_STATIC_BIN_LEN] = {0xCA, 0xFE, 0xBE, 0xBE, 0xDA, 0xEF, 0xEB, 0xEB};
203 ByteBuffer regBuffer;
204 String replicaFileName;
205 String fileOpenMode(L"w+");
206 bool fileExists = false;
207 result r = PrepareToWrite();
208 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Registry data make is failed.", GetErrorMessage(r));
210 SysTryReturnResult(NID_IO, (_pBuffer && _length > 0), E_SUCCESS, "Buffer length 0, Nothing to write, so success!");
212 fileExists = _FileImpl::IsFileExist(_regPath);
214 replicaFileName = _SecureIoUtil::MakeRegistryReplica(_regPath, &nameIndex);
215 SysTryReturn(NID_IO, GetLastResult() == E_SUCCESS, GetLastResult(), GetLastResult(), "[%s] Failed to make registry replica.", GetErrorMessage(GetLastResult()));
217 unique_ptr< _FileImpl > pFileImpl(new (std::nothrow) _FileImpl());
218 SysTryReturnResult(NID_IO, pFileImpl != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
220 r = pFileImpl->Construct(_regPath, fileOpenMode, false, null);
221 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Constructing the file has failed.", GetErrorMessage(r));
223 if (fileExists && _SecureIoUtil::IsEmpty(_regPath) == false)
225 r = _SecureIoUtil::SetRegistryFlag(pFileImpl.get(), FLAG_STATE_CTF);
226 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in registry header.", GetErrorMessage(r));
228 r = pFileImpl->Truncate(SECURE_REG_HEADER_SIZE_V1);
229 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to trucate registry file.", GetErrorMessage(r));
234 r = regBuffer.Construct(length);
235 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Propagated.", GetErrorMessage(r));
237 r = regBuffer.SetArray((byte*) _pBuffer, 0, length);
238 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Propagated.", GetErrorMessage(r));
242 unique_ptr< ByteBuffer > pEncryptedData(_SecureIoUtil::DoCipherAesN(_CIPHER_INFORMATRION, regBuffer, *__pSecretKey, Tizen::Security::Crypto::CIPHER_ENCRYPT));
243 SysTryReturn(NID_IO, pEncryptedData != null, E_IO, E_IO, "[E_IO] Failed to encrypt data.");
245 r = pFileImpl->Seek(FILESEEKPOSITION_BEGIN, 0);
246 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
248 memcpy(regHeader, SECURE_REG_HEADER_STRING, SECURE_REG_HEADER_STRING_SIZE);
249 memcpy(regHeader + SECURE_REG_HEADER_STRING_SIZE, reservedValue, SECURE_IO_STATIC_BIN_LEN);
250 regHeader[SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN] = 1;
251 regHeader[SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN + 1] = nameIndex;
252 memset(regHeader + SECURE_REG_HEADER_STRING_SIZE + SECURE_IO_STATIC_BIN_LEN + SECURE_IO_2_BYTES, 0, SECURE_IO_LOF_SIZE);
253 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);
255 r = pFileImpl->Write(regHeader, SECURE_REG_HEADER_SIZE_V1);
256 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to write secure header to registry file!", GetErrorMessage(r));
258 r = pFileImpl->Write(*pEncryptedData);
259 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to write secure header to registry file!", GetErrorMessage(r));
261 r = pFileImpl->Flush();
262 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to flush the registry.", GetErrorMessage(r));
264 pFileImpl.reset(null);
266 //reopen file to update LOF and replica flag.
267 pFileImpl = unique_ptr< _FileImpl >(new (std::nothrow) _FileImpl());
268 SysTryReturnResult(NID_IO, pFileImpl != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
270 r = pFileImpl->Construct(_regPath, L"r+", false, null);
271 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Constructing the file has failed.", GetErrorMessage(r));
273 r = _SecureIoUtil::SetRegistryFlag(pFileImpl.get(), FLAG_STATE_CVF_CTF);
274 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags to registry header.", GetErrorMessage(r));
276 r = _SaveLengthOfFile(pFileImpl.get());
277 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set length to registry header.", GetErrorMessage(r));
279 r = pFileImpl->Seek(FILESEEKPOSITION_BEGIN, 0);
280 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Seek file has failed.", GetErrorMessage(r));
282 memset(regHeader, 0, sizeof(regHeader));
283 dataSize = pFileImpl->Read(regHeader, SECURE_REG_HEADER_SIZE_V1);
285 if (dataSize < SECURE_REG_HEADER_SIZE_V1)
288 SysLog(NID_IO, "[%s]Failed to read secure header", GetErrorMessage(r));
292 if (_FileImpl::IsFileExist(replicaFileName))
294 r = _FileImpl::Remove(replicaFileName);
295 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s]Failed to delete replica file.", GetErrorMessage(r));
298 r = _SecureIoUtil::DeleteRegistryReplica(regHeader, _regPath);
299 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to delete replica file.", GetErrorMessage(r));
301 r = _SecureIoUtil::SetRegistryFlag(pFileImpl.get(), FLAG_STATE_CVF);
302 SysTryReturn(NID_IO, !IsFailed(r), r, r, "[%s] Failed to set flags in registry file.", GetErrorMessage(r));