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 <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 using namespace WrtDB;
52 const std::size_t ENCRYPTION_CHUNK_MAX_SIZE = 8192; // bytes
53 const std::size_t ENCRYPTION_DEC_CHUNK_SIZE = 4; // bytes
55 std::set<std::string>& getSupportedForEncryption()
57 static std::set<std::string> encryptSet;
58 if (encryptSet.empty()) {
59 encryptSet.insert(".html");
60 encryptSet.insert(".css");
61 encryptSet.insert(".js");
66 bool isSupportedForEncryption(const std::string &file)
68 size_t foundKey = file.rfind(".");
69 if (std::string::npos != foundKey) {
70 std::string mimeType = file.substr(foundKey);
71 return getSupportedForEncryption().count(mimeType) > 0;
79 * @param path Path to a file.
81 * @return Stream handle.
82 * @throw ExtractFileFailed If error (other than EINTR) occurs.
84 FILE* openFile(const std::string& path, const std::string& mode)
90 result = fopen(path.c_str(), mode.c_str());
91 } while ((NULL == result) && (EINTR == errno));
95 ThrowMsg(Jobs::WidgetInstall::Exceptions::EncryptionFailed,
96 "Could not open file " << path);
103 * Reads bytes from a stream.
105 * @param buffer Buffer to read the bytes into.
106 * @param count Number of bytes to read.
107 * @param stream Stream to read from.
108 * @return Number of bytes read
109 * @throw ExtractFileFailed If error (other than EINTR) occurs.
111 std::size_t readBytes(unsigned char* buffer, std::size_t count, FILE* stream)
113 std::size_t result = std::fread(buffer,
114 sizeof(unsigned char),
121 if (0 != std::ferror(stream))
125 ThrowMsg(Jobs::WidgetInstall::Exceptions::ErrorExternalInstallingFailure,
126 "Error while reading data" <<
127 " [" << DPL::GetErrnoString(error) << "]");
136 * Writes bytes to a stream.
138 * @param buffer Data to write.
139 * @param count Number of bytes.
140 * @param stream Stream to write to.
141 * @throw ExtractFileFailed If error (other than EINTR) occurs.
143 void writeBytes(unsigned char* buffer, std::size_t count, FILE* stream)
145 std::size_t bytesWritten = 0;
146 std::size_t bytesToWrite = 0;
149 bytesToWrite = count - bytesWritten;
150 bytesWritten = std::fwrite(buffer + bytesWritten,
151 sizeof(unsigned char),
152 count - bytesWritten,
154 if ((bytesWritten != bytesToWrite) && (EINTR != errno))
157 ThrowMsg(Jobs::WidgetInstall::Exceptions::EncryptionFailed,
158 "Error while writing data" <<
159 " [" << DPL::GetErrnoString(error) << "]");
161 } while ((bytesWritten != bytesToWrite) && (EINTR == errno));
164 int ssmEncrypt(InstallMode::RootPath rootPath, std::string pkgId, const char*
165 inChunk, int inBytes, char** outChunk, int *outBytes)
167 if (rootPath == InstallMode::RootPath::RO) {
168 return ssm_encrypt_preloaded_application(inChunk, inBytes,
171 return ssm_encrypt(pkgId.c_str(), pkgId.length(),
179 namespace WidgetInstall {
180 TaskEncryptResource::TaskEncryptResource(InstallerContext& context) :
181 DPL::TaskDecl<TaskEncryptResource>(this),
184 AddStep(&TaskEncryptResource::StartStep);
185 AddStep(&TaskEncryptResource::StepEncryptResource);
186 AddStep(&TaskEncryptResource::EndStep);
189 void TaskEncryptResource::StepEncryptResource()
191 LogDebug("Step Encrypt resource");
193 EncryptDirectory(m_context.locations->getTemporaryRootDir());
196 void TaskEncryptResource::EncryptDirectory(std::string path)
200 char * const paths[] = { const_cast<char * const>(path.c_str()), NULL };
202 if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
205 LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: "
207 ThrowMsg(Exceptions::EncryptionFailed, "Error reading directory: "
211 while ((ftsent = fts_read(fts)) != NULL) {
212 switch (ftsent->fts_info) {
218 //directories, non-regular files, dangling symbolic links
223 //regular files and other objects that can be counted
224 if (isSupportedForEncryption(ftsent->fts_path)) {
225 EncryptFile(ftsent->fts_path);
233 LogWarning(__PRETTY_FUNCTION__
234 << ": traversal failed on file: "
237 << strerror(ftsent->fts_errno));
238 ThrowMsg(Exceptions::EncryptionFailed, "Error reading file");
243 if (fts_close(fts) == -1) {
245 LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
250 void TaskEncryptResource::EncryptFile(const std::string &fileName)
252 LogDebug("Encrypt file: " << fileName);
253 std::string encFile = fileName + ".enc";
256 memset(&info, 0, sizeof(info));
257 if (stat(fileName.c_str(), &info) != 0)
260 ThrowMsg(Exceptions::EncryptionFailed,
261 "Could not access file " << fileName <<
262 "[" << DPL::GetErrnoString(error) << "]");
264 const std::size_t fileSize = info.st_size;
266 LogDebug(fileName << " size is 0, so encryption is skiped");
270 // If update installed preload web, should skip encryption.
271 if (!(m_context.mode.rootPath == InstallMode::RootPath::RO &&
272 m_context.mode.installTime == InstallMode::InstallTime::PRELOAD
273 && m_context.mode.extension == InstallMode::ExtensionType::DIR)) {
275 DPL::ScopedFClose inFile(openFile(fileName, "r"));
276 DPL::ScopedFClose outFile(openFile(encFile, "w"));
278 const std::size_t chunkSize = (fileSize > ENCRYPTION_CHUNK_MAX_SIZE
279 ? ENCRYPTION_CHUNK_MAX_SIZE : fileSize);
281 std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
282 std::size_t bytesRead = 0;
283 /* TODO : pkgId should change to appId after wrt-client label changed. */
284 std::string pkgId = DPL::ToUTF8String(m_context.widgetConfig.tzPkgid);
288 bytesRead = readBytes(inChunk.get(), chunkSize, inFile.Get());
289 if (0 != bytesRead) {
291 char *outChunk = NULL;
292 if (0 != ssmEncrypt(m_context.mode.rootPath, pkgId,
293 (char*)inChunk.get(), (int)bytesRead,
294 &outChunk, &outDecSize)) {
295 ThrowMsg(Exceptions::EncryptionFailed,
296 "Encryption Failed using TrustZone");
299 std::stringstream toString;
300 toString << outDecSize;
302 writeBytes((unsigned char*)toString.str().c_str(),
303 sizeof(int), outFile.Get());
304 writeBytes((unsigned char*)outChunk, outDecSize, outFile.Get());
307 inChunk.reset(new unsigned char[chunkSize]);
309 } while (0 == std::feof(inFile.Get()));
314 LogDebug("File encrypted successfully");
315 LogDebug("Remove plain-text file: " << fileName);
316 if (0 != unlink(fileName.c_str()))
318 Throw(Exceptions::EncryptionFailed);
321 LogDebug("Rename encrypted file");
322 if (0 != std::rename(encFile.c_str(), fileName.c_str()))
324 Throw(Exceptions::EncryptionFailed);
328 std::string realPath = fileName;
330 m_context.locations->getTemporaryRootDir().length(),
331 m_context.locations->getSourceDir());
333 WrtDB::EncryptedFileInfo fileInfo;
334 fileInfo.fileName = DPL::FromUTF8String(realPath);
335 fileInfo.fileSize = fileSize;
337 m_context.widgetConfig.encryptedFiles.insert(fileInfo);
340 void TaskEncryptResource::StartStep()
342 LogDebug("--------- <TaskEncryptResource> : START ----------");
345 void TaskEncryptResource::EndStep()
347 m_context.job->UpdateProgress(
348 InstallerContext::INSTALL_ECRYPTION_FILES,
349 "Ecrypt resource files");
351 LogDebug("--------- <TaskEncryptResource> : END ----------");
353 } //namespace WidgetInstall