[Release] wrt-installer_0.1.55
[framework/web/wrt-installer.git] / src / jobs / widget_install / task_encrypt_resource.cpp
index 2ea97ee..0b47580 100644 (file)
 #undef __USE_FILE_OFFSET64
 
 #include <unistd.h>
-#include <string>
 #include <sys/stat.h>
 #include <fts.h>
 #include <string.h>
 #include <errno.h>
+#include <cstdio>
+#include <sstream>
+#include<iostream>
+
+#include <memory>
 
 #include <dpl/log/log.h>
 #include <dpl/errno_string.h>
 #include <dpl/foreach.h>
+#include <dpl/scoped_fclose.h>
 #include <dpl/wrt-dao-ro/global_config.h>
+#include <dpl/string.h>
+#include <FBaseByteBuffer.h>
+#include <security/FSecCrypto_TrustZoneService.h>
 
 #include <widget_install/job_widget_install.h>
 #include <widget_install/widget_install_context.h>
 #include <widget_install/widget_install_errors.h>
 
 using namespace WrtDB;
-using namespace WRTEncryptor;
+
+extern "C"
+{
+    void InitWebAppInfo(const char* appId, const char* rootPath);
+}
 
 namespace {
+const std::size_t ENCRYPTION_CHUNK_MAX_SIZE = 4096; // bytes
+const std::size_t ENCRYPTION_DEC_CHUNK_SIZE = 4; // bytes
+static bool initWebApp = false;
+
 std::set<std::string>& getSupportedForEncryption()
 {
     static std::set<std::string> encryptSet;
@@ -63,6 +79,150 @@ bool isSupportedForEncryption(const std::string &file)
     }
     return false;
 }
+
+/**
+ * Opens a file.
+ *
+ * @param path Path to a file.
+ * @param mode Mode.
+ * @return Stream handle.
+ * @throw ExtractFileFailed If error (other than EINTR) occurs.
+ */
+FILE* openFile(const std::string& path, const std::string& mode)
+{
+    FILE* result = NULL;
+
+    do
+    {
+        result = fopen(path.c_str(), mode.c_str());
+    } while ((NULL == result) && (EINTR == errno));
+
+    if (NULL == result)
+    {
+        ThrowMsg(Jobs::WidgetInstall::Exceptions::EncryptionFailed,
+                 "Could not open file " << path);
+    }
+
+    return result;
+}
+
+/**
+ * Reads bytes from a stream.
+ *
+ * @param buffer Buffer to read the bytes into.
+ * @param count Number of bytes to read.
+ * @param stream Stream to read from.
+ * @return Number of bytes read
+ * @throw ExtractFileFailed If error (other than EINTR) occurs.
+ */
+std::size_t readBytes(unsigned char* buffer, std::size_t count, FILE* stream)
+{
+    std::size_t result = std::fread(buffer,
+                                    sizeof(unsigned char),
+                                    count,
+                                    stream);
+
+    if (result != count)
+    {
+        int error = errno;
+        if (0 != std::ferror(stream))
+        {
+            if (EINTR != error)
+            {
+                ThrowMsg(Jobs::WidgetInstall::Exceptions::ErrorExternalInstallingFailure,
+                         "Error while reading data" <<
+                         " [" << DPL::GetErrnoString(error) << "]");
+            }
+        }
+    }
+
+    return result;
+}
+
+/**
+ * Writes bytes to a stream.
+ *
+ * @param buffer Data to write.
+ * @param count Number of bytes.
+ * @param stream Stream to write to.
+ * @throw ExtractFileFailed If error (other than EINTR) occurs.
+ */
+void writeBytes(unsigned char* buffer, std::size_t count, FILE* stream)
+{
+    std::size_t bytesWritten = 0;
+    std::size_t bytesToWrite = 0;
+    do
+    {
+        bytesToWrite = count - bytesWritten;
+        bytesWritten = std::fwrite(buffer + bytesWritten,
+                                   sizeof(unsigned char),
+                                   count - bytesWritten,
+                                   stream);
+        if ((bytesWritten != bytesToWrite) && (EINTR != errno))
+        {
+            int error = errno;
+            ThrowMsg(Jobs::WidgetInstall::Exceptions::EncryptionFailed,
+                     "Error while writing data" <<
+                     " [" << DPL::GetErrnoString(error) << "]");
+        }
+    } while ((bytesWritten != bytesToWrite) && (EINTR == errno));
+}
+
+/*
+ * get encrypted string from trustzone
+*/
+Tizen::Base::ByteBuffer* EncryptChunkByTrustZone(
+        Tizen::Base::ByteBuffer* appInfo,
+        const unsigned char *plainBuffer,
+        int pBufSize)
+{
+    using namespace Tizen::Base;
+    if(!initWebApp)
+    {
+        char* pAppId = null;
+        pAppId = (char*)calloc(appInfo->GetRemaining()+1, 1);
+        memcpy(pAppId, appInfo->GetPointer(), appInfo->GetRemaining());
+        InitWebAppInfo(pAppId, "");
+        free (pAppId);
+        initWebApp = true;
+    }
+
+    Tizen::Security::Crypto::_TrustZoneService* pInstance;
+    pInstance = Tizen::Security::Crypto::_TrustZoneService::GetInstance();
+
+    ByteBuffer pBuf;
+    pBuf.Construct(pBufSize);
+    const byte *pByte = reinterpret_cast<const byte*>(plainBuffer);
+    if (pBuf.SetArray(pByte, 0, pBufSize) != E_SUCCESS) {
+        LogDebug("Couldnot set pBuf");
+        return NULL;
+    }
+    pBuf.Flip();
+
+    return pInstance->_TrustZoneService::EncryptN(*appInfo, pBuf);
+}
+
+Tizen::Base::ByteBuffer* TEST_dec(
+        Tizen::Base::ByteBuffer* appInfo,
+        const unsigned char *plainBuffer,
+        int pBufSize)
+{
+    using namespace Tizen::Base;
+
+    Tizen::Security::Crypto::_TrustZoneService* pInstance;
+    pInstance = Tizen::Security::Crypto::_TrustZoneService::GetInstance();
+
+    ByteBuffer pBuf;
+    pBuf.Construct(pBufSize);
+    const byte *pByte = reinterpret_cast<const byte*>(plainBuffer);
+    if (pBuf.SetArray(pByte, 0, pBufSize) != E_SUCCESS) {
+        LogDebug("Couldnot set pBuf");
+        return NULL;
+    }
+    pBuf.Flip();
+
+    return pInstance->_TrustZoneService::DecryptN(*appInfo, pBuf);
+}
 }
 
 namespace Jobs {
@@ -77,135 +237,170 @@ TaskEncryptResource::TaskEncryptResource(InstallerContext& context) :
 void TaskEncryptResource::StepEncryptResource()
 {
     LogDebug("Step Encrypt resource");
-    m_resEnc = new ResourceEncryptor;
-    m_resEnc->CreateEncryptionKey(DPL::ToUTF8String(*m_context.
-                widgetConfig.pkgname));
 
     EncryptDirectory(m_context.locations->getTemporaryRootDir());
+    m_context.job->UpdateProgress(
+            InstallerContext::INSTALL_ECRYPTION_FILES,
+            "Ecrypt resource files");
 }
 
 void TaskEncryptResource::EncryptDirectory(std::string path)
 {
     FTS *fts;
     FTSENT *ftsent;
-    char * const paths[] = {const_cast<char * const>(path.c_str()), NULL};
+    char * const paths[] = { const_cast<char * const>(path.c_str()), NULL };
 
-    if ((fts = fts_open(paths, FTS_PHYSICAL|FTS_NOCHDIR, NULL)) == NULL) {
+    if ((fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR, NULL)) == NULL) {
         //ERROR
         int error = errno;
         LogWarning(__PRETTY_FUNCTION__ << ": fts_open failed with error: "
-                << strerror(error));
-        ThrowMsg(Exceptions::InternalError, "Error reading directory: "
-                << path);
+                                       << strerror(error));
+        ThrowMsg(Exceptions::EncryptionFailed, "Error reading directory: "
+                 << path);
     }
 
     while ((ftsent = fts_read(fts)) != NULL) {
         switch (ftsent->fts_info) {
-            case FTS_DP:
-            case FTS_DC:
-            case FTS_D:
-            case FTS_DEFAULT:
-            case FTS_SLNONE:
-                //directories, non-regular files, dangling symbolic links
-                break;
-            case FTS_F:
-            case FTS_NSOK:
-            case FTS_SL:
-                //regular files and other objects that can be counted
-                if (isSupportedForEncryption(ftsent->fts_path)) {
-                    EncryptFile(ftsent->fts_path);
-                }
-                break;
-            case FTS_NS:
-            case FTS_DOT:
-            case FTS_DNR:
-            case FTS_ERR:
-            default:
-                LogWarning(__PRETTY_FUNCTION__
-                        << ": traversal failed on file: "
-                        << ftsent->fts_path
-                        << " with error: "
-                        << strerror(ftsent->fts_errno));
-                ThrowMsg(Exceptions::InternalError, "Error reading file");
+        case FTS_DP:
+        case FTS_DC:
+        case FTS_D:
+        case FTS_DEFAULT:
+        case FTS_SLNONE:
+            //directories, non-regular files, dangling symbolic links
+            break;
+        case FTS_F:
+        case FTS_NSOK:
+        case FTS_SL:
+            //regular files and other objects that can be counted
+            if (isSupportedForEncryption(ftsent->fts_path)) {
+                EncryptFile(ftsent->fts_path);
+            }
+            break;
+        case FTS_NS:
+        case FTS_DOT:
+        case FTS_DNR:
+        case FTS_ERR:
+        default:
+            LogWarning(__PRETTY_FUNCTION__
+                       << ": traversal failed on file: "
+                       << ftsent->fts_path
+                       << " with error: "
+                       << strerror(ftsent->fts_errno));
+            ThrowMsg(Exceptions::EncryptionFailed, "Error reading file");
+            break;
         }
     }
 
     if (fts_close(fts) == -1) {
         int error = errno;
         LogWarning(__PRETTY_FUNCTION__ << ": fts_close failed with error: "
-                << strerror(error));
+                                       << strerror(error));
     }
 }
 
 void TaskEncryptResource::EncryptFile(const std::string &fileName)
 {
-    Try
+    LogDebug("Encrypt file: " << fileName);
+    std::string encFile = fileName + ".enc";
+
+    struct stat info;
+    memset(&info, 0, sizeof(info));
+    if (stat(fileName.c_str(), &info) != 0)
     {
-        LogDebug("Need to ecnrypt file Name " << fileName);
-        std::string encFile = fileName + ".enc";
-
-        struct stat buf;
-        int ret = stat(fileName.c_str(), &buf);
-        if(ret == 0) {
-            size_t fileSize = buf.st_size;
-
-            FILE* resFp = fopen(fileName.c_str(), "r");
-            if ( NULL == resFp) {
-                LogError("Couldnot open file : " << fileName);
-                return;
-            }
+        int error = errno;
+        ThrowMsg(Exceptions::EncryptionFailed,
+                "Could not access file " << fileName <<
+                "[" << DPL::GetErrnoString(error) << "]");
+    }
+    const std::size_t fileSize = info.st_size;
+    if (0 == fileSize) {
+        LogDebug(fileName << " size is 0, so encryption is skiped");
+        return;
+    }
 
-            int blockSize = m_resEnc->GetBlockSize(fileSize);
-            LogDebug("Get block size : " << blockSize);
+    DPL::ScopedFClose inFile(openFile(fileName, "r"));
+    DPL::ScopedFClose outFile(openFile(encFile, "w"));
 
-            unsigned char readBuf[fileSize];
-            unsigned char outEncBuf[blockSize];
-            memset(readBuf, 0, fileSize);
-            memset(outEncBuf, 0, blockSize);
+    const std::size_t chunkSize = (fileSize > ENCRYPTION_CHUNK_MAX_SIZE
+            ? ENCRYPTION_CHUNK_MAX_SIZE : fileSize);
 
-            ret = fread(readBuf, sizeof(unsigned char), fileSize, resFp);
-            if (ret!=fileSize){
-                LogError("Failed to read ecryption buffer with error: " << strerror(errno) );
-                fclose(resFp);
-               return;
-            }
+    std::unique_ptr<unsigned char[]> inChunk(new unsigned char[chunkSize]);
+    std::unique_ptr<unsigned char[]> outChunk;
 
-            m_resEnc->EncryptChunk(readBuf, outEncBuf, fileSize);
+    std::size_t bytesRead = 0;
+    using namespace Tizen::Base;
 
-            FILE* encFp = fopen(encFile.c_str(), "w");
-            if (NULL == encFp) {
-                LogError("Failed to open ecryption file");
-                fclose(resFp);
-                return;
-            }
-            fwrite(outEncBuf, sizeof(unsigned char), blockSize, encFp);
+    std::string pkgid =
+        DPL::ToUTF8String(m_context.widgetConfig.tzAppid).c_str();
+    const byte *b_pkgid = reinterpret_cast<const byte*>(
+            pkgid.c_str());
+    ByteBuffer appInfo;
+    appInfo.Construct(pkgid.length());
 
-            fclose(resFp);
-            fclose(encFp);
+    if (appInfo.SetArray(b_pkgid, 0, pkgid.length()) != E_SUCCESS) {
+        LogDebug("Couldnot set appInfo");
+        return;
+    }
 
-            LogDebug("Success to encrypt file");
-            LogDebug("Remove unecrypted file : " << fileName);
+    appInfo.Flip();
 
-            unlink(fileName.c_str());
-            if ((rename(encFile.c_str(), fileName.c_str())) != 0) {
-                ThrowMsg(Exceptions::ExtractFileFailed, fileName);
+    do
+    {
+        bytesRead = readBytes(inChunk.get(), chunkSize, inFile.Get());
+        if (0 != bytesRead) {
+            ByteBuffer *getBuffer = EncryptChunkByTrustZone(
+                    &appInfo,
+                    inChunk.get(), bytesRead);
+            if (getBuffer == NULL) {
+                ThrowMsg(Exceptions::EncryptionFailed,
+                        "Encryption Failed using TrustZone");
             }
+            int decBufSize = getBuffer->GetRemaining();
 
-            std::string realPath = fileName;
-            realPath.replace(0, m_context.locations->getTemporaryRootDir().length(),
-                    m_context.locations->getSourceDir());
+            outChunk.reset(new unsigned char[decBufSize]);
+            memcpy(outChunk.get(), getBuffer->GetPointer(), getBuffer->GetRemaining());
+            getBuffer->Reset();
 
-            WrtDB::EncryptedFileInfo info;
-            info.fileName = DPL::FromUTF8String(realPath);
-            info.fileSize = fileSize;
+            char writeSize[ENCRYPTION_DEC_CHUNK_SIZE];
+            memset(writeSize, 0x00, ENCRYPTION_DEC_CHUNK_SIZE);
+            std::stringstream toString;
+            toString << decBufSize;
+            strncpy(writeSize, toString.str().c_str(), toString.str().length());
 
-            m_context.widgetConfig.encryptedFiles.insert(info);
+            writeBytes((unsigned char*)writeSize,
+                    ENCRYPTION_DEC_CHUNK_SIZE, outFile.Get());
+            writeBytes(outChunk.get(), decBufSize, outFile.Get());
         }
+
+    } while (0 == std::feof(inFile.Get()));
+
+    outFile.Reset();
+    inFile.Reset();
+
+    LogDebug("File encrypted successfully");
+    LogDebug("Remove plain-text file: " << fileName);
+    if (0 != unlink(fileName.c_str()))
+    {
+        Throw(Exceptions::EncryptionFailed);
     }
-    Catch(ResourceEncryptor::Exception::Base)
+
+    LogDebug("Rename encrypted file");
+    if (0 != std::rename(encFile.c_str(), fileName.c_str()))
     {
-        ReThrowMsg(Exceptions::ExtractFileFailed, fileName);
+        Throw(Exceptions::EncryptionFailed);
     }
+
+    std::string realPath = fileName;
+    realPath.replace(0,
+            m_context.locations->getTemporaryRootDir().length(),
+            m_context.locations->getSourceDir());
+
+    WrtDB::EncryptedFileInfo fileInfo;
+    fileInfo.fileName = DPL::FromUTF8String(realPath);
+    fileInfo.fileSize = fileSize;
+
+    m_context.widgetConfig.encryptedFiles.insert(fileInfo);
 }
+
 } //namespace WidgetInstall
 } //namespace Jobs