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 if (pBuf.SetArray(pByte, 0, pBufSize) != E_SUCCESS) {
197 LogDebug("Couldnot set pBuf");
202 return pInstance->_TrustZoneService::EncryptN(*appInfo, pBuf);
205 Tizen::Base::ByteBuffer* TEST_dec(
206 Tizen::Base::ByteBuffer* appInfo,
207 const unsigned char *plainBuffer,
210 using namespace Tizen::Base;
212 Tizen::Security::Crypto::_TrustZoneService* pInstance;
213 pInstance = Tizen::Security::Crypto::_TrustZoneService::GetInstance();
216 pBuf.Construct(pBufSize);
217 const byte *pByte = reinterpret_cast<const byte*>(plainBuffer);
218 if (pBuf.SetArray(pByte, 0, pBufSize) != E_SUCCESS) {
219 LogDebug("Couldnot set pBuf");
224 return pInstance->_TrustZoneService::DecryptN(*appInfo, pBuf);
229 namespace WidgetInstall {
230 TaskEncryptResource::TaskEncryptResource(InstallerContext& context) :
231 DPL::TaskDecl<TaskEncryptResource>(this),
234 AddStep(&TaskEncryptResource::StepEncryptResource);
237 void TaskEncryptResource::StepEncryptResource()
239 LogDebug("Step Encrypt resource");
241 EncryptDirectory(m_context.locations->getTemporaryRootDir());
242 m_context.job->UpdateProgress(
243 InstallerContext::INSTALL_ECRYPTION_FILES,
244 "Ecrypt resource files");
247 void TaskEncryptResource::EncryptDirectory(std::string path)
251 char * const paths[] = { const_cast<char * const>(path.c_str()), NULL };
253 if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
256 LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: "
258 ThrowMsg(Exceptions::EncryptionFailed, "Error reading directory: "
262 while ((ftsent = fts_read(fts)) != NULL) {
263 switch (ftsent->fts_info) {
269 //directories, non-regular files, dangling symbolic links
274 //regular files and other objects that can be counted
275 if (isSupportedForEncryption(ftsent->fts_path)) {
276 EncryptFile(ftsent->fts_path);
284 LogWarning(__PRETTY_FUNCTION__
285 << ": traversal failed on file: "
288 << strerror(ftsent->fts_errno));
289 ThrowMsg(Exceptions::EncryptionFailed, "Error reading file");
294 if (fts_close(fts) == -1) {
296 LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
301 void TaskEncryptResource::EncryptFile(const std::string &fileName)
303 LogDebug("Encrypt file: " << fileName);
304 std::string encFile = fileName + ".enc";
307 memset(&info, 0, sizeof(info));
308 if (stat(fileName.c_str(), &info) != 0)
311 ThrowMsg(Exceptions::EncryptionFailed,
312 "Could not access file " << fileName <<
313 "[" << DPL::GetErrnoString(error) << "]");
315 const std::size_t fileSize = info.st_size;
317 LogDebug(fileName << " size is 0, so encryption is skiped");
321 DPL::ScopedFClose inFile(openFile(fileName, "r"));
322 DPL::ScopedFClose outFile(openFile(encFile, "w"));
324 const std::size_t chunkSize = (fileSize > ENCRYPTION_CHUNK_MAX_SIZE
325 ? ENCRYPTION_CHUNK_MAX_SIZE : fileSize);
327 std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
328 std::unique_ptr<unsigned char[]> outChunk;
330 std::size_t bytesRead = 0;
331 using namespace Tizen::Base;
334 DPL::ToUTF8String(m_context.widgetConfig.tzAppid).c_str();
335 const byte *b_pkgid = reinterpret_cast<const byte*>(
338 appInfo.Construct(pkgid.length());
340 if (appInfo.SetArray(b_pkgid, 0, pkgid.length()) != E_SUCCESS) {
341 LogDebug("Couldnot set appInfo");
349 bytesRead = readBytes(inChunk.get(), chunkSize, inFile.Get());
350 if (0 != bytesRead) {
351 ByteBuffer *getBuffer = EncryptChunkByTrustZone(
353 inChunk.get(), bytesRead);
354 if (getBuffer == NULL) {
355 ThrowMsg(Exceptions::EncryptionFailed,
356 "Encryption Failed using TrustZone");
358 int decBufSize = getBuffer->GetRemaining();
360 outChunk.reset(new unsigned char[decBufSize]);
361 memcpy(outChunk.get(), getBuffer->GetPointer(), getBuffer->GetRemaining());
364 char writeSize[ENCRYPTION_DEC_CHUNK_SIZE];
365 memset(writeSize, 0x00, ENCRYPTION_DEC_CHUNK_SIZE);
366 std::stringstream toString;
367 toString << decBufSize;
368 strncpy(writeSize, toString.str().c_str(), toString.str().length());
370 writeBytes((unsigned char*)writeSize,
371 ENCRYPTION_DEC_CHUNK_SIZE, outFile.Get());
372 writeBytes(outChunk.get(), decBufSize, outFile.Get());
375 } while (0 == std::feof(inFile.Get()));
380 LogDebug("File encrypted successfully");
381 LogDebug("Remove plain-text file: " << fileName);
382 if (0 != unlink(fileName.c_str()))
384 Throw(Exceptions::EncryptionFailed);
387 LogDebug("Rename encrypted file");
388 if (0 != std::rename(encFile.c_str(), fileName.c_str()))
390 Throw(Exceptions::EncryptionFailed);
393 std::string realPath = fileName;
395 m_context.locations->getTemporaryRootDir().length(),
396 m_context.locations->getSourceDir());
398 WrtDB::EncryptedFileInfo fileInfo;
399 fileInfo.fileName = DPL::FromUTF8String(realPath);
400 fileInfo.fileSize = fileSize;
402 m_context.widgetConfig.encryptedFiles.insert(fileInfo);
405 } //namespace WidgetInstall