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));
170 int ssmEncrypt(InstallMode::InstallTime time, std::string pkgId, const char*
171 inChunk, int inBytes, char** outChunk, int *outBytes)
173 if (time == InstallMode::InstallTime::PRELOAD) {
174 return ssm_encrypt_preloaded_application(inChunk, inBytes, outChunk, outBytes);
176 return ssm_encrypt(pkgId.c_str(),pkgId.length(), inChunk, inBytes, outChunk, outBytes);
183 namespace WidgetInstall {
184 TaskEncryptResource::TaskEncryptResource(InstallerContext& context) :
185 DPL::TaskDecl<TaskEncryptResource>(this),
188 AddStep(&TaskEncryptResource::StartStep);
189 AddStep(&TaskEncryptResource::StepEncryptResource);
190 AddStep(&TaskEncryptResource::EndStep);
193 void TaskEncryptResource::StepEncryptResource()
195 _D("Step Encrypt resource");
197 EncryptDirectory(m_context.locations->getSourceDir());
200 void TaskEncryptResource::EncryptDirectory(std::string path)
204 char * const paths[] = { const_cast<char * const>(path.c_str()), NULL };
206 if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
209 _W("%s: fts_open failed with error: %s", __PRETTY_FUNCTION__, strerror(error));
210 ThrowMsg(Exceptions::EncryptionFailed, "Error reading directory: "
214 while ((ftsent = fts_read(fts)) != NULL) {
215 switch (ftsent->fts_info) {
221 //directories, non-regular files, dangling symbolic links
226 //regular files and other objects that can be counted
227 if (isSupportedForEncryption(ftsent->fts_path)) {
228 EncryptFile(ftsent->fts_path);
236 _W("%s: traversal failed on file: %s with error: %s", __PRETTY_FUNCTION__, ftsent->fts_path, strerror(ftsent->fts_errno));
237 ThrowMsg(Exceptions::EncryptionFailed, "Error reading file");
242 if (fts_close(fts) == -1) {
244 _W("%s: fts_close failed with error: %s", __PRETTY_FUNCTION__, strerror(error));
248 void TaskEncryptResource::EncryptFile(const std::string &fileName)
250 _D("Encrypt file: %s", fileName.c_str());
251 std::string encFile = fileName + ".enc";
254 memset(&info, 0, sizeof(info));
255 if (stat(fileName.c_str(), &info) != 0)
258 ThrowMsg(Exceptions::EncryptionFailed,
259 "Could not access file " << fileName <<
260 "[" << DPL::GetErrnoString(error) << "]");
262 const std::size_t fileSize = info.st_size;
264 _D("%s size is 0, so encryption is skiped", fileName.c_str());
268 // If update installed preload web, should skip encryption.
269 if (!(m_context.mode.rootPath == InstallMode::RootPath::RO &&
270 (m_context.mode.installTime == InstallMode::InstallTime::PRELOAD
271 || m_context.mode.installTime == InstallMode::InstallTime::FOTA)
272 && m_context.mode.extension == InstallMode::ExtensionType::DIR)) {
274 DPL::ScopedFClose inFile(openFile(fileName, "r"));
275 DPL::ScopedFClose outFile(openFile(encFile, "w"));
277 const std::size_t chunkSize = (fileSize > ENCRYPTION_CHUNK_MAX_SIZE
278 ? ENCRYPTION_CHUNK_MAX_SIZE : fileSize);
280 std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
281 std::size_t bytesRead = 0;
282 std::string pkgId = DPL::ToUTF8String(m_context.widgetConfig.tzPkgid);
286 bytesRead = readBytes(inChunk.get(), chunkSize, inFile.Get());
287 if (0 != bytesRead) {
289 char *outChunk = NULL;
290 if (0 != ssmEncrypt(m_context.mode.installTime, pkgId,
291 (char*)inChunk.get(), (int)bytesRead,
292 &outChunk, &outDecSize)) {
293 ThrowMsg(Exceptions::EncryptionFailed,
294 "Encryption Failed using TrustZone");
297 std::stringstream toString;
298 toString << outDecSize;
300 writeBytes((unsigned char*)toString.str().c_str(),
301 sizeof(int), outFile.Get());
302 writeBytes((unsigned char*)outChunk, outDecSize, outFile.Get());
305 inChunk.reset(new unsigned char[chunkSize]);
307 } while (0 == std::feof(inFile.Get()));
312 _D("File encrypted successfully");
313 _D("Remove plain-text file: %s", fileName.c_str());
314 if (0 != unlink(fileName.c_str()))
316 Throw(Exceptions::EncryptionFailed);
319 _D("Rename encrypted file");
320 if (0 != std::rename(encFile.c_str(), fileName.c_str()))
322 Throw(Exceptions::EncryptionFailed);
326 WrtDB::EncryptedFileInfo fileInfo;
327 fileInfo.fileName = DPL::FromUTF8String(fileName);
328 fileInfo.fileSize = fileSize;
330 m_context.widgetConfig.encryptedFiles.insert(fileInfo);
333 void TaskEncryptResource::StartStep()
335 LOGD("--------- <TaskEncryptResource> : START ----------");
338 void TaskEncryptResource::EndStep()
340 m_context.job->UpdateProgress(
341 InstallerContext::INSTALL_ECRYPTION_FILES,
342 "Ecrypt resource files");
344 LOGD("--------- <TaskEncryptResource> : END ----------");
346 } //namespace WidgetInstall