From: JongHeon Choi Date: Thu, 28 Jul 2016 06:19:06 +0000 (+0900) Subject: File encryption method reading whole files into a dynamic stack buffer X-Git-Tag: submit/tizen/20160831.042125^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a1af58e5c609671447bbc3d455a3004bc4442c61;p=platform%2Fcore%2Fappfw%2Fwgt-backend.git File encryption method reading whole files into a dynamic stack buffer Related changes: [crosswalk-tizen] https://github.com/crosswalk-project/crosswalk-tizen/pull/135 https://review.tizen.org/gerrit/#/c/83459/ Change-Id: I87d41c578e161622035e65e324b3d9590e2c266e --- diff --git a/src/wgt/step/encryption/step_encrypt_resources.cc b/src/wgt/step/encryption/step_encrypt_resources.cc index ad5485f..4d5fb91 100644 --- a/src/wgt/step/encryption/step_encrypt_resources.cc +++ b/src/wgt/step/encryption/step_encrypt_resources.cc @@ -10,8 +10,10 @@ #include #include +#include #include +#include #include #include @@ -21,8 +23,51 @@ namespace { +const std::size_t kEncryptionChunkMaxSize = 8_kB; // bytes const std::set 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 @@ -105,102 +150,124 @@ bool StepEncryptResources::Encrypt(const bf::path &src) { } 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(input_buffer), - length, - &encrypted_data, - &enc_data_len); - else - ret = wae_encrypt_web_application( - context_->uid.get(), - context_->pkgid.get().c_str(), - reinterpret_cast(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 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(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; }