#include <boost/system/error_code.hpp>
#include <common/utils/file_util.h>
+#include <common/utils/byte_size_literals.h>
#include <manifest_parser/utils/logging.h>
+#include <sys/stat.h>
#include <algorithm>
#include <cstdio>
namespace {
+const std::size_t kEncryptionChunkMaxSize = 8_kB; // bytes
const std::set<std::string> encryptSet { ".html", ".htm", ".css", ".js"};
+FILE* OpenFile(const std::string& path, const std::string& mode) {
+ FILE* result = nullptr;
+
+ do {
+ result = fopen(path.c_str(), mode.c_str());
+ } while ((nullptr == result));
+
+ return result;
+}
+
+std::size_t ReadBytes(unsigned char* buffer, std::size_t count, FILE* stream) {
+ std::size_t result = std::fread(buffer,
+ 1,
+ count,
+ stream);
+ if (result != count) {
+ if (0 != std::ferror(stream)) {
+ LOG(ERROR) << "Error while reading data";
+ }
+ }
+
+ return result;
+}
+
+void WriteBytes(unsigned char* buffer, std::size_t count, FILE* stream) {
+ // original file is treated as destination!
+ std::size_t bytes_written = 0;
+ std::size_t bytes_to_write = 0;
+ do {
+ bytes_to_write = count - bytes_written;
+ bytes_written = std::fwrite(buffer + bytes_written,
+ sizeof(unsigned char),
+ count - bytes_written,
+ stream);
+ if ((bytes_written != bytes_to_write)) {
+ LOG(ERROR) << "Error while writing data";
+ free(buffer);
+ fclose(stream);
+ }
+ } while ((bytes_written != bytes_to_write));
+}
+
} // namespace
}
bool StepEncryptResources::EncryptFile(const bf::path &src) {
- FILE *input = fopen(src.string().c_str(), "rb");
- if (!input) {
- LOG(ERROR) << "Cannot open file for encryption: " << src;
+ bf::path encFile(src.string() + ".enc");
+ struct stat info;
+ memset(&info, 0, sizeof(info));
+ if (stat(src.string().c_str(), &info) != 0) {
+ LOG(ERROR) << "Could not access file " << src.string();
return false;
}
-
- // read size
- fseek(input , 0 , SEEK_END);
- size_t length = ftell(input);
-
- // don't encrypt empty files because libwebappenc doesn't support it
- if (length == 0) {
- fclose(input);
+ const std::size_t fileSize = info.st_size;
+ if (0 == fileSize) {
+ LOG(ERROR) << src.string().c_str() << " size is 0, so encryption is skiped";
return true;
}
- rewind(input);
-
- char *input_buffer = new char[length];
- if (length != fread(input_buffer, sizeof(char), length, input)) {
- LOG(ERROR) << "Read error, file: " << src;
- fclose(input);
- delete []input_buffer;
+ FILE *input = OpenFile(src.string().c_str(), "rb");
+ if (input == nullptr) {
+ LOG(ERROR) << "Cannot open file for encryption: " << src.string();
return false;
}
- fclose(input);
- unsigned char* encrypted_data = nullptr;
- size_t enc_data_len = 0;
- int ret;
- if (context_->request_mode.get() == common_installer::RequestMode::GLOBAL)
- ret = wae_encrypt_global_web_application(
- context_->pkgid.get().c_str(),
- context_->is_preload_request.get() ?
- true : false,
- reinterpret_cast<const unsigned char*>(input_buffer),
- length,
- &encrypted_data,
- &enc_data_len);
- else
- ret = wae_encrypt_web_application(
- context_->uid.get(),
- context_->pkgid.get().c_str(),
- reinterpret_cast<const unsigned char*>(input_buffer),
- length,
- &encrypted_data,
- &enc_data_len);
- delete []input_buffer;
- if (WAE_ERROR_NONE != ret) {
- switch (ret) {
- case WAE_ERROR_INVALID_PARAMETER:
- LOG(ERROR) << "Error during encrypting: WAE_ERROR_INVALID_PARAMETER";
- break;
- case WAE_ERROR_PERMISSION_DENIED:
- LOG(ERROR) << "Error during encrypting: WAE_ERROR_PERMISSION_DENIED";
- break;
- case WAE_ERROR_NO_KEY:
- LOG(ERROR) << "Error during encrypting: WAE_ERROR_NO_KEY";
- break;
- case WAE_ERROR_KEY_MANAGER:
- LOG(ERROR) << "Error during encrypting: WAE_ERROR_KEY_MANAGER";
- break;
- case WAE_ERROR_CRYPTO:
- LOG(ERROR) << "Error during encrypting: WAE_ERROR_CRYPTO";
- break;
- case WAE_ERROR_UNKNOWN:
- LOG(ERROR) << "Error during encrypting: WAE_ERROR_UNKNOWN";
- break;
- default:
- LOG(ERROR) << "Error during encrypting: UNKNOWN";
- break;
- }
+ FILE *output = OpenFile(encFile.string().c_str(), "wb");
+ if (output == nullptr) {
+ LOG(ERROR) << "Cannot create encrypted file: " << encFile.string();
return false;
}
- // original file is treated as destination!
- FILE *output = fopen(src.string().c_str(), "wb");
- if (!output) {
- LOG(ERROR) << "Cannot create encrypted file: " << src;
- free(encrypted_data);
+ std::size_t chunkSize = (fileSize > kEncryptionChunkMaxSize
+ ? kEncryptionChunkMaxSize : fileSize);
+
+ std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
+ std::size_t bytesRead = 0;
+
+ do {
+ bytesRead = ReadBytes(inChunk.get(), chunkSize, input);
+ if (0 != bytesRead) {
+ unsigned char* encrypted_data = nullptr;
+ size_t encrypted_size = 0;
+ // TODO(p.sikorski) check if it is Preloaded
+ int ret;
+ if (context_->request_mode.get() == common_installer::RequestMode::GLOBAL) {
+ ret = wae_encrypt_global_web_application(
+ context_->pkgid.get().c_str(),
+ context_->is_preload_request.get() ?
+ true : false,
+ inChunk.get(),
+ (size_t)bytesRead,
+ &encrypted_data,
+ &encrypted_size);
+ } else {
+ ret = wae_encrypt_web_application(
+ context_->uid.get(),
+ context_->pkgid.get().c_str(),
+ inChunk.get(),
+ (size_t)bytesRead,
+ &encrypted_data,
+ &encrypted_size);
+ }
+
+ if (WAE_ERROR_NONE != ret) {
+ LOG(ERROR) << "Error during encrypting:";
+ switch (ret) {
+ case WAE_ERROR_INVALID_PARAMETER:
+ LOG(ERROR) << "WAE_ERROR_INVALID_PARAMETER";
+ break;
+ case WAE_ERROR_PERMISSION_DENIED:
+ LOG(ERROR) << "WAE_ERROR_PERMISSION_DENIED";
+ break;
+ case WAE_ERROR_NO_KEY:
+ LOG(ERROR) << "WAE_ERROR_NO_KEY";
+ break;
+ case WAE_ERROR_KEY_MANAGER:
+ LOG(ERROR) << "WAE_ERROR_KEY_MANAGER";
+ break;
+ case WAE_ERROR_CRYPTO:
+ LOG(ERROR) << "WAE_ERROR_CRYPTO";
+ break;
+ case WAE_ERROR_UNKNOWN:
+ LOG(ERROR) << "WAE_ERROR_UNKNOWN";
+ break;
+ default:
+ LOG(ERROR) << "UNKNOWN";
+ break;
+ }
+ fclose(output);
+ fclose(input);
+ return false;
+ }
+
+ if (encrypted_size <= 0) {
+ LOG(ERROR) << "Encryption Failed using TrustZone";
+ fclose(output);
+ fclose(input);
+ return false;
+ }
+
+ std::stringstream toString;
+ toString << encrypted_size;
+
+ WriteBytes((unsigned char*)toString.str().c_str(), sizeof(int), output);
+ WriteBytes((unsigned char*)encrypted_data, encrypted_size, output);
+ free(encrypted_data);
+ }
+ inChunk.reset(new unsigned char[chunkSize]);
+
+ } while (!std::feof(input));
+
+ fclose(output);
+ fclose(input);
+
+ LOG(DEBUG) << "File encrypted successfully";
+ if (0 != unlink(src.string().c_str())) {
return false;
}
- if (enc_data_len != fwrite(reinterpret_cast<const char*>(encrypted_data),
- sizeof(char),
- enc_data_len,
- output)) {
- LOG(ERROR) << "Write error, file: " << src;
- free(encrypted_data);
- fclose(output);
+ LOG(DEBUG) << "Rename encrypted file";
+ if (0 != std::rename(encFile.c_str(), src.string().c_str())) {
return false;
}
-
- fclose(output);
- free(encrypted_data);
return true;
}