1 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by a apache 2.0 license that can be
3 // found in the LICENSE file.
5 #include "wgt/step/encryption/step_encrypt_resources.h"
7 #include <web_app_enc.h>
9 #include <boost/filesystem/operations.hpp>
10 #include <boost/system/error_code.hpp>
12 #include <common/utils/file_util.h>
13 #include <common/utils/byte_size_literals.h>
15 #include <manifest_parser/utils/logging.h>
26 const std::size_t kEncryptionChunkMaxSize = 8_kB; // bytes
27 const std::set<std::string> encryptSet { ".html", ".htm", ".css", ".js"};
29 FILE* OpenFile(const std::string& path, const std::string& mode) {
30 FILE* result = nullptr;
33 result = fopen(path.c_str(), mode.c_str());
34 } while ((nullptr == result));
39 std::size_t ReadBytes(unsigned char* buffer, std::size_t count, FILE* stream) {
40 std::size_t result = std::fread(buffer,
44 if (result != count) {
45 if (0 != std::ferror(stream)) {
46 LOG(ERROR) << "Error while reading data";
53 void WriteBytes(unsigned char* buffer, std::size_t count, FILE* stream) {
54 // original file is treated as destination!
55 std::size_t bytes_written = 0;
56 std::size_t bytes_to_write = 0;
58 bytes_to_write = count - bytes_written;
59 bytes_written = std::fwrite(buffer + bytes_written,
60 sizeof(unsigned char),
61 count - bytes_written,
63 if ((bytes_written != bytes_to_write)) {
64 LOG(ERROR) << "Error while writing data";
68 } while ((bytes_written != bytes_to_write));
75 namespace encryption {
77 namespace bf = boost::filesystem;
78 namespace bs = boost::system;
80 common_installer::Step::Status StepEncryptResources::precheck() {
81 backend_data_ = static_cast<WgtBackendData*>(context_->backend_data.get());
83 LOG(ERROR) << "no backend data";
84 return common_installer::Step::Status::ERROR;
90 LOG(ERROR) << "unpacked_dir_path attribute is empty";
91 return Step::Status::INVALID_VALUE;
93 if (!bf::exists(input_)) {
94 LOG(ERROR) << "unpacked_dir_path (" << input_ << ") path does not exist";
95 return Step::Status::INVALID_VALUE;
98 return common_installer::Step::Status::OK;
101 common_installer::Step::Status StepEncryptResources::process() {
102 if (!backend_data_->settings.get().encryption_enabled()) {
103 LOG(DEBUG) << "no encryption";
104 return common_installer::Step::Status::OK;
106 LOG(DEBUG) << "Encrypting";
108 if (!Encrypt(input_)) {
109 LOG(ERROR) << "Error during encryption";
110 return common_installer::Step::Status::ERROR;
113 return common_installer::Step::Status::OK;
116 bool StepEncryptResources::Encrypt(const bf::path &src) {
117 // traversing through src dir (recurrence if subdir found)
118 // for every file found, check if it should be encrypted (ToBeEncrypted)
119 // if yes, encrypt it (and replace original one)
121 for (bf::directory_iterator file(src);
122 file != bf::directory_iterator();
124 bs::error_code error_code;
125 bf::path current(file->path());
127 bool is_dir = bf::is_directory(current, error_code);
131 if (!Encrypt(current))
136 bool is_sym = bf::is_symlink(symlink_status(current, error_code));
142 // it is regular file (not dir, not symlink)
143 if (ToBeEncrypted(current)) {
144 LOG(INFO) << "File for encryption: " << current;
145 if (!EncryptFile(current))
152 bool StepEncryptResources::EncryptFile(const bf::path &src) {
153 bf::path encFile(src.string() + ".enc");
155 memset(&info, 0, sizeof(info));
156 if (stat(src.string().c_str(), &info) != 0) {
157 LOG(ERROR) << "Could not access file " << src.string();
160 const std::size_t fileSize = info.st_size;
162 LOG(ERROR) << src.string().c_str() << " size is 0, so encryption is skiped";
166 FILE *input = OpenFile(src.string().c_str(), "rb");
167 if (input == nullptr) {
168 LOG(ERROR) << "Cannot open file for encryption: " << src.string();
172 FILE *output = OpenFile(encFile.string().c_str(), "wb");
173 if (output == nullptr) {
174 LOG(ERROR) << "Cannot create encrypted file: " << encFile.string();
178 std::size_t chunkSize = (fileSize > kEncryptionChunkMaxSize
179 ? kEncryptionChunkMaxSize : fileSize);
181 std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
182 std::size_t bytesRead = 0;
185 bytesRead = ReadBytes(inChunk.get(), chunkSize, input);
186 if (0 != bytesRead) {
187 unsigned char* encrypted_data = nullptr;
188 size_t encrypted_size = 0;
189 // TODO(p.sikorski) check if it is Preloaded
191 if (context_->request_mode.get() == common_installer::RequestMode::GLOBAL) {
192 ret = wae_encrypt_global_web_application(
193 context_->pkgid.get().c_str(),
194 context_->is_preload_request.get() ?
201 ret = wae_encrypt_web_application(
203 context_->pkgid.get().c_str(),
210 if (WAE_ERROR_NONE != ret) {
211 LOG(ERROR) << "Error during encrypting:";
213 case WAE_ERROR_INVALID_PARAMETER:
214 LOG(ERROR) << "WAE_ERROR_INVALID_PARAMETER";
216 case WAE_ERROR_PERMISSION_DENIED:
217 LOG(ERROR) << "WAE_ERROR_PERMISSION_DENIED";
219 case WAE_ERROR_NO_KEY:
220 LOG(ERROR) << "WAE_ERROR_NO_KEY";
222 case WAE_ERROR_KEY_MANAGER:
223 LOG(ERROR) << "WAE_ERROR_KEY_MANAGER";
225 case WAE_ERROR_CRYPTO:
226 LOG(ERROR) << "WAE_ERROR_CRYPTO";
228 case WAE_ERROR_UNKNOWN:
229 LOG(ERROR) << "WAE_ERROR_UNKNOWN";
232 LOG(ERROR) << "UNKNOWN";
240 if (encrypted_size <= 0) {
241 LOG(ERROR) << "Encryption Failed using TrustZone";
247 std::stringstream toString;
248 toString << encrypted_size;
250 WriteBytes((unsigned char*)toString.str().c_str(), sizeof(int), output);
251 WriteBytes((unsigned char*)encrypted_data, encrypted_size, output);
252 free(encrypted_data);
254 inChunk.reset(new unsigned char[chunkSize]);
256 } while (!std::feof(input));
261 LOG(DEBUG) << "File encrypted successfully";
262 if (0 != unlink(src.string().c_str())) {
266 LOG(DEBUG) << "Rename encrypted file";
267 if (0 != std::rename(encFile.c_str(), src.string().c_str())) {
274 void StepEncryptResources::SetEncryptionRoot() {
275 input_ = context_->unpacked_dir_path.get();
278 bool StepEncryptResources::ToBeEncrypted(const bf::path &file) {
279 size_t found_key = file.string().rfind(".");
280 if (std::string::npos != found_key) {
281 std::string mimeType = file.string().substr(found_key);
282 std::transform(mimeType.begin(), mimeType.end(), mimeType.begin(),
284 return encryptSet.count(mimeType) > 0;
289 } // namespace encryption