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
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 <ss_manager.h>
45 #include <widget_install/job_widget_install.h>
46 #include <widget_install/widget_install_context.h>
47 #include <widget_install/widget_install_errors.h>
49 #include <installer_log.h>
51 using namespace WrtDB;
54 const std::size_t ENCRYPTION_CHUNK_MAX_SIZE = 8192; // bytes
55 const std::size_t ENCRYPTION_DEC_CHUNK_SIZE = 4; // bytes
57 std::set<std::string>& getSupportedForEncryption()
59 static std::set<std::string> encryptSet;
60 if (encryptSet.empty()) {
61 encryptSet.insert(".html");
62 encryptSet.insert(".htm");
63 encryptSet.insert(".css");
64 encryptSet.insert(".js");
69 bool isSupportedForEncryption(const std::string &file)
71 size_t foundKey = file.rfind(".");
72 if (std::string::npos != foundKey) {
73 std::string mimeType = file.substr(foundKey);
74 std::transform(mimeType.begin(), mimeType.end(), mimeType.begin(),
77 return getSupportedForEncryption().count(mimeType) > 0;
85 * @param path Path to a file.
87 * @return Stream handle.
88 * @throw ExtractFileFailed If error (other than EINTR) occurs.
90 FILE* openFile(const std::string& path, const std::string& mode)
96 result = fopen(path.c_str(), mode.c_str());
97 } while ((NULL == result) && (EINTR == errno));
101 ThrowMsg(Jobs::WidgetInstall::Exceptions::EncryptionFailed,
102 "Could not open file " << path);
109 * Reads bytes from a stream.
111 * @param buffer Buffer to read the bytes into.
112 * @param count Number of bytes to read.
113 * @param stream Stream to read from.
114 * @return Number of bytes read
115 * @throw ExtractFileFailed If error (other than EINTR) occurs.
117 std::size_t readBytes(unsigned char* buffer, std::size_t count, FILE* stream)
119 std::size_t result = std::fread(buffer,
120 sizeof(unsigned char),
127 if (0 != std::ferror(stream))
131 ThrowMsg(Jobs::WidgetInstall::Exceptions::ErrorExternalInstallingFailure,
132 "Error while reading data" <<
133 " [" << DPL::GetErrnoString(error) << "]");
142 * Writes bytes to a stream.
144 * @param buffer Data to write.
145 * @param count Number of bytes.
146 * @param stream Stream to write to.
147 * @throw ExtractFileFailed If error (other than EINTR) occurs.
149 void writeBytes(unsigned char* buffer, std::size_t count, FILE* stream)
151 std::size_t bytesWritten = 0;
152 std::size_t bytesToWrite = 0;
155 bytesToWrite = count - bytesWritten;
156 bytesWritten = std::fwrite(buffer + bytesWritten,
157 sizeof(unsigned char),
158 count - bytesWritten,
160 if ((bytesWritten != bytesToWrite) && (EINTR != errno))
163 ThrowMsg(Jobs::WidgetInstall::Exceptions::EncryptionFailed,
164 "Error while writing data" <<
165 " [" << DPL::GetErrnoString(error) << "]");
167 } while ((bytesWritten != bytesToWrite) && (EINTR == errno));
171 int ssmEncrypt(InstallMode::RootPath rootPath, std::string pkgId, const char*
172 inChunk, int inBytes, char** outChunk, int *outBytes)
174 if (rootPath == InstallMode::RootPath::RO) {
175 return ssm_encrypt_preloaded_application(inChunk, inBytes,
178 return ssm_encrypt(pkgId.c_str(), pkgId.length(),
187 namespace WidgetInstall {
188 TaskEncryptResource::TaskEncryptResource(InstallerContext& context) :
189 DPL::TaskDecl<TaskEncryptResource>(this),
192 AddStep(&TaskEncryptResource::StartStep);
194 AddStep(&TaskEncryptResource::StepEncryptResource);
196 AddStep(&TaskEncryptResource::EndStep);
200 void TaskEncryptResource::StepEncryptResource()
202 _D("Step Encrypt resource");
204 EncryptDirectory(m_context.locations->getTemporaryRootDir());
207 void TaskEncryptResource::EncryptDirectory(std::string path)
211 char * const paths[] = { const_cast<char * const>(path.c_str()), NULL };
213 if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
216 _W("%s: fts_open failed with error: %s", __PRETTY_FUNCTION__, strerror(error));
217 ThrowMsg(Exceptions::EncryptionFailed, "Error reading directory: "
221 while ((ftsent = fts_read(fts)) != NULL) {
222 switch (ftsent->fts_info) {
228 //directories, non-regular files, dangling symbolic links
233 //regular files and other objects that can be counted
234 if (isSupportedForEncryption(ftsent->fts_path)) {
235 EncryptFile(ftsent->fts_path);
243 _W("%s: traversal failed on file: %s with error: %s", __PRETTY_FUNCTION__, ftsent->fts_path, strerror(ftsent->fts_errno));
244 ThrowMsg(Exceptions::EncryptionFailed, "Error reading file");
249 if (fts_close(fts) == -1) {
251 _W("%s: fts_close failed with error: %s", __PRETTY_FUNCTION__, strerror(error));
255 void TaskEncryptResource::EncryptFile(const std::string &fileName)
257 _D("Encrypt file: %s", fileName.c_str());
258 std::string encFile = fileName + ".enc";
261 memset(&info, 0, sizeof(info));
262 if (stat(fileName.c_str(), &info) != 0)
265 ThrowMsg(Exceptions::EncryptionFailed,
266 "Could not access file " << fileName <<
267 "[" << DPL::GetErrnoString(error) << "]");
269 const std::size_t fileSize = info.st_size;
271 _D("%s size is 0, so encryption is skiped", fileName.c_str());
275 // If update installed preload web, should skip encryption.
276 if (!(m_context.mode.rootPath == InstallMode::RootPath::RO &&
277 m_context.mode.installTime == InstallMode::InstallTime::PRELOAD
278 && m_context.mode.extension == InstallMode::ExtensionType::DIR)) {
280 DPL::ScopedFClose inFile(openFile(fileName, "r"));
281 DPL::ScopedFClose outFile(openFile(encFile, "w"));
283 const std::size_t chunkSize = (fileSize > ENCRYPTION_CHUNK_MAX_SIZE
284 ? ENCRYPTION_CHUNK_MAX_SIZE : fileSize);
286 std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
287 std::size_t bytesRead = 0;
288 /* TODO : pkgId should change to appId after wrt-client label changed. */
289 std::string pkgId = DPL::ToUTF8String(m_context.widgetConfig.tzPkgid);
293 bytesRead = readBytes(inChunk.get(), chunkSize, inFile.Get());
294 if (0 != bytesRead) {
296 char *outChunk = NULL;
297 if (0 != ssmEncrypt(m_context.mode.rootPath, pkgId,
298 (char*)inChunk.get(), (int)bytesRead,
299 &outChunk, &outDecSize)) {
300 ThrowMsg(Exceptions::EncryptionFailed,
301 "Encryption Failed using TrustZone");
304 std::stringstream toString;
305 toString << outDecSize;
307 writeBytes((unsigned char*)toString.str().c_str(),
308 sizeof(int), outFile.Get());
309 writeBytes((unsigned char*)outChunk, outDecSize, outFile.Get());
312 inChunk.reset(new unsigned char[chunkSize]);
314 } while (0 == std::feof(inFile.Get()));
319 _D("File encrypted successfully");
320 _D("Remove plain-text file: %s", fileName.c_str());
321 if (0 != unlink(fileName.c_str()))
323 Throw(Exceptions::EncryptionFailed);
326 _D("Rename encrypted file");
327 if (0 != std::rename(encFile.c_str(), fileName.c_str()))
329 Throw(Exceptions::EncryptionFailed);
333 std::string realPath = fileName;
335 m_context.locations->getTemporaryRootDir().length(),
336 m_context.locations->getSourceDir());
338 WrtDB::EncryptedFileInfo fileInfo;
339 fileInfo.fileName = DPL::FromUTF8String(realPath);
340 fileInfo.fileSize = fileSize;
342 m_context.widgetConfig.encryptedFiles.insert(fileInfo);
346 void TaskEncryptResource::StartStep()
348 _D("--------- <TaskEncryptResource> : START ----------");
351 void TaskEncryptResource::EndStep()
353 m_context.job->UpdateProgress(
354 InstallerContext::INSTALL_ECRYPTION_FILES,
355 "Ecrypt resource files");
357 _D("--------- <TaskEncryptResource> : END ----------");
359 } //namespace WidgetInstall