VirtualBox

Changeset 54486 in vbox


Ignore:
Timestamp:
Feb 25, 2015 12:49:39 PM (10 years ago)
Author:
vboxsync
Message:

Main/Medium: Add basic support to encrypt/decrypt media, work in progress

Location:
trunk/src/VBox/Main
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r54438 r54486  
    1341713417  <interface
    1341813418    name="IMedium" extends="$unknown"
    13419     uuid="05f2bbb6-a3a6-4fb9-9b49-6d0dda7142ac"
     13419    uuid="e6aa3c67-6f51-4ba6-a012-cf4825069abb"
    1342013420    wsmap="managed"
    1342113421    >
     
    1466014660        </result>
    1466114661      </desc>
     14662      <param name="progress" type="IProgress" dir="return">
     14663        <desc>Progress object to track the operation completion.</desc>
     14664      </param>
     14665    </method>
     14666
     14667    <method name="changeEncryption">
     14668      <desc>
     14669        Starts encryption of this medium. This means that the stored data in the
     14670        medium is encrypted.
     14671
     14672        This medium will be placed to <link to="MediumState_LockedWrite"/>
     14673        state.
     14674
     14675        Please note that the results can be either returned straight away,
     14676        or later as the result of the background operation via the object
     14677        returned via the @a progress parameter.
     14678
     14679        <result name="VBOX_E_NOT_SUPPORTED">
     14680          Encryption is not supported for this medium because it is attached to more than one VM
     14681          or has children.
     14682        </result>
     14683      </desc>
     14684      <param name="newPassword" type="wstring" dir="in">
     14685        <desc>
     14686          The new password the medium should be protected with. Use an empty string
     14687          to indicate that the result should not be encrypted.
     14688        </desc>
     14689      </param>
     14690      <param name="oldPassword" type="wstring" dir="in">
     14691        <desc>
     14692          The old password the medium is protected with. Use an empty string to indicate
     14693          that the medium wasn't encrypted before.
     14694        </desc>
     14695      </param>
     14696      <param name="cipher" type="wstring" dir="in">
     14697        <desc>The cipher to use for encryption.</desc>
     14698      </param>
    1466214699      <param name="progress" type="IProgress" dir="return">
    1466314700        <desc>Progress object to track the operation completion.</desc>
  • trunk/src/VBox/Main/include/MediumImpl.h

    r53541 r54486  
    275275                   ComPtr<IProgress> &aProgress);
    276276    HRESULT reset(ComPtr<IProgress> &aProgress);
     277    HRESULT changeEncryption(const com::Utf8Str &aNewPassword, const com::Utf8Str &aOldPassword,
     278                             const com::Utf8Str &aCipher, ComPtr<IProgress> &aProgress);
    277279
    278280    // Private internal nmethods
     
    312314    static DECLCALLBACK(int) i_vdTcpGetPeerAddress(VDSOCKET Sock, PRTNETADDR pAddr);
    313315
     316    static DECLCALLBACK(bool) i_vdCryptoConfigAreKeysValid(void *pvUser,
     317                                                           const char *pszzValid);
     318    static DECLCALLBACK(int) i_vdCryptoConfigQuerySize(void *pvUser, const char *pszName,
     319                                                       size_t *pcbValue);
     320    static DECLCALLBACK(int) i_vdCryptoConfigQuery(void *pvUser, const char *pszName,
     321                                                   char *pszValue, size_t cchValue);
     322
     323    static DECLCALLBACK(int) i_vdCryptoKeyRetain(void *pvUser, const char *pszId,
     324                                                 const uint8_t **ppbKey, size_t *pcbKey);
     325    static DECLCALLBACK(int) i_vdCryptoKeyRelease(void *pvUser, const char *pszId);
     326    static DECLCALLBACK(int) i_vdCryptoKeyStoreGetPassword(void *pvUser, const char **ppszPassword);
     327    static DECLCALLBACK(int) i_vdCryptoKeyStoreSave(void *pvUser, const void *pvKeyStore, size_t cbKeyStore);
     328    static DECLCALLBACK(int) i_vdCryptoKeyStoreReturnParameters(void *pvUser, const char *pszCipher,
     329                                                                const uint8_t *pbDek, size_t cbDek);
     330
    314331    class Task;
    315332    class CreateBaseTask;
     
    323340    class ExportTask;
    324341    class ImportTask;
     342    class EncryptTask;
    325343    friend class Task;
    326344    friend class CreateBaseTask;
     
    334352    friend class ExportTask;
    335353    friend class ImportTask;
     354    friend class EncryptTask;
    336355
    337356    HRESULT i_startThread(Medium::Task *pTask);
     
    348367    HRESULT i_taskExportHandler(Medium::ExportTask &task);
    349368    HRESULT i_taskImportHandler(Medium::ImportTask &task);
     369    HRESULT i_taskEncryptHandler(Medium::EncryptTask &task);
     370
     371    struct CryptoFilterSettings;
     372    void i_taskEncryptSettingsSetup(CryptoFilterSettings *pSettings, const char *pszCipher,
     373                                    const char *pszKeyStore,  const char *pszPassword,
     374                                    bool fCreateKeyStore);
    350375
    351376    struct Data;            // opaque data struct, defined in MediumImpl.cpp
  • trunk/src/VBox/Main/src-server/MediumImpl.cpp

    r54438 r54486  
    2020#include "SystemPropertiesImpl.h"
    2121#include "VirtualBoxImpl.h"
     22#include "ExtPackManagerImpl.h"
    2223
    2324#include "AutoCaller.h"
     
    3536#include <iprt/tcp.h>
    3637#include <iprt/cpp/utils.h>
     38#include <iprt/memsafer.h>
     39#include <iprt/base64.h>
    3740
    3841#include <VBox/vd.h>
     
    4043#include <algorithm>
    4144#include <list>
     45
     46#include <openssl/rand.h>
    4247
    4348typedef std::list<Guid> GuidList;
     
    666671};
    667672
     673class Medium::EncryptTask : public Medium::Task
     674{
     675public:
     676    EncryptTask(Medium *aMedium,
     677                const com::Utf8Str &strNewPassword,
     678                const com::Utf8Str &strOldPassword,
     679                const com::Utf8Str &strCipher,
     680                Progress *aProgress,
     681                MediumLockList *aMediumLockList)
     682        : Medium::Task(aMedium, aProgress),
     683          mstrNewPassword(strNewPassword),
     684          mstrOldPassword(strOldPassword),
     685          mstrCipher(strCipher),
     686          mpMediumLockList(aMediumLockList)
     687    {
     688        AssertReturnVoidStmt(aMediumLockList != NULL, mRC = E_FAIL);
     689        /* aParent may be NULL */
     690        mRC = mParentCaller.rc();
     691        if (FAILED(mRC))
     692            return;
     693
     694        mVDImageIfaces = aMedium->m->vdImageIfaces;
     695    }
     696
     697    ~EncryptTask()
     698    {
     699        if (mstrNewPassword.length())
     700            RTMemWipeThoroughly(mstrNewPassword.mutableRaw(), mstrNewPassword.length(), 10 /* cPasses */);
     701        if (mstrOldPassword.length())
     702            RTMemWipeThoroughly(mstrOldPassword.mutableRaw(), mstrOldPassword.length(), 10 /* cPasses */);
     703        delete mpMediumLockList;
     704    }
     705
     706    Utf8Str mstrNewPassword;
     707    Utf8Str mstrOldPassword;
     708    Utf8Str mstrCipher;
     709    MediumLockList *mpMediumLockList;
     710    PVDINTERFACE    mVDImageIfaces;
     711
     712private:
     713    virtual HRESULT handler();
     714
     715    AutoCaller mParentCaller;
     716};
     717
     718/**
     719 * Settings for a crypto filter instance.
     720 */
     721struct Medium::CryptoFilterSettings
     722{
     723    CryptoFilterSettings()
     724        : fCreateKeyStore(false),
     725          pszPassword(NULL),
     726          pszKeyStore(NULL),
     727          pszKeyStoreLoad(NULL),
     728          pbDek(NULL),
     729          cbDek(0),
     730          pszCipher(NULL)
     731    { }
     732
     733    bool              fCreateKeyStore;
     734    const char        *pszPassword;
     735    char              *pszKeyStore;
     736    const char        *pszKeyStoreLoad;
     737
     738    const uint8_t     *pbDek;
     739    size_t            cbDek;
     740    const char        *pszCipher;
     741
     742    PVDINTERFACE      vdFilterIfaces;
     743
     744    VDINTERFACECONFIG vdIfCfg;
     745    VDINTERFACECRYPTO vdIfCrypto;
     746};
     747
    668748/**
    669749 * Thread function for time-consuming medium tasks.
     
    803883{
    804884    return mMedium->i_taskImportHandler(*this);
     885}
     886
     887/**
     888 * Implementation code for the "encrypt" task.
     889 */
     890HRESULT Medium::EncryptTask::handler()
     891{
     892    return mMedium->i_taskEncryptHandler(*this);
    805893}
    806894
     
    29343022
    29353023    LogFlowThisFunc(("LEAVE, rc=%Rhrc\n", rc));
     3024
     3025    return rc;
     3026}
     3027
     3028HRESULT Medium::changeEncryption(const com::Utf8Str &aNewPassword, const com::Utf8Str &aOldPassword,
     3029                                 const com::Utf8Str &aCipher, ComPtr<IProgress> &aProgress)
     3030{
     3031    HRESULT rc = S_OK;
     3032    ComObjPtr<Progress> pProgress;
     3033    Medium::Task *pTask = NULL;
     3034
     3035    try
     3036    {
     3037        AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     3038
     3039        DeviceType_T devType = i_getDeviceType();
     3040        /* Cannot encrypt DVD or floppy images so far. */
     3041        if (   devType == DeviceType_DVD
     3042            || devType == DeviceType_Floppy)
     3043            return setError(VBOX_E_INVALID_OBJECT_STATE,
     3044                            tr("Cannot encrypt DVD or Floppy medium '%s'"),
     3045                            m->strLocationFull.c_str());
     3046
     3047        /* Cannot encrypt child media so far. */
     3048        if (m->pParent)
     3049            return setError(VBOX_E_INVALID_OBJECT_STATE,
     3050                            tr("Cannot encrypt medium '%s' because it is a differencing medium"),
     3051                            m->strLocationFull.c_str());
     3052
     3053        /* Cannot encrypt media which are attached to more than one virtual machine. */
     3054        if (m->backRefs.size() > 1)
     3055            return setError(VBOX_E_INVALID_OBJECT_STATE,
     3056                            tr("Cannot encrypt medium '%s' because it is attached to %d virtual machines"),
     3057                            m->strLocationFull.c_str(), m->backRefs.size());
     3058
     3059        if (m->llChildren.size() != 0)
     3060            return setError(VBOX_E_INVALID_OBJECT_STATE,
     3061                            tr("Cannot encrypt medium '%s' because it has %d children"),
     3062                            m->strLocationFull.c_str(), m->llChildren.size());
     3063
     3064        /* Build the medium lock list. */
     3065        MediumLockList *pMediumLockList(new MediumLockList());
     3066        alock.release();
     3067        rc = i_createMediumLockList(true /* fFailIfInaccessible */ ,
     3068                                    true /* fMediumLockWrite */,
     3069                                    NULL,
     3070                                    *pMediumLockList);
     3071        alock.acquire();
     3072        if (FAILED(rc))
     3073        {
     3074            delete pMediumLockList;
     3075            throw rc;
     3076        }
     3077
     3078        alock.release();
     3079        rc = pMediumLockList->Lock();
     3080        alock.acquire();
     3081        if (FAILED(rc))
     3082        {
     3083            delete pMediumLockList;
     3084            throw setError(rc,
     3085                           tr("Failed to lock media when compacting '%s'"),
     3086                           i_getLocationFull().c_str());
     3087        }
     3088
     3089        pProgress.createObject();
     3090        rc = pProgress->init(m->pVirtualBox,
     3091                             static_cast <IMedium *>(this),
     3092                             BstrFmt(tr("Compacting medium '%s'"), m->strLocationFull.c_str()).raw(),
     3093                             TRUE /* aCancelable */);
     3094        if (FAILED(rc))
     3095        {
     3096            delete pMediumLockList;
     3097            throw rc;
     3098        }
     3099
     3100        /* setup task object to carry out the operation asynchronously */
     3101        pTask = new Medium::EncryptTask(this, aNewPassword, aOldPassword,
     3102                                        aCipher, pProgress, pMediumLockList);
     3103        rc = pTask->rc();
     3104        AssertComRC(rc);
     3105        if (FAILED(rc))
     3106            throw rc;
     3107    }
     3108    catch (HRESULT aRC) { rc = aRC; }
     3109
     3110    if (SUCCEEDED(rc))
     3111    {
     3112        rc = i_startThread(pTask);
     3113
     3114        if (SUCCEEDED(rc))
     3115            pProgress.queryInterfaceTo(aProgress.asOutParam());
     3116    }
     3117    else if (pTask != NULL)
     3118        delete pTask;
    29363119
    29373120    return rc;
     
    66026785    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
    66036786    return RTTcpGetPeerAddress(pSocketInt->hSocket, pAddr);
     6787}
     6788
     6789DECLCALLBACK(bool) Medium::i_vdCryptoConfigAreKeysValid(void *pvUser, const char *pszzValid)
     6790{
     6791    /* Just return always true here. */
     6792    return true;
     6793}
     6794
     6795DECLCALLBACK(int) Medium::i_vdCryptoConfigQuerySize(void *pvUser, const char *pszName, size_t *pcbValue)
     6796{
     6797    Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser;
     6798    AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
     6799    AssertReturn(VALID_PTR(pcbValue), VERR_INVALID_POINTER);
     6800
     6801    size_t cbValue = 0;
     6802    if (!strcmp(pszName, "Algorithm"))
     6803        cbValue = strlen(pSettings->pszCipher) + 1;
     6804    else if (!strcmp(pszName, "KeyStore"))
     6805        cbValue = RTBase64DecodedSize(pSettings->pszKeyStoreLoad, NULL) + 1;
     6806    else if (!strcmp(pszName, "CreateKeyStore"))
     6807        cbValue = 2; /* Single digit + terminator. */
     6808    else
     6809        return VERR_CFGM_VALUE_NOT_FOUND;
     6810
     6811    *pcbValue = cbValue + 1 /* include terminator */;
     6812
     6813    return VINF_SUCCESS;
     6814}
     6815
     6816DECLCALLBACK(int) Medium::i_vdCryptoConfigQuery(void *pvUser, const char *pszName,
     6817                                                char *pszValue, size_t cchValue)
     6818{
     6819    Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser;
     6820    AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
     6821    AssertReturn(VALID_PTR(pszValue), VERR_INVALID_POINTER);
     6822
     6823    if (!strcmp(pszName, "KeyStore"))
     6824        return RTBase64Decode(pSettings->pszKeyStoreLoad, pszValue, cchValue, NULL, NULL);
     6825    else
     6826    {
     6827        const char *psz = NULL;
     6828        if (!strcmp(pszName, "Algorithm"))
     6829            psz = pSettings->pszCipher;
     6830        else if (!strcmp(pszName, "CreateKeyStore"))
     6831        {
     6832            if (pSettings->fCreateKeyStore)
     6833                psz = "1";
     6834            else
     6835                psz = "0";
     6836        }
     6837        else
     6838            return VERR_CFGM_VALUE_NOT_FOUND;
     6839
     6840        size_t cch = strlen(psz);
     6841        if (cch >= cchValue)
     6842            return VERR_CFGM_NOT_ENOUGH_SPACE;
     6843
     6844        memcpy(pszValue, psz, cch + 1);
     6845    }
     6846
     6847    return VINF_SUCCESS;
     6848}
     6849
     6850DECLCALLBACK(int) Medium::i_vdCryptoKeyRetain(void *pvUser, const char *pszId,
     6851                                              const uint8_t **ppbKey, size_t *pcbKey)
     6852{
     6853    Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser;
     6854    AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
     6855    AssertMsgFailedReturn(("This method should not be called here!\n"), VERR_INVALID_STATE);
     6856}
     6857
     6858DECLCALLBACK(int) Medium::i_vdCryptoKeyRelease(void *pvUser, const char *pszId)
     6859{
     6860    Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser;
     6861    AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
     6862    AssertMsgFailedReturn(("This method should not be called here!\n"), VERR_INVALID_STATE);
     6863}
     6864
     6865DECLCALLBACK(int) Medium::i_vdCryptoKeyStoreGetPassword(void *pvUser, const char **ppszPassword)
     6866{
     6867    Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser;
     6868    AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
     6869
     6870    *ppszPassword = pSettings->pszPassword;
     6871    return VINF_SUCCESS;
     6872}
     6873
     6874DECLCALLBACK(int) Medium::i_vdCryptoKeyStoreSave(void *pvUser, const void *pvKeyStore, size_t cbKeyStore)
     6875{
     6876    Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser;
     6877    AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
     6878
     6879    size_t cbEnc = RTBase64EncodedLength(cbKeyStore);
     6880    pSettings->pszKeyStore = (char *)RTMemAllocZ(cbEnc + 1);
     6881    if (!pSettings->pszKeyStore)
     6882        return VERR_NO_MEMORY;
     6883
     6884    int rc = RTBase64Encode(pvKeyStore, cbKeyStore, pSettings->pszKeyStore, cbEnc + 1, NULL);
     6885    if (RT_FAILURE(rc))
     6886    {
     6887        RTMemFree(pSettings->pszKeyStore);
     6888        pSettings->pszKeyStore = NULL;
     6889    }
     6890
     6891    return rc;
     6892}
     6893
     6894DECLCALLBACK(int) Medium::i_vdCryptoKeyStoreReturnParameters(void *pvUser, const char *pszCipher,
     6895                                                             const uint8_t *pbDek, size_t cbDek)
     6896{
     6897    Medium::CryptoFilterSettings *pSettings = (Medium::CryptoFilterSettings *)pvUser;
     6898    AssertPtrReturn(pSettings, VERR_GENERAL_FAILURE);
     6899
     6900    pSettings->pszCipher = pszCipher;
     6901    pSettings->pbDek     = pbDek;
     6902    pSettings->cbDek     = cbDek;
     6903
     6904    return VINF_SUCCESS;
    66046905}
    66056906
     
    84048705}
    84058706
     8707/**
     8708 * Sets up the encryption settings for a filter.
     8709 */
     8710void Medium::i_taskEncryptSettingsSetup(CryptoFilterSettings *pSettings, const char *pszCipher,
     8711                                        const char *pszKeyStore, const char *pszPassword,
     8712                                        bool fCreateKeyStore)
     8713{
     8714    pSettings->pszCipher       = pszCipher;
     8715    pSettings->pszPassword     = pszPassword;
     8716    pSettings->pszKeyStoreLoad = pszKeyStore;
     8717    pSettings->fCreateKeyStore = fCreateKeyStore;
     8718    pSettings->pbDek           = NULL;
     8719    pSettings->cbDek           = 0;
     8720    pSettings->vdFilterIfaces  = NULL;
     8721
     8722    pSettings->vdIfCfg.pfnAreKeysValid = i_vdCryptoConfigAreKeysValid;
     8723    pSettings->vdIfCfg.pfnQuerySize    = i_vdCryptoConfigQuerySize;
     8724    pSettings->vdIfCfg.pfnQuery        = i_vdCryptoConfigQuery;
     8725    pSettings->vdIfCfg.pfnQueryBytes   = NULL;
     8726
     8727    pSettings->vdIfCrypto.pfnKeyRetain                = i_vdCryptoKeyRetain;
     8728    pSettings->vdIfCrypto.pfnKeyRelease               = i_vdCryptoKeyRelease;
     8729    pSettings->vdIfCrypto.pfnKeyStoreGetPassword      = i_vdCryptoKeyStoreGetPassword;
     8730    pSettings->vdIfCrypto.pfnKeyStoreSave             = i_vdCryptoKeyStoreSave;
     8731    pSettings->vdIfCrypto.pfnKeyStoreReturnParameters = i_vdCryptoKeyStoreReturnParameters;
     8732
     8733    int vrc = VDInterfaceAdd(&pSettings->vdIfCfg.Core,
     8734                             "Medium::vdInterfaceCfgCrypto",
     8735                             VDINTERFACETYPE_CONFIG, pSettings,
     8736                             sizeof(VDINTERFACECONFIG), &pSettings->vdFilterIfaces);
     8737    AssertRC(vrc);
     8738
     8739    vrc = VDInterfaceAdd(&pSettings->vdIfCrypto.Core,
     8740                         "Medium::vdInterfaceCrypto",
     8741                         VDINTERFACETYPE_CRYPTO, pSettings,
     8742                         sizeof(VDINTERFACECRYPTO), &pSettings->vdFilterIfaces);
     8743    AssertRC(vrc);
     8744}
     8745
     8746/**
     8747 * Implementation code for the "compact" task.
     8748 *
     8749 * @param task
     8750 * @return
     8751 */
     8752HRESULT Medium::i_taskEncryptHandler(Medium::EncryptTask &task)
     8753{
     8754    HRESULT rc = S_OK;
     8755
     8756    /* Lock all in {parent,child} order. The lock is also used as a
     8757     * signal from the task initiator (which releases it only after
     8758     * RTThreadCreate()) that we can start the job. */
     8759    AutoWriteLock thisLock(this COMMA_LOCKVAL_SRC_POS);
     8760
     8761    try
     8762    {
     8763# ifdef VBOX_WITH_EXTPACK
     8764        static const Utf8Str strExtPackPuel("Oracle VM VirtualBox Extension Pack");
     8765        static const char *s_pszVDPlugin = "VDPluginCrypt";
     8766        ExtPackManager *pExtPackManager = m->pVirtualBox->i_getExtPackManager();
     8767        if (pExtPackManager->i_isExtPackUsable(strExtPackPuel.c_str()))
     8768        {
     8769            /* Load the plugin */
     8770            Utf8Str strPlugin;
     8771            rc = pExtPackManager->i_getLibraryPathForExtPack(s_pszVDPlugin, &strExtPackPuel, &strPlugin);
     8772            if (SUCCEEDED(rc))
     8773            {
     8774                int vrc = VDPluginLoadFromFilename(strPlugin.c_str());
     8775                if (RT_FAILURE(vrc))
     8776                    throw setError(VBOX_E_NOT_SUPPORTED,
     8777                                   tr("Encrypting the image failed because the encryption plugin could not be loaded (%s)"),
     8778                                   i_vdError(vrc).c_str());
     8779            }
     8780            else
     8781                throw setError(VBOX_E_NOT_SUPPORTED,
     8782                               tr("Encryption is not supported because the extension pack '%s' is missing the encryption plugin (old extension pack installed?)"),
     8783                               strExtPackPuel.c_str());
     8784        }
     8785        else
     8786            throw setError(VBOX_E_NOT_SUPPORTED,
     8787                           tr("Encryption is not supported because the extension pack '%s' is missing"),
     8788                           strExtPackPuel.c_str());
     8789
     8790        PVBOXHDD pDisk = NULL;
     8791        int vrc = VDCreate(m->vdDiskIfaces, i_convertDeviceType(), &pDisk);
     8792        ComAssertRCThrow(vrc, E_FAIL);
     8793
     8794        Medium::CryptoFilterSettings CryptoSettingsRead;
     8795        Medium::CryptoFilterSettings CryptoSettingsWrite;
     8796
     8797        uint8_t *pbDek = NULL;
     8798        size_t cbDek = 0;
     8799        char *pszCipherOld = NULL;
     8800        char *pszKeyStoreEncNew = NULL;
     8801        void *pvBuf = NULL;
     8802        try
     8803        {
     8804            /* Set up disk encryption filters. */
     8805            if (task.mstrOldPassword.isEmpty())
     8806            {
     8807                /*
     8808                 * Query whether the medium property indicating that encryption is
     8809                 * configured is existing.
     8810                 */
     8811                settings::StringsMap::iterator it = m->mapProperties.find("CRYPT/KeyStore");
     8812                if (it != m->mapProperties.end())
     8813                    throw setError(VBOX_E_INVALID_OBJECT_STATE,
     8814                                   tr("The password given for the encrypted image is incorrect"));
     8815            }
     8816            else
     8817            {
     8818                settings::StringsMap::iterator it = m->mapProperties.find("CRYPT/KeyStore");
     8819                if (it == m->mapProperties.end())
     8820                    throw setError(VBOX_E_INVALID_OBJECT_STATE,
     8821                                   tr("The image is not configured for encryption"));
     8822
     8823                i_taskEncryptSettingsSetup(&CryptoSettingsRead, NULL, it->second.c_str(), task.mstrOldPassword.c_str(),
     8824                                           false /* fCreateKeyStore */);
     8825                vrc = VDFilterAdd(pDisk, "CRYPT", VD_FILTER_FLAGS_READ, CryptoSettingsRead.vdFilterIfaces);
     8826                if (RT_FAILURE(vrc))
     8827                    throw setError(VBOX_E_INVALID_OBJECT_STATE,
     8828                                   tr("Failed to load the decryption filter: %s"),
     8829                                   i_vdError(vrc).c_str());
     8830            }
     8831
     8832            if (task.mstrNewPassword.isNotEmpty())
     8833            {
     8834                if (task.mstrCipher.isEmpty())
     8835                    throw setError(VBOX_E_OBJECT_NOT_FOUND,
     8836                                   tr("No valid cipher identifier was given for encryption"));
     8837
     8838                i_taskEncryptSettingsSetup(&CryptoSettingsWrite, task.mstrCipher.c_str(), NULL,
     8839                                           task.mstrNewPassword.c_str(), true /* fCreateKeyStore */);
     8840                vrc = VDFilterAdd(pDisk, "CRYPT", VD_FILTER_FLAGS_WRITE, CryptoSettingsWrite.vdFilterIfaces);
     8841                if (RT_FAILURE(vrc))
     8842                    throw setError(VBOX_E_INVALID_OBJECT_STATE,
     8843                                   tr("Failed to load the encryption filter: %s"),
     8844                                   i_vdError(vrc).c_str());
     8845            }
     8846
     8847            /* Open all media in the chain. */
     8848            MediumLockList::Base::const_iterator mediumListBegin =
     8849                task.mpMediumLockList->GetBegin();
     8850            MediumLockList::Base::const_iterator mediumListEnd =
     8851                task.mpMediumLockList->GetEnd();
     8852            MediumLockList::Base::const_iterator mediumListLast =
     8853                mediumListEnd;
     8854            mediumListLast--;
     8855            for (MediumLockList::Base::const_iterator it = mediumListBegin;
     8856                 it != mediumListEnd;
     8857                 ++it)
     8858            {
     8859                const MediumLock &mediumLock = *it;
     8860                const ComObjPtr<Medium> &pMedium = mediumLock.GetMedium();
     8861                AutoReadLock alock(pMedium COMMA_LOCKVAL_SRC_POS);
     8862
     8863                /* sanity check */
     8864                if (it == mediumListLast)
     8865                    Assert(pMedium->m->state == MediumState_LockedWrite);
     8866                else
     8867                    Assert(pMedium->m->state == MediumState_LockedRead);
     8868
     8869                /* Open all media but last in read-only mode. Do not handle
     8870                 * shareable media, as compaction and sharing are mutually
     8871                 * exclusive. */
     8872                vrc = VDOpen(pDisk,
     8873                             pMedium->m->strFormat.c_str(),
     8874                             pMedium->m->strLocationFull.c_str(),
     8875                             m->uOpenFlagsDef | (it == mediumListLast ? VD_OPEN_FLAGS_NORMAL : VD_OPEN_FLAGS_READONLY),
     8876                             pMedium->m->vdImageIfaces);
     8877                if (RT_FAILURE(vrc))
     8878                    throw setError(VBOX_E_FILE_ERROR,
     8879                                   tr("Could not open the medium storage unit '%s'%s"),
     8880                                   pMedium->m->strLocationFull.c_str(),
     8881                                   i_vdError(vrc).c_str());
     8882            }
     8883
     8884            Assert(m->state == MediumState_LockedWrite);
     8885
     8886            Utf8Str location(m->strLocationFull);
     8887
     8888            /* unlock before the potentially lengthy operation */
     8889            thisLock.release();
     8890
     8891            /** @todo: Move the copying to the VD library and think about how to handle an I/O error
     8892             * in the middle of the process. Implement progress interface. */
     8893            uint64_t uOffset = 0;
     8894            size_t cbBuf = 2*_1M;
     8895            uint64_t cbDisk = VDGetSize(pDisk, VD_LAST_IMAGE);
     8896
     8897            if (!cbDisk)
     8898                throw setError(VBOX_E_FILE_ERROR,
     8899                               tr("Could not query the size of the disk '%s'"),
     8900                               m->strLocationFull.c_str());
     8901
     8902            pvBuf = RTMemAllocZ(cbBuf);
     8903            if (!pvBuf)
     8904                throw setError(VBOX_E_INVALID_OBJECT_STATE,
     8905                               tr("Could not allocate %zu bytes of memory for the encryption"),
     8906                               cbBuf);
     8907
     8908            while (uOffset < cbDisk)
     8909            {
     8910                size_t cbCopy = RT_MIN(cbBuf, cbDisk - uOffset);
     8911                vrc = VDRead(pDisk, uOffset, pvBuf, cbCopy);
     8912                if (RT_FAILURE(vrc))
     8913                    throw setError(VBOX_E_INVALID_OBJECT_STATE,
     8914                                   tr("Could not read the original data from the image at offset %llu: %Rrc"),
     8915                                   uOffset, vrc);
     8916
     8917                /* Write back, the filter will do the encryption if configured. */
     8918                vrc = VDWrite(pDisk, uOffset, pvBuf, cbCopy);
     8919                if (RT_FAILURE(vrc))
     8920                    throw setError(VBOX_E_INVALID_OBJECT_STATE,
     8921                                   tr("Could not write the data to the image at offset %llu: %Rrc"),
     8922                                   uOffset, vrc);
     8923
     8924                uOffset += cbCopy;
     8925            }
     8926
     8927            thisLock.acquire();
     8928            /* If everything went well set the new key store. */
     8929            settings::StringsMap::iterator it = m->mapProperties.find("CRYPT/KeyStore");
     8930            if (it != m->mapProperties.end())
     8931                m->mapProperties.erase(it);
     8932
     8933            if (CryptoSettingsWrite.pszKeyStore)
     8934                m->mapProperties["CRYPT/KeyStore"] = Utf8Str(CryptoSettingsWrite.pszKeyStore);
     8935
     8936            thisLock.release();
     8937            i_markRegistriesModified();
     8938            m->pVirtualBox->i_saveModifiedRegistries();
     8939        }
     8940        catch (HRESULT aRC) { rc = aRC; }
     8941
     8942        if (pvBuf)
     8943            RTMemFree(pvBuf);
     8944
     8945        VDDestroy(pDisk);
     8946# else
     8947        throw setError(VBOX_E_NOT_SUPPORTED,
     8948                       tr("Encryption is not supported because extension pack support is not built in"));
     8949# endif
     8950
     8951
     8952    }
     8953    catch (HRESULT aRC) { rc = aRC; }
     8954
     8955    /* Everything is explicitly unlocked when the task exits,
     8956     * as the task destruction also destroys the media chain. */
     8957
     8958    return rc;
     8959}
     8960
    84068961/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette