2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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.
17 * @file task_ecnrypt_resource.cpp
18 * @author Soyoung Kim (sy037.kim@samsung.com)
20 * @brief Implementation file for installer task encrypt resource
22 #include "task_encrypt_resource.h"
24 #undef __USE_FILE_OFFSET64
35 #include <dpl/log/log.h>
36 #include <dpl/errno_string.h>
37 #include <dpl/foreach.h>
38 #include <dpl/scoped_fclose.h>
39 #include <dpl/wrt-dao-ro/global_config.h>
40 #include <dpl/string.h>
41 #include <FBaseByteBuffer.h>
42 #include <security/FSecCrypto_TrustZoneService.h>
44 #include <widget_install/job_widget_install.h>
45 #include <widget_install/widget_install_context.h>
46 #include <widget_install/widget_install_errors.h>
48 using namespace WrtDB;
51 const std::size_t ENCRYPTION_CHUNK_MAX_SIZE = 1008; // bytes
53 std::set<std::string>& getSupportedForEncryption()
55 static std::set<std::string> encryptSet;
56 if (encryptSet.empty()) {
57 encryptSet.insert(".html");
58 encryptSet.insert(".css");
59 encryptSet.insert(".js");
64 bool isSupportedForEncryption(const std::string &file)
66 size_t foundKey = file.rfind(".");
67 if (std::string::npos != foundKey) {
68 std::string mimeType = file.substr(foundKey);
69 return getSupportedForEncryption().count(mimeType) > 0;
77 * @param path Path to a file.
79 * @return Stream handle.
80 * @throw ExtractFileFailed If error (other than EINTR) occurs.
82 FILE* openFile(const std::string& path, const std::string& mode)
88 result = fopen(path.c_str(), mode.c_str());
89 } while ((NULL == result) && (EINTR == errno));
93 ThrowMsg(Jobs::WidgetInstall::Exceptions::InternalError,
94 "Could not open file " << path);
101 * Reads bytes from a stream.
103 * @param buffer Buffer to read the bytes into.
104 * @param count Number of bytes to read.
105 * @param stream Stream to read from.
106 * @return Number of bytes read
107 * @throw ExtractFileFailed If error (other than EINTR) occurs.
109 std::size_t readBytes(unsigned char* buffer, std::size_t count, FILE* stream)
111 std::size_t result = std::fread(buffer,
112 sizeof(unsigned char),
119 if (0 != std::ferror(stream))
123 ThrowMsg(Jobs::WidgetInstall::Exceptions::InternalError,
124 "Error while reading data" <<
125 " [" << DPL::GetErrnoString(error) << "]");
134 * Writes bytes to a stream.
136 * @param buffer Data to write.
137 * @param count Number of bytes.
138 * @param stream Stream to write to.
139 * @throw ExtractFileFailed If error (other than EINTR) occurs.
141 void writeBytes(unsigned char* buffer, std::size_t count, FILE* stream)
143 std::size_t bytesWritten = 0;
144 std::size_t bytesToWrite = 0;
147 bytesToWrite = count - bytesWritten;
148 bytesWritten = std::fwrite(buffer + bytesWritten,
149 sizeof(unsigned char),
150 count - bytesWritten,
152 if ((bytesWritten != bytesToWrite) && (EINTR != errno))
155 ThrowMsg(Jobs::WidgetInstall::Exceptions::InternalError,
156 "Error while writing data" <<
157 " [" << DPL::GetErrnoString(error) << "]");
159 } while ((bytesWritten != bytesToWrite) && (EINTR == errno));
163 * get encrypted string from trustzone
165 Tizen::Base::ByteBuffer* EncryptChunkByTrustZone(
166 Tizen::Base::ByteBuffer* appInfo,
167 const unsigned char *plainBuffer,
170 using namespace Tizen::Base;
172 Tizen::Security::Crypto::_TrustZoneService* pInstance;
173 pInstance = Tizen::Security::Crypto::_TrustZoneService::GetInstance();
176 pBuf.Construct(pBufSize);
177 const byte *pByte = reinterpret_cast<const byte*>(plainBuffer);
178 pBuf.SetArray(pByte, 0, pBufSize);
181 ByteBuffer* getBuffer = pInstance->_TrustZoneService::EncryptN(*appInfo, pBuf);
187 namespace WidgetInstall {
188 TaskEncryptResource::TaskEncryptResource(InstallerContext& context) :
189 DPL::TaskDecl<TaskEncryptResource>(this),
192 AddStep(&TaskEncryptResource::StepEncryptResource);
195 void TaskEncryptResource::StepEncryptResource()
197 LogDebug("Step Encrypt resource");
199 EncryptDirectory(m_context.locations->getTemporaryRootDir());
200 m_context.job->UpdateProgress(
201 InstallerContext::INSTALL_ECRYPTION_FILES,
202 "Ecrypt resource files");
205 void TaskEncryptResource::EncryptDirectory(std::string path)
209 char * const paths[] = { const_cast<char * const>(path.c_str()), NULL };
211 if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
214 LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: "
216 ThrowMsg(Exceptions::InternalError, "Error reading directory: "
220 while ((ftsent = fts_read(fts)) != NULL) {
221 switch (ftsent->fts_info) {
227 //directories, non-regular files, dangling symbolic links
232 //regular files and other objects that can be counted
233 if (isSupportedForEncryption(ftsent->fts_path)) {
234 EncryptFile(ftsent->fts_path);
242 LogWarning(__PRETTY_FUNCTION__
243 << ": traversal failed on file: "
246 << strerror(ftsent->fts_errno));
247 ThrowMsg(Exceptions::InternalError, "Error reading file");
252 if (fts_close(fts) == -1) {
254 LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
259 void TaskEncryptResource::EncryptFile(const std::string &fileName)
263 LogDebug("Encrypt file: " << fileName);
264 std::string encFile = fileName + ".enc";
267 memset(&info, 0, sizeof(info));
268 if (stat(fileName.c_str(), &info) != 0)
271 ThrowMsg(Exceptions::InternalError,
272 "Could not access file " << fileName <<
273 "[" << DPL::GetErrnoString(error) << "]");
275 const std::size_t fileSize = info.st_size;
277 DPL::ScopedFClose inFile(openFile(fileName, "r"));
278 DPL::ScopedFClose outFile(openFile(encFile, "w"));
280 const std::size_t chunkSize = (fileSize > ENCRYPTION_CHUNK_MAX_SIZE
281 ? ENCRYPTION_CHUNK_MAX_SIZE : fileSize);
283 std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
284 std::unique_ptr<unsigned char[]> outChunk;
286 std::size_t bytesRead = 0;
287 using namespace Tizen::Base;
290 DPL::ToUTF8String(m_context.widgetConfig.tzAppid).c_str();
291 const byte *b_pkgid = reinterpret_cast<const byte*>(
294 appInfo.Construct(pkgid.length());
295 appInfo.SetArray(b_pkgid, 0, pkgid.length());
300 bytesRead = readBytes(inChunk.get(), chunkSize, inFile.Get());
301 if (0 != bytesRead) {
303 ByteBuffer *getBuffer = EncryptChunkByTrustZone(
305 inChunk.get(), bytesRead);
306 int decBufSize = getBuffer->GetRemaining();
308 outChunk.reset(new unsigned char[decBufSize]);
309 memcpy(outChunk.get(), getBuffer->GetPointer(), getBuffer->GetRemaining());
312 writeBytes(outChunk.get(), decBufSize, outFile.Get());
315 } while (0 == std::feof(inFile.Get()));
317 LogDebug("File encrypted successfully");
322 LogDebug("Remove plain-text file: " << fileName);
323 if (0 != unlink(fileName.c_str()))
325 Throw(Exceptions::InternalError);
328 LogDebug("Rename encrypted file");
329 if (0 != std::rename(encFile.c_str(), fileName.c_str()))
331 Throw(Exceptions::InternalError);
334 std::string realPath = fileName;
336 m_context.locations->getTemporaryRootDir().length(),
337 m_context.locations->getSourceDir());
339 WrtDB::EncryptedFileInfo fileInfo;
340 fileInfo.fileName = DPL::FromUTF8String(realPath);
341 fileInfo.fileSize = fileSize;
343 m_context.widgetConfig.encryptedFiles.insert(fileInfo);
345 Catch (Exceptions::InternalError)
347 ReThrowMsg(Exceptions::ExtractFileFailed, fileName);
351 } //namespace WidgetInstall