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
37 #include <dpl/log/log.h>
38 #include <dpl/errno_string.h>
39 #include <dpl/foreach.h>
40 #include <dpl/scoped_fclose.h>
41 #include <dpl/wrt-dao-ro/global_config.h>
42 #include <dpl/string.h>
43 #include <FBaseByteBuffer.h>
44 #include <security/FSecCrypto_TrustZoneService.h>
46 #include <widget_install/job_widget_install.h>
47 #include <widget_install/widget_install_context.h>
48 #include <widget_install/widget_install_errors.h>
50 using namespace WrtDB;
54 void InitWebAppInfo(const char* appId, const char* rootPath);
58 const std::size_t ENCRYPTION_CHUNK_MAX_SIZE = 4096; // bytes
59 const std::size_t ENCRYPTION_DEC_CHUNK_SIZE = 4; // bytes
60 static bool initWebApp = false;
62 std::set<std::string>& getSupportedForEncryption()
64 static std::set<std::string> encryptSet;
65 if (encryptSet.empty()) {
66 encryptSet.insert(".html");
67 encryptSet.insert(".css");
68 encryptSet.insert(".js");
73 bool isSupportedForEncryption(const std::string &file)
75 size_t foundKey = file.rfind(".");
76 if (std::string::npos != foundKey) {
77 std::string mimeType = file.substr(foundKey);
78 return getSupportedForEncryption().count(mimeType) > 0;
86 * @param path Path to a file.
88 * @return Stream handle.
89 * @throw ExtractFileFailed If error (other than EINTR) occurs.
91 FILE* openFile(const std::string& path, const std::string& mode)
97 result = fopen(path.c_str(), mode.c_str());
98 } while ((NULL == result) && (EINTR == errno));
102 ThrowMsg(Jobs::WidgetInstall::Exceptions::EncryptionFailed,
103 "Could not open file " << path);
110 * Reads bytes from a stream.
112 * @param buffer Buffer to read the bytes into.
113 * @param count Number of bytes to read.
114 * @param stream Stream to read from.
115 * @return Number of bytes read
116 * @throw ExtractFileFailed If error (other than EINTR) occurs.
118 std::size_t readBytes(unsigned char* buffer, std::size_t count, FILE* stream)
120 std::size_t result = std::fread(buffer,
121 sizeof(unsigned char),
128 if (0 != std::ferror(stream))
132 ThrowMsg(Jobs::WidgetInstall::Exceptions::ErrorExternalInstallingFailure,
133 "Error while reading data" <<
134 " [" << DPL::GetErrnoString(error) << "]");
143 * Writes bytes to a stream.
145 * @param buffer Data to write.
146 * @param count Number of bytes.
147 * @param stream Stream to write to.
148 * @throw ExtractFileFailed If error (other than EINTR) occurs.
150 void writeBytes(unsigned char* buffer, std::size_t count, FILE* stream)
152 std::size_t bytesWritten = 0;
153 std::size_t bytesToWrite = 0;
156 bytesToWrite = count - bytesWritten;
157 bytesWritten = std::fwrite(buffer + bytesWritten,
158 sizeof(unsigned char),
159 count - bytesWritten,
161 if ((bytesWritten != bytesToWrite) && (EINTR != errno))
164 ThrowMsg(Jobs::WidgetInstall::Exceptions::EncryptionFailed,
165 "Error while writing data" <<
166 " [" << DPL::GetErrnoString(error) << "]");
168 } while ((bytesWritten != bytesToWrite) && (EINTR == errno));
172 * get encrypted string from trustzone
174 Tizen::Base::ByteBuffer* EncryptChunkByTrustZone(
175 Tizen::Base::ByteBuffer* appInfo,
176 const unsigned char *plainBuffer,
179 using namespace Tizen::Base;
183 pAppId = (char*)calloc(appInfo->GetRemaining()+1, 1);
184 memcpy(pAppId, appInfo->GetPointer(), appInfo->GetRemaining());
185 InitWebAppInfo(pAppId, "");
190 Tizen::Security::Crypto::_TrustZoneService* pInstance;
191 pInstance = Tizen::Security::Crypto::_TrustZoneService::GetInstance();
194 pBuf.Construct(pBufSize);
195 const byte *pByte = reinterpret_cast<const byte*>(plainBuffer);
196 pBuf.SetArray(pByte, 0, pBufSize);
199 ByteBuffer* getBuffer = pInstance->_TrustZoneService::EncryptN(*appInfo, pBuf);
203 Tizen::Base::ByteBuffer* TEST_dec(
204 Tizen::Base::ByteBuffer* appInfo,
205 const unsigned char *plainBuffer,
208 using namespace Tizen::Base;
210 Tizen::Security::Crypto::_TrustZoneService* pInstance;
211 pInstance = Tizen::Security::Crypto::_TrustZoneService::GetInstance();
214 pBuf.Construct(pBufSize);
215 const byte *pByte = reinterpret_cast<const byte*>(plainBuffer);
216 pBuf.SetArray(pByte, 0, pBufSize);
219 ByteBuffer* getBufferTEST =
220 pInstance->_TrustZoneService::DecryptN(*appInfo, pBuf);
221 return getBufferTEST;
226 namespace WidgetInstall {
227 TaskEncryptResource::TaskEncryptResource(InstallerContext& context) :
228 DPL::TaskDecl<TaskEncryptResource>(this),
231 AddStep(&TaskEncryptResource::StepEncryptResource);
234 void TaskEncryptResource::StepEncryptResource()
236 LogDebug("Step Encrypt resource");
238 EncryptDirectory(m_context.locations->getTemporaryRootDir());
239 m_context.job->UpdateProgress(
240 InstallerContext::INSTALL_ECRYPTION_FILES,
241 "Ecrypt resource files");
244 void TaskEncryptResource::EncryptDirectory(std::string path)
248 char * const paths[] = { const_cast<char * const>(path.c_str()), NULL };
250 if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
253 LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: "
255 ThrowMsg(Exceptions::EncryptionFailed, "Error reading directory: "
259 while ((ftsent = fts_read(fts)) != NULL) {
260 switch (ftsent->fts_info) {
266 //directories, non-regular files, dangling symbolic links
271 //regular files and other objects that can be counted
272 if (isSupportedForEncryption(ftsent->fts_path)) {
273 EncryptFile(ftsent->fts_path);
281 LogWarning(__PRETTY_FUNCTION__
282 << ": traversal failed on file: "
285 << strerror(ftsent->fts_errno));
286 ThrowMsg(Exceptions::EncryptionFailed, "Error reading file");
291 if (fts_close(fts) == -1) {
293 LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
298 void TaskEncryptResource::EncryptFile(const std::string &fileName)
300 LogDebug("Encrypt file: " << fileName);
301 std::string encFile = fileName + ".enc";
304 memset(&info, 0, sizeof(info));
305 if (stat(fileName.c_str(), &info) != 0)
308 ThrowMsg(Exceptions::EncryptionFailed,
309 "Could not access file " << fileName <<
310 "[" << DPL::GetErrnoString(error) << "]");
312 const std::size_t fileSize = info.st_size;
314 DPL::ScopedFClose inFile(openFile(fileName, "r"));
315 DPL::ScopedFClose outFile(openFile(encFile, "w"));
317 const std::size_t chunkSize = (fileSize > ENCRYPTION_CHUNK_MAX_SIZE
318 ? ENCRYPTION_CHUNK_MAX_SIZE : fileSize);
320 std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
321 std::unique_ptr<unsigned char[]> outChunk;
323 std::size_t bytesRead = 0;
324 using namespace Tizen::Base;
327 DPL::ToUTF8String(m_context.widgetConfig.tzAppid).c_str();
328 const byte *b_pkgid = reinterpret_cast<const byte*>(
331 appInfo.Construct(pkgid.length());
332 appInfo.SetArray(b_pkgid, 0, pkgid.length());
337 bytesRead = readBytes(inChunk.get(), chunkSize, inFile.Get());
338 if (0 != bytesRead) {
339 ByteBuffer *getBuffer = EncryptChunkByTrustZone(
341 inChunk.get(), bytesRead);
342 int decBufSize = getBuffer->GetRemaining();
344 outChunk.reset(new unsigned char[decBufSize]);
345 memcpy(outChunk.get(), getBuffer->GetPointer(), getBuffer->GetRemaining());
348 char writeSize[ENCRYPTION_DEC_CHUNK_SIZE];
349 memset(writeSize, 0x00, ENCRYPTION_DEC_CHUNK_SIZE);
350 std::stringstream toString;
351 toString << decBufSize;
352 strncpy(writeSize, toString.str().c_str(), toString.str().length());
354 writeBytes((unsigned char*)writeSize,
355 ENCRYPTION_DEC_CHUNK_SIZE, outFile.Get());
356 writeBytes(outChunk.get(), decBufSize, outFile.Get());
359 } while (0 == std::feof(inFile.Get()));
364 LogDebug("File encrypted successfully");
365 LogDebug("Remove plain-text file: " << fileName);
366 if (0 != unlink(fileName.c_str()))
368 Throw(Exceptions::EncryptionFailed);
371 LogDebug("Rename encrypted file");
372 if (0 != std::rename(encFile.c_str(), fileName.c_str()))
374 Throw(Exceptions::EncryptionFailed);
377 std::string realPath = fileName;
379 m_context.locations->getTemporaryRootDir().length(),
380 m_context.locations->getSourceDir());
382 WrtDB::EncryptedFileInfo fileInfo;
383 fileInfo.fileName = DPL::FromUTF8String(realPath);
384 fileInfo.fileSize = fileSize;
386 m_context.widgetConfig.encryptedFiles.insert(fileInfo);
389 } //namespace WidgetInstall