LCOV - code coverage report
Current view: top level - port - cpl_vsil_crypt.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 741 790 93.8 %
Date: 2024-04-28 18:08:58 Functions: 37 38 97.4 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Project:  CPL - Common Portability Library
       4             :  * Purpose:  Implement VSI large file api for encrypted files.
       5             :  * Author:   Even Rouault, even.rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      21             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #include "cpl_port.h"
      30             : #include "cpl_vsi_virtual.h"
      31             : 
      32             : #include <cstddef>
      33             : #include <algorithm>
      34             : 
      35             : #include "cpl_error.h"
      36             : #include "cpl_vsi.h"
      37             : 
      38             : CPL_C_START
      39             : void CPL_DLL VSIInstallCryptFileHandler();
      40             : void CPL_DLL VSISetCryptKey(const GByte *pabyKey, int nKeySize);
      41             : CPL_C_END
      42             : 
      43             : constexpr char VSICRYPT_PREFIX[] = "/vsicrypt/";
      44             : 
      45             : #if defined(HAVE_CRYPTOPP) || defined(DOXYGEN_SKIP)
      46             : 
      47             : //! @cond Doxygen_Suppress
      48             : 
      49             : /* Increase Major in case of backward incompatible changes */
      50             : constexpr int VSICRYPT_CURRENT_MAJOR = 1;
      51             : constexpr int VSICRYPT_CURRENT_MINOR = 0;
      52             : constexpr char VSICRYPT_SIGNATURE[] = "VSICRYPT";  // Must be 8 chars.
      53             : 
      54             : constexpr char VSICRYPT_PREFIX_WITHOUT_SLASH[] = "/vsicrypt";
      55             : 
      56             : constexpr unsigned int VSICRYPT_READ = 0x1;
      57             : constexpr unsigned int VSICRYPT_WRITE = 0x2;
      58             : 
      59             : /* Begin of crypto++ headers */
      60             : #ifdef _MSC_VER
      61             : #pragma warning(push)
      62             : #pragma warning(disable : 4189)
      63             : #pragma warning(disable : 4512)
      64             : #pragma warning(disable : 4244)
      65             : #pragma warning(disable : 4505)
      66             : #endif
      67             : 
      68             : #ifdef __GNUC__
      69             : #pragma GCC diagnostic push
      70             : #pragma GCC diagnostic ignored "-Weffc++"
      71             : #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
      72             : #pragma GCC diagnostic ignored "-Wold-style-cast"
      73             : #endif
      74             : 
      75             : #ifdef USE_ONLY_CRYPTODLL_ALG
      76             : #include "cryptopp/dll.h"
      77             : #else
      78             : #include "cryptopp/aes.h"
      79             : #include "cryptopp/blowfish.h"
      80             : #include "cryptopp/camellia.h"
      81             : #include "cryptopp/cast.h"
      82             : #include "cryptopp/des.h"
      83             : #include "cryptopp/mars.h"
      84             : #include "cryptopp/idea.h"
      85             : #include "cryptopp/rc5.h"
      86             : #include "cryptopp/rc6.h"
      87             : #include "cryptopp/serpent.h"
      88             : #include "cryptopp/shacal2.h"
      89             : #include "cryptopp/skipjack.h"
      90             : #include "cryptopp/tea.h"
      91             : #include "cryptopp/twofish.h"
      92             : #endif
      93             : 
      94             : #include "cryptopp/filters.h"
      95             : #include "cryptopp/modes.h"
      96             : #include "cryptopp/osrng.h"
      97             : 
      98             : #ifdef __GNUC__
      99             : #pragma GCC diagnostic pop
     100             : #endif
     101             : 
     102             : #ifdef _MSC_VER
     103             : #pragma warning(pop)
     104             : #endif
     105             : 
     106             : // Fix compatibility with Crypto++
     107             : #if CRYPTOPP_VERSION >= 600
     108             : typedef CryptoPP::byte cryptopp_byte;
     109             : #else
     110             : typedef byte cryptopp_byte;
     111             : #endif
     112             : 
     113             : /* End of crypto++ headers */
     114             : 
     115             : // I don't really understand why this is necessary, especially
     116             : // when cryptopp.dll and GDAL have been compiled with the same
     117             : // VC version and /MD. But otherwise you'll get crashes
     118             : // Borrowed from dlltest.cpp of crypto++
     119             : #if defined(_WIN32) && defined(USE_ONLY_CRYPTODLL_ALG)
     120             : 
     121             : static CryptoPP::PNew s_pNew = nullptr;
     122             : static CryptoPP::PDelete s_pDelete = nullptr;
     123             : 
     124             : extern "C" __declspec(dllexport) void __cdecl SetNewAndDeleteFromCryptoPP(
     125             :     CryptoPP::PNew pNew, CryptoPP::PDelete pDelete,
     126             :     CryptoPP::PSetNewHandler pSetNewHandler)
     127             : {
     128             :     s_pNew = pNew;
     129             :     s_pDelete = pDelete;
     130             : }
     131             : 
     132             : void *__cdecl operator new(size_t size)
     133             : {
     134             :     return s_pNew(size);
     135             : }
     136             : 
     137             : void __cdecl operator delete(void *p)
     138             : {
     139             :     s_pDelete(p);
     140             : }
     141             : 
     142             : #endif  // defined(_WIN32) && defined(USE_ONLY_CRYPTODLL_ALG)
     143             : 
     144             : static GByte *pabyGlobalKey = nullptr;
     145             : static int nGlobalKeySize = 0;
     146             : 
     147             : typedef enum
     148             : {
     149             :     ALG_AES,
     150             :     ALG_Blowfish,
     151             :     ALG_Camellia,
     152             :     // ALG_CAST128, (obsolete)
     153             :     ALG_CAST256,
     154             :     // ALG_DES, (obsolete)
     155             :     ALG_DES_EDE2,
     156             :     ALG_DES_EDE3,
     157             :     // ALG_DES_XEX3, (obsolete)
     158             :     // ALG_Gost, (obsolete)
     159             :     ALG_MARS,
     160             :     ALG_IDEA,
     161             :     // ALG_RC2, (obsolete)
     162             :     ALG_RC5,
     163             :     ALG_RC6,
     164             :     // ALG_SAFER_K, (obsolete)
     165             :     // ALG_SAFER_SK, (obsolete)
     166             :     ALG_Serpent,
     167             :     ALG_SHACAL2,
     168             :     // ALG_SHARK, (obsolete)
     169             :     ALG_SKIPJACK,
     170             :     ALG_Twofish,
     171             :     // ALG_ThreeWay, (obsolete)
     172             :     ALG_XTEA,
     173             :     ALG_MAX = ALG_XTEA
     174             : } VSICryptAlg;
     175             : 
     176             : typedef enum
     177             : {
     178             :     MODE_CBC,
     179             :     MODE_CFB,
     180             :     MODE_OFB,
     181             :     MODE_CTR,
     182             :     MODE_CBC_CTS,
     183             :     MODE_MAX = MODE_CBC_CTS
     184             : } VSICryptMode;
     185             : 
     186             : //! @endcond
     187             : 
     188             : /************************************************************************/
     189             : /*                          VSISetCryptKey()                            */
     190             : /************************************************************************/
     191             : 
     192             : /** Installs the encryption/decryption key.
     193             :  *
     194             :  * By passing a NULL key, the previously installed key will be cleared.
     195             :  * Note, however, that it is not guaranteed that there won't be trace of it
     196             :  * in other places in memory or in on-disk temporary file.
     197             :  *
     198             :  * @param pabyKey key. Might be NULL to clear previously set key.
     199             :  * @param nKeySize length of the key in bytes. Might be 0 to clear
     200             :  * previously set key.
     201             :  *
     202             :  * @see VSIInstallCryptFileHandler() for documentation on /vsicrypt/
     203             :  */
     204           3 : void VSISetCryptKey(const GByte *pabyKey, int nKeySize)
     205             : {
     206           3 :     CPLAssert((pabyKey != nullptr && nKeySize != 0) ||
     207             :               (pabyKey == nullptr && nKeySize == 0));
     208           3 :     if (pabyGlobalKey)
     209             :     {
     210             :         // Make some effort to clear the memory, although it could have leaked
     211             :         // elsewhere...
     212           2 :         memset(pabyGlobalKey, 0, nGlobalKeySize);
     213           2 :         CPLFree(pabyGlobalKey);
     214           2 :         pabyGlobalKey = nullptr;
     215           2 :         nGlobalKeySize = 0;
     216             :     }
     217           3 :     if (pabyKey)
     218             :     {
     219           2 :         pabyGlobalKey = static_cast<GByte *>(CPLMalloc(nKeySize));
     220           2 :         memcpy(pabyGlobalKey, pabyKey, nKeySize);
     221           2 :         nGlobalKeySize = nKeySize;
     222             :     }
     223           3 : }
     224             : 
     225             : //! @cond Doxygen_Suppress
     226             : 
     227             : /************************************************************************/
     228             : /*                             GetAlg()                                 */
     229             : /************************************************************************/
     230             : 
     231             : #undef CASE_ALG
     232             : #define CASE_ALG(alg)                                                          \
     233             :     if (EQUAL(pszName, #alg))                                                  \
     234             :         return ALG_##alg;
     235             : 
     236        1043 : static VSICryptAlg GetAlg(const char *pszName)
     237             : {
     238        1043 :     CASE_ALG(AES)
     239          16 :     CASE_ALG(Blowfish)
     240          14 :     CASE_ALG(Camellia)
     241             :     // CASE_ALG(CAST128) (obsolete)
     242          13 :     CASE_ALG(CAST256)
     243             :     // CASE_ALG(DES) (obsolete)
     244          12 :     CASE_ALG(DES_EDE2)
     245          11 :     CASE_ALG(DES_EDE3)
     246             :     // CASE_ALG(DES_XEX3) (obsolete)
     247             :     // CASE_ALG(Ghost) (obsolete)
     248          10 :     CASE_ALG(MARS)
     249           9 :     CASE_ALG(IDEA)
     250             :     // CASE_ALG(RC2) (obsolete)
     251           8 :     CASE_ALG(RC5)
     252           7 :     CASE_ALG(RC6)
     253             :     // CASE_ALG(SAFER_K) (obsolete)
     254             :     // CASE_ALG(SAFER_SK) (obsolete)
     255           6 :     CASE_ALG(Serpent)
     256           5 :     CASE_ALG(SHACAL2)
     257             :     // CASE_ALG(SHARK) (obsolete)
     258           4 :     CASE_ALG(SKIPJACK)
     259             :     // CASE_ALG(ThreeWay) (obsolete)
     260           3 :     CASE_ALG(Twofish)
     261           2 :     CASE_ALG(XTEA)
     262             : 
     263           1 :     CPLError(CE_Warning, CPLE_NotSupported,
     264             :              "Unsupported cipher algorithm: %s. Using AES instead", pszName);
     265           1 :     return ALG_AES;
     266             : }
     267             : 
     268             : /************************************************************************/
     269             : /*                          GetEncBlockCipher()                         */
     270             : /************************************************************************/
     271             : 
     272             : #undef CASE_ALG
     273             : #define CASE_ALG(alg)                                                          \
     274             :     case ALG_##alg:                                                            \
     275             :         return new CryptoPP::alg::Encryption();
     276             : 
     277        2224 : static CryptoPP::BlockCipher *GetEncBlockCipher(VSICryptAlg eAlg)
     278             : {
     279        2224 :     switch (eAlg)
     280             :     {
     281        2180 :         CASE_ALG(AES)
     282             : #ifndef USE_ONLY_CRYPTODLL_ALG
     283           5 :         CASE_ALG(Blowfish)
     284           3 :         CASE_ALG(Camellia)
     285             :         // CASE_ALG(CAST128) (obsolete)
     286           3 :         CASE_ALG(CAST256)
     287             : #endif
     288             :         // CASE_ALG(DES) (obsolete)
     289           3 :         CASE_ALG(DES_EDE2)
     290           3 :         CASE_ALG(DES_EDE3)
     291             :         // CASE_ALG(DES_XEX3) (obsolete)
     292             : #ifndef USE_ONLY_CRYPTODLL_ALG
     293             :         // CASE_ALG(Gost) (obsolete)
     294           3 :         CASE_ALG(MARS)
     295           3 :         CASE_ALG(IDEA)
     296             :         // CASE_ALG(RC2) (obsolete)
     297           3 :         CASE_ALG(RC5)
     298           3 :         CASE_ALG(RC6)
     299             :         // CASE_ALG(SAFER_K) (obsolete)
     300             :         // CASE_ALG(SAFER_SK) (obsolete)
     301           3 :         CASE_ALG(Serpent)
     302           3 :         CASE_ALG(SHACAL2)
     303             :         // CASE_ALG(SHARK) (obsolete)
     304             : #endif
     305           3 :         CASE_ALG(SKIPJACK)
     306             : #ifndef USE_ONLY_CRYPTODLL_ALG
     307             :         // CASE_ALG(ThreeWay) (obsolete)
     308           3 :         CASE_ALG(Twofish)
     309           3 :         CASE_ALG(XTEA)
     310             : #endif
     311           0 :         default:
     312           0 :             return nullptr;
     313             :     }
     314             : }
     315             : 
     316             : /************************************************************************/
     317             : /*                          GetDecBlockCipher()                         */
     318             : /************************************************************************/
     319             : 
     320             : #undef CASE_ALG
     321             : #define CASE_ALG(alg)                                                          \
     322             :     case ALG_##alg:                                                            \
     323             :         return new CryptoPP::alg::Decryption();
     324             : 
     325        1172 : static CryptoPP::BlockCipher *GetDecBlockCipher(VSICryptAlg eAlg)
     326             : {
     327        1172 :     switch (eAlg)
     328             :     {
     329        1143 :         CASE_ALG(AES)
     330             : #ifndef USE_ONLY_CRYPTODLL_ALG
     331           3 :         CASE_ALG(Blowfish)
     332           2 :         CASE_ALG(Camellia)
     333             :         // CASE_ALG(CAST128) (obsolete)
     334           2 :         CASE_ALG(CAST256)
     335             : #endif
     336             :         // CASE_ALG(DES) (obsolete)
     337           2 :         CASE_ALG(DES_EDE2)
     338           2 :         CASE_ALG(DES_EDE3)
     339             :         // CASE_ALG(DES_XEX3) (obsolete)
     340             : #ifndef USE_ONLY_CRYPTODLL_ALG
     341             :         // CASE_ALG(Gost) (obsolete)
     342           2 :         CASE_ALG(MARS)
     343           2 :         CASE_ALG(IDEA)
     344             :         // CASE_ALG(RC2) (obsolete)
     345           2 :         CASE_ALG(RC5)
     346           2 :         CASE_ALG(RC6)
     347             :         // CASE_ALG(SAFER_K) (obsolete)
     348             :         // CASE_ALG(SAFER_SK) (obsolete)
     349           2 :         CASE_ALG(Serpent)
     350           2 :         CASE_ALG(SHACAL2)
     351             :         // CASE_ALG(SHARK) (obsolete)
     352             : #endif
     353           2 :         CASE_ALG(SKIPJACK)
     354             : #ifndef USE_ONLY_CRYPTODLL_ALG
     355             :         // CASE_ALG(ThreeWay) (obsolete)
     356           2 :         CASE_ALG(Twofish)
     357           2 :         CASE_ALG(XTEA)
     358             : #endif
     359           0 :         default:
     360           0 :             return nullptr;
     361             :     }
     362             : }
     363             : 
     364             : /************************************************************************/
     365             : /*                             GetMode()                                */
     366             : /************************************************************************/
     367             : 
     368        1043 : static VSICryptMode GetMode(const char *pszName)
     369             : {
     370        1043 :     if (EQUAL(pszName, "CBC"))
     371        1037 :         return MODE_CBC;
     372           6 :     if (EQUAL(pszName, "CFB"))
     373           1 :         return MODE_CFB;
     374           5 :     if (EQUAL(pszName, "OFB"))
     375           1 :         return MODE_OFB;
     376           4 :     if (EQUAL(pszName, "CTR"))
     377           1 :         return MODE_CTR;
     378           3 :     if (EQUAL(pszName, "CBC_CTS"))
     379           2 :         return MODE_CBC_CTS;
     380             : 
     381           1 :     CPLError(CE_Warning, CPLE_NotSupported,
     382             :              "Unsupported cipher block mode: %s. Using CBC instead", pszName);
     383           1 :     return MODE_CBC;
     384             : }
     385             : 
     386             : /************************************************************************/
     387             : /*                          VSICryptFileHeader                          */
     388             : /************************************************************************/
     389             : 
     390             : class VSICryptFileHeader
     391             : {
     392             :     CPL_DISALLOW_COPY_ASSIGN(VSICryptFileHeader)
     393             : 
     394             :     std::string CryptKeyCheck(CryptoPP::BlockCipher *poEncCipher);
     395             : 
     396             :   public:
     397        1273 :     VSICryptFileHeader() = default;
     398             : 
     399             :     int ReadFromFile(VSIVirtualHandle *fp, const CPLString &osKey);
     400             :     int WriteToFile(VSIVirtualHandle *fp, CryptoPP::BlockCipher *poEncCipher);
     401             : 
     402             :     GUInt16 nHeaderSize = 0;
     403             :     GByte nMajorVersion = 0;
     404             :     GByte nMinorVersion = 0;
     405             :     GUInt16 nSectorSize = 512;
     406             :     VSICryptAlg eAlg = ALG_AES;
     407             :     VSICryptMode eMode = MODE_CBC;
     408             :     CPLString osIV{};
     409             :     bool bAddKeyCheck = false;
     410             :     GUIntBig nPayloadFileSize = 0;
     411             :     CPLString osFreeText{};
     412             :     CPLString osExtraContent{};
     413             : };
     414             : 
     415             : /************************************************************************/
     416             : /*                         VSICryptReadError()                          */
     417             : /************************************************************************/
     418             : 
     419          51 : static bool VSICryptReadError()
     420             : {
     421          51 :     CPLError(CE_Failure, CPLE_FileIO, "Cannot read header");
     422          51 :     return false;
     423             : }
     424             : 
     425             : /************************************************************************/
     426             : /*                       VSICryptGenerateSectorIV()                     */
     427             : /************************************************************************/
     428             : 
     429             : // TODO(rouault): This function really needs a comment saying what it does.
     430      145400 : static std::string VSICryptGenerateSectorIV(const std::string &osIV,
     431             :                                             vsi_l_offset nOffset)
     432             : {
     433      145400 :     std::string osSectorIV(osIV);
     434      145400 :     const size_t nLength = std::min(sizeof(vsi_l_offset), osSectorIV.size());
     435     1308600 :     for (size_t i = 0; i < nLength; i++)
     436             :     {
     437             :         // TODO(rouault): Explain what this block is trying to do?
     438     1163200 :         osSectorIV[i] = static_cast<char>((osSectorIV[i] ^ nOffset) & 0xff);
     439     1163200 :         nOffset >>= 8;
     440             :     }
     441      145400 :     return osSectorIV;
     442             : }
     443             : 
     444             : /************************************************************************/
     445             : /*                          CryptKeyCheck()                             */
     446             : /************************************************************************/
     447             : 
     448             : std::string
     449          14 : VSICryptFileHeader::CryptKeyCheck(CryptoPP::BlockCipher *poEncCipher)
     450             : {
     451          28 :     std::string osKeyCheckRes;
     452             : 
     453          14 :     CPLAssert(osIV.size() == poEncCipher->BlockSize());
     454             :     // Generate a unique IV with a sector offset of 0xFFFFFFFFFFFFFFFF.
     455             :     std::string osCheckIV(
     456          28 :         VSICryptGenerateSectorIV(osIV, ~(static_cast<vsi_l_offset>(0))));
     457             :     CryptoPP::StreamTransformation *poMode;
     458             :     try
     459             :     {
     460          28 :         poMode = new CryptoPP::CBC_Mode_ExternalCipher::Encryption(
     461             :             *poEncCipher,
     462          14 :             reinterpret_cast<const cryptopp_byte *>(osCheckIV.c_str()));
     463             :     }
     464           0 :     catch (const std::exception &e)
     465             :     {
     466           0 :         CPLError(CE_Failure, CPLE_AppDefined, "CryptoPP exception: %s",
     467           0 :                  e.what());
     468           0 :         return std::string();
     469             :     }
     470          14 :     CryptoPP::StringSink *poSink = new CryptoPP::StringSink(osKeyCheckRes);
     471             :     CryptoPP::StreamTransformationFilter *poEnc =
     472             :         new CryptoPP::StreamTransformationFilter(
     473          14 :             *poMode, poSink, CryptoPP::StreamTransformationFilter::NO_PADDING);
     474             :     // Not sure if it is add extra security, but pick up something that is
     475             :     // unlikely to be a plain text (random number).
     476          28 :     poEnc->Put(
     477             :         reinterpret_cast<const cryptopp_byte *>(
     478             :             "\xDB\x31\xB9\x1B\xD3\x1C\xFA\x3E\x84\x06\xC1\x42\xC3\xEC\xCD\x9A"
     479             :             "\x02\x36\x22\x15\x58\x88\x74\x65\x00\x2F\x98\xBC\x69\x22\xE1\x63"),
     480          14 :         std::min(32U, poEncCipher->BlockSize()));
     481          14 :     poEnc->MessageEnd();
     482          14 :     delete poEnc;
     483          14 :     delete poMode;
     484             : 
     485          14 :     return osKeyCheckRes;
     486             : }
     487             : 
     488             : /************************************************************************/
     489             : /*                          ReadFromFile()                              */
     490             : /************************************************************************/
     491             : 
     492         235 : int VSICryptFileHeader::ReadFromFile(VSIVirtualHandle *fp,
     493             :                                      const CPLString &osKey)
     494             : {
     495         235 :     GByte abySignature[8] = {};
     496         235 :     fp->Seek(0, SEEK_SET);
     497         235 :     CPL_STATIC_ASSERT(sizeof(VSICRYPT_SIGNATURE) == 8 + 1);
     498         461 :     if (fp->Read(abySignature, 8, 1) == 0 ||
     499         226 :         memcmp(abySignature, VSICRYPT_SIGNATURE, 8) != 0)
     500             :     {
     501          33 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid signature");
     502          33 :         return FALSE;
     503             :     }
     504             : 
     505         202 :     if (fp->Read(&nHeaderSize, 2, 1) == 0)
     506           2 :         return VSICryptReadError();
     507         200 :     nHeaderSize = CPL_LSBWORD16(nHeaderSize);
     508         200 :     if (nHeaderSize < 8 + 2 + 1 + 1)
     509             :     {
     510           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid header size : %d",
     511           1 :                  nHeaderSize);
     512           1 :         return FALSE;
     513             :     }
     514             : 
     515         199 :     if (fp->Read(&nMajorVersion, 1, 1) == 0)
     516           1 :         return VSICryptReadError();
     517         198 :     if (fp->Read(&nMinorVersion, 1, 1) == 0)
     518           1 :         return VSICryptReadError();
     519             : 
     520         197 :     if (nMajorVersion != VSICRYPT_CURRENT_MAJOR)
     521             :     {
     522           3 :         CPLError(CE_Failure, CPLE_AppDefined, "Unhandled major version : %d",
     523           3 :                  nMajorVersion);
     524           3 :         return FALSE;
     525             :     }
     526         194 :     if (nMinorVersion != VSICRYPT_CURRENT_MINOR)
     527             :     {
     528           2 :         CPLDebug("VSICRYPT", "Minor version in file is %d", nMinorVersion);
     529             :     }
     530             : 
     531         194 :     if (fp->Read(&nSectorSize, 2, 1) == 0)
     532           2 :         return VSICryptReadError();
     533         192 :     nSectorSize = CPL_LSBWORD16(nSectorSize);
     534             : 
     535             :     GByte nAlg, nMode;
     536         192 :     if (fp->Read(&nAlg, 1, 1) == 0 || fp->Read(&nMode, 1, 1) == 0)
     537           2 :         return VSICryptReadError();
     538         190 :     if (nAlg > ALG_MAX)
     539             :     {
     540           2 :         CPLError(CE_Failure, CPLE_NotSupported,
     541             :                  "Unsupported cipher algorithm %d", nAlg);
     542           2 :         return FALSE;
     543             :     }
     544         188 :     if (nMode > MODE_MAX)
     545             :     {
     546           2 :         CPLError(CE_Failure, CPLE_NotSupported,
     547             :                  "Unsupported cipher block mode %d", nMode);
     548           2 :         return FALSE;
     549             :     }
     550         186 :     eAlg = static_cast<VSICryptAlg>(nAlg);
     551         186 :     eMode = static_cast<VSICryptMode>(nMode);
     552             : 
     553             :     GByte nIVSize;
     554         186 :     if (fp->Read(&nIVSize, 1, 1) == 0)
     555           1 :         return VSICryptReadError();
     556             : 
     557         185 :     osIV.resize(nIVSize);
     558             :     // TODO(schwehr): Using the const buffer of a string is a bad idea.
     559         185 :     if (fp->Read(reinterpret_cast<void *>(const_cast<char *>(osIV.c_str())), 1,
     560         370 :                  nIVSize) != nIVSize)
     561          18 :         return VSICryptReadError();
     562             : 
     563             :     GUInt16 nFreeTextSize;
     564         167 :     if (fp->Read(&nFreeTextSize, 2, 1) == 0)
     565           2 :         return VSICryptReadError();
     566             : 
     567         165 :     osFreeText.resize(nFreeTextSize);
     568         165 :     if (fp->Read(
     569         165 :             reinterpret_cast<void *>(const_cast<char *>(osFreeText.c_str())), 1,
     570         330 :             nFreeTextSize) != nFreeTextSize)
     571           5 :         return VSICryptReadError();
     572             : 
     573             :     GByte nKeyCheckSize;
     574         160 :     if (fp->Read(&nKeyCheckSize, 1, 1) == 0)
     575           1 :         return VSICryptReadError();
     576         159 :     bAddKeyCheck = nKeyCheckSize != 0;
     577         159 :     if (nKeyCheckSize)
     578             :     {
     579          11 :         CPLString osKeyCheck;
     580          11 :         osKeyCheck.resize(nKeyCheckSize);
     581          11 :         if (fp->Read(reinterpret_cast<void *>(
     582          11 :                          const_cast<char *>(osKeyCheck.c_str())),
     583          22 :                      1, nKeyCheckSize) != nKeyCheckSize)
     584           2 :             return VSICryptReadError();
     585             : 
     586           9 :         if (osKey.empty() && pabyGlobalKey == nullptr)
     587             :         {
     588           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     589             :                      "Encryption key not defined as key/key_b64 parameter, "
     590             :                      "VSICRYPT_KEY/VSICRYPT_KEY_B64 configuration option or "
     591             :                      "VSISetCryptKey() API");
     592           1 :             return FALSE;
     593             :         }
     594             : 
     595           8 :         CryptoPP::BlockCipher *poEncCipher = GetEncBlockCipher(eAlg);
     596           8 :         if (poEncCipher == nullptr)
     597           0 :             return FALSE;
     598             : 
     599           8 :         if (osIV.size() != poEncCipher->BlockSize())
     600             :         {
     601           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     602             :                      "Inconsistent initial vector");
     603           1 :             delete poEncCipher;
     604           1 :             return FALSE;
     605             :         }
     606             : 
     607           7 :         int nMaxKeySize = static_cast<int>(poEncCipher->MaxKeyLength());
     608             : 
     609             :         try
     610             :         {
     611           7 :             if (!osKey.empty())
     612             :             {
     613             :                 const int nKeySize =
     614           6 :                     std::min(nMaxKeySize, static_cast<int>(osKey.size()));
     615           6 :                 poEncCipher->SetKey(
     616           6 :                     reinterpret_cast<const cryptopp_byte *>(osKey.c_str()),
     617           6 :                     nKeySize);
     618             :             }
     619           1 :             else if (pabyGlobalKey)
     620             :             {
     621           1 :                 const int nKeySize = std::min(nMaxKeySize, nGlobalKeySize);
     622           1 :                 poEncCipher->SetKey(pabyGlobalKey, nKeySize);
     623             :             }
     624             :         }
     625           1 :         catch (const std::exception &e)
     626             :         {
     627           1 :             CPLError(CE_Failure, CPLE_AppDefined, "CryptoPP exception: %s",
     628           1 :                      e.what());
     629           1 :             delete poEncCipher;
     630           1 :             return FALSE;
     631             :         }
     632             : 
     633           6 :         std::string osKeyCheckRes = CryptKeyCheck(poEncCipher);
     634             : 
     635           6 :         delete poEncCipher;
     636             : 
     637          12 :         if (osKeyCheck.size() != osKeyCheckRes.size() ||
     638           6 :             memcmp(osKeyCheck.c_str(), osKeyCheckRes.c_str(),
     639             :                    osKeyCheck.size()) != 0)
     640             :         {
     641           2 :             CPLError(CE_Failure, CPLE_AppDefined, "Bad key");
     642           2 :             return FALSE;
     643             :         }
     644             :     }
     645             : 
     646         152 :     if (fp->Read(&nPayloadFileSize, 8, 1) == 0)
     647           8 :         return VSICryptReadError();
     648         144 :     CPL_LSBPTR64(&nPayloadFileSize);
     649             : #ifdef VERBOSE_VSICRYPT
     650             :     CPLDebug("VSICRYPT", "nPayloadFileSize read = " CPL_FRMT_GUIB,
     651             :              nPayloadFileSize);
     652             : #endif
     653             : 
     654         144 :     GUInt16 nExtraContentSize = 0;
     655         144 :     if (fp->Read(&nExtraContentSize, 2, 1) == 0)
     656           2 :         return VSICryptReadError();
     657         142 :     nExtraContentSize = CPL_LSBWORD16(nExtraContentSize);
     658             : 
     659         142 :     osExtraContent.resize(nExtraContentSize);
     660         142 :     if (fp->Read(const_cast<char *>(osExtraContent.c_str()), 1,
     661         284 :                  nExtraContentSize) != nExtraContentSize)
     662           4 :         return VSICryptReadError();
     663             : 
     664         138 :     return TRUE;
     665             : }
     666             : 
     667             : /************************************************************************/
     668             : /*                          WriteToFile()                               */
     669             : /************************************************************************/
     670             : 
     671        2074 : int VSICryptFileHeader::WriteToFile(VSIVirtualHandle *fp,
     672             :                                     CryptoPP::BlockCipher *poEncCipher)
     673             : {
     674        2074 :     fp->Seek(0, SEEK_SET);
     675             : 
     676        2074 :     bool bRet = fp->Write(VSICRYPT_SIGNATURE, 8, 1) == 1;
     677             : 
     678        2074 :     std::string osKeyCheckRes;
     679        2074 :     if (bAddKeyCheck)
     680             :     {
     681           8 :         osKeyCheckRes = CryptKeyCheck(poEncCipher);
     682             :     }
     683             : 
     684             :     GUInt16 nHeaderSizeNew =
     685             :         static_cast<GUInt16>(8 +                         /* signature */
     686             :                              2 +                         /* header size */
     687             :                              1 +                         /* major version */
     688             :                              1 +                         /* minor version */
     689             :                              2 +                         /* sector size */
     690             :                              1 +                         /* alg */
     691             :                              1 +                         /* mode */
     692        2074 :                              1 + osIV.size() +           /* IV */
     693        2074 :                              2 + osFreeText.size() +     /* free text */
     694        2074 :                              1 + osKeyCheckRes.size() +  /* key check */
     695             :                              8 +                         /* payload size */
     696        2074 :                              2 + osExtraContent.size()); /* extra content */
     697        2074 :     if (nHeaderSize != 0)
     698        1038 :         CPLAssert(nHeaderSizeNew == nHeaderSize);
     699             :     else
     700        1036 :         nHeaderSize = nHeaderSizeNew;
     701             : 
     702        2074 :     GUInt16 nHeaderSizeToWrite = CPL_LSBWORD16(nHeaderSizeNew);
     703        2074 :     bRet &= (fp->Write(&nHeaderSizeToWrite, 2, 1) == 1);
     704             : 
     705        2074 :     GByte nMajorVersionToWrite = VSICRYPT_CURRENT_MAJOR;
     706        2074 :     bRet &= (fp->Write(&nMajorVersionToWrite, 1, 1) == 1);
     707             : 
     708        2074 :     GByte nMinorVersionToWrite = VSICRYPT_CURRENT_MINOR;
     709        2074 :     bRet &= (fp->Write(&nMinorVersionToWrite, 1, 1) == 1);
     710             : 
     711        2074 :     GUInt16 nSectorSizeToWrite = CPL_LSBWORD16(nSectorSize);
     712        2074 :     bRet &= (fp->Write(&nSectorSizeToWrite, 2, 1) == 1);
     713             : 
     714        2074 :     GByte nAlg = static_cast<GByte>(eAlg);
     715        2074 :     bRet &= (fp->Write(&nAlg, 1, 1) == 1);
     716             : 
     717        2074 :     GByte nMode = static_cast<GByte>(eMode);
     718        2074 :     bRet &= (fp->Write(&nMode, 1, 1) == 1);
     719             : 
     720        2074 :     GByte nIVSizeToWrite = static_cast<GByte>(osIV.size());
     721        2074 :     CPLAssert(nIVSizeToWrite == osIV.size());
     722        2074 :     bRet &= (fp->Write(&nIVSizeToWrite, 1, 1) == 1);
     723        2074 :     bRet &= (fp->Write(osIV.c_str(), 1, osIV.size()) == osIV.size());
     724             : 
     725             :     GUInt16 nFreeTextSizeToWrite =
     726        2074 :         CPL_LSBWORD16(static_cast<GUInt16>(osFreeText.size()));
     727        2074 :     bRet &= (fp->Write(&nFreeTextSizeToWrite, 2, 1) == 1);
     728        2074 :     bRet &= (fp->Write(osFreeText.c_str(), 1, osFreeText.size()) ==
     729        2074 :              osFreeText.size());
     730             : 
     731        2074 :     GByte nSize = static_cast<GByte>(osKeyCheckRes.size());
     732        2074 :     bRet &= (fp->Write(&nSize, 1, 1) == 1);
     733        2074 :     bRet &= (fp->Write(osKeyCheckRes.c_str(), 1, osKeyCheckRes.size()) ==
     734        2074 :              osKeyCheckRes.size());
     735             : 
     736        2074 :     GUIntBig nPayloadFileSizeToWrite = nPayloadFileSize;
     737        2074 :     CPL_LSBPTR64(&nPayloadFileSizeToWrite);
     738        2074 :     bRet &= (fp->Write(&nPayloadFileSizeToWrite, 8, 1) == 1);
     739             : 
     740             :     GUInt16 nExtraContentSizeToWrite =
     741        2074 :         CPL_LSBWORD16(static_cast<GUInt16>(osExtraContent.size()));
     742        2074 :     bRet &= (fp->Write(&nExtraContentSizeToWrite, 2, 1) == 1);
     743        2074 :     bRet &= (fp->Write(osExtraContent.c_str(), 1, osExtraContent.size()) ==
     744        2074 :              osExtraContent.size());
     745             : 
     746        2074 :     CPLAssert(fp->Tell() == nHeaderSize);
     747             : 
     748        4148 :     return bRet;
     749             : }
     750             : 
     751             : /************************************************************************/
     752             : /*                          VSICryptFileHandle                          */
     753             : /************************************************************************/
     754             : 
     755             : class VSICryptFileHandle final : public VSIVirtualHandle
     756             : {
     757             :     CPL_DISALLOW_COPY_ASSIGN(VSICryptFileHandle)
     758             : 
     759             :   private:
     760             :     CPLString osBaseFilename{};
     761             :     int nPerms = 0;
     762             :     VSIVirtualHandle *poBaseHandle = nullptr;
     763             :     VSICryptFileHeader *poHeader = nullptr;
     764             :     bool bUpdateHeader = false;
     765             :     vsi_l_offset nCurPos = 0;
     766             :     bool bEOF = false;
     767             : 
     768             :     CryptoPP::BlockCipher *poEncCipher = nullptr;
     769             :     CryptoPP::BlockCipher *poDecCipher = nullptr;
     770             :     int nBlockSize = 0;
     771             : 
     772             :     vsi_l_offset nWBOffset = 0;
     773             :     GByte *pabyWB = nullptr;
     774             :     int nWBSize = 0;
     775             :     bool bWBDirty = false;
     776             : 
     777             :     bool bLastSectorWasModified = false;
     778             : 
     779             :     void EncryptBlock(GByte *pabyData, vsi_l_offset nOffset);
     780             :     bool DecryptBlock(GByte *pabyData, vsi_l_offset nOffset);
     781             :     bool FlushDirty();
     782             : 
     783             :   public:
     784             :     VSICryptFileHandle(const CPLString &osBaseFilename,
     785             :                        VSIVirtualHandle *poBaseHandle,
     786             :                        VSICryptFileHeader *poHeader, int nPerms);
     787             :     ~VSICryptFileHandle() override;
     788             : 
     789             :     int Init(const CPLString &osKey, bool bWriteHeader = false);
     790             : 
     791             :     int Seek(vsi_l_offset nOffset, int nWhence) override;
     792             :     vsi_l_offset Tell() override;
     793             :     size_t Read(void *pBuffer, size_t nSize, size_t nMemb) override;
     794             :     size_t Write(const void *pBuffer, size_t nSize, size_t nMemb) override;
     795             :     int Eof() override;
     796             :     int Flush() override;
     797             :     int Close() override;
     798             :     int Truncate(vsi_l_offset nNewSize) override;
     799             : };
     800             : 
     801             : /************************************************************************/
     802             : /*                          VSICryptFileHandle()                        */
     803             : /************************************************************************/
     804             : 
     805        1173 : VSICryptFileHandle::VSICryptFileHandle(const CPLString &osBaseFilenameIn,
     806             :                                        VSIVirtualHandle *poBaseHandleIn,
     807             :                                        VSICryptFileHeader *poHeaderIn,
     808        1173 :                                        int nPermsIn)
     809             :     : osBaseFilename(osBaseFilenameIn), nPerms(nPermsIn),
     810        1173 :       poBaseHandle(poBaseHandleIn), poHeader(poHeaderIn)
     811             : {
     812        1173 : }
     813             : 
     814             : /************************************************************************/
     815             : /*                         ~VSICryptFileHandle()                        */
     816             : /************************************************************************/
     817             : 
     818        2346 : VSICryptFileHandle::~VSICryptFileHandle()
     819             : {
     820        1173 :     Close();
     821        1173 :     delete poHeader;
     822        1173 :     delete poEncCipher;
     823        1173 :     delete poDecCipher;
     824        1173 :     CPLFree(pabyWB);
     825        2346 : }
     826             : 
     827             : /************************************************************************/
     828             : /*                               Init()                                 */
     829             : /************************************************************************/
     830             : 
     831        1173 : int VSICryptFileHandle::Init(const CPLString &osKey, bool bWriteHeader)
     832             : {
     833        1173 :     poEncCipher = GetEncBlockCipher(poHeader->eAlg);
     834        1173 :     if (poEncCipher == nullptr)
     835             :     {
     836           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     837             :                  "Cipher algorithm not supported in this build: %d",
     838           0 :                  static_cast<int>(poHeader->eAlg));
     839           0 :         return FALSE;
     840             :     }
     841             : 
     842        1173 :     if (poHeader->osIV.size() != poEncCipher->BlockSize())
     843             :     {
     844           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Inconsistent initial vector");
     845           1 :         return FALSE;
     846             :     }
     847             : 
     848        1172 :     poDecCipher = GetDecBlockCipher(poHeader->eAlg);
     849        1172 :     nBlockSize = poEncCipher->BlockSize();
     850        1172 :     int nMaxKeySize = static_cast<int>(poEncCipher->MaxKeyLength());
     851             : 
     852             :     try
     853             :     {
     854        1172 :         if (!osKey.empty())
     855             :         {
     856             :             const int nKeySize =
     857        1167 :                 std::min(nMaxKeySize, static_cast<int>(osKey.size()));
     858        1167 :             poEncCipher->SetKey(
     859        1167 :                 reinterpret_cast<const cryptopp_byte *>(osKey.c_str()),
     860        1167 :                 nKeySize);
     861        1166 :             poDecCipher->SetKey(
     862        1166 :                 reinterpret_cast<const cryptopp_byte *>(osKey.c_str()),
     863        1166 :                 nKeySize);
     864             :         }
     865           5 :         else if (pabyGlobalKey)
     866             :         {
     867           5 :             const int nKeySize = std::min(nMaxKeySize, nGlobalKeySize);
     868           5 :             poEncCipher->SetKey(pabyGlobalKey, nKeySize);
     869           4 :             poDecCipher->SetKey(pabyGlobalKey, nKeySize);
     870             :         }
     871             :         else
     872           0 :             return FALSE;
     873             :     }
     874           2 :     catch (const std::exception &e)
     875             :     {
     876           2 :         CPLError(CE_Failure, CPLE_AppDefined, "CryptoPP exception: %s",
     877           2 :                  e.what());
     878           2 :         return FALSE;
     879             :     }
     880             : 
     881        1170 :     pabyWB = static_cast<GByte *>(CPLCalloc(1, poHeader->nSectorSize));
     882             : 
     883        1170 :     if ((poHeader->nSectorSize % nBlockSize) != 0)
     884             :     {
     885           3 :         CPLError(CE_Failure, CPLE_AppDefined,
     886             :                  "Sector size (%d) is not a multiple of block size (%d)",
     887           3 :                  poHeader->nSectorSize, nBlockSize);
     888           3 :         return FALSE;
     889             :     }
     890        1167 :     if (poHeader->eMode == MODE_CBC_CTS &&
     891           3 :         poHeader->nSectorSize < 2 * nBlockSize)
     892             :     {
     893           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     894             :                  "Sector size (%d) should be at least twice larger than "
     895             :                  "the block size (%d) in CBC_CTS.",
     896           1 :                  poHeader->nSectorSize, nBlockSize);
     897           1 :         return FALSE;
     898             :     }
     899             : 
     900        1166 :     if (bWriteHeader && !poHeader->WriteToFile(poBaseHandle, poEncCipher))
     901             :     {
     902           0 :         return FALSE;
     903             :     }
     904             : 
     905        1166 :     return TRUE;
     906             : }
     907             : 
     908             : /************************************************************************/
     909             : /*                          EncryptBlock()                              */
     910             : /************************************************************************/
     911             : 
     912       70139 : void VSICryptFileHandle::EncryptBlock(GByte *pabyData, vsi_l_offset nOffset)
     913             : {
     914       70139 :     std::string osRes;
     915       70139 :     std::string osIV(VSICryptGenerateSectorIV(poHeader->osIV, nOffset));
     916       70139 :     CPLAssert(static_cast<int>(osIV.size()) == nBlockSize);
     917             : 
     918             :     CryptoPP::StreamTransformation *poMode;
     919             :     try
     920             :     {
     921       70139 :         if (poHeader->eMode == MODE_CBC)
     922       70131 :             poMode = new CryptoPP::CBC_Mode_ExternalCipher::Encryption(
     923       70131 :                 *poEncCipher,
     924       70131 :                 reinterpret_cast<const cryptopp_byte *>(osIV.c_str()));
     925           8 :         else if (poHeader->eMode == MODE_CFB)
     926           2 :             poMode = new CryptoPP::CFB_Mode_ExternalCipher::Encryption(
     927           2 :                 *poEncCipher,
     928           2 :                 reinterpret_cast<const cryptopp_byte *>(osIV.c_str()));
     929           6 :         else if (poHeader->eMode == MODE_OFB)
     930           2 :             poMode = new CryptoPP::OFB_Mode_ExternalCipher::Encryption(
     931           2 :                 *poEncCipher,
     932           2 :                 reinterpret_cast<const cryptopp_byte *>(osIV.c_str()));
     933           4 :         else if (poHeader->eMode == MODE_CTR)
     934           2 :             poMode = new CryptoPP::CTR_Mode_ExternalCipher::Encryption(
     935           2 :                 *poEncCipher,
     936           2 :                 reinterpret_cast<const cryptopp_byte *>(osIV.c_str()));
     937             :         else
     938           2 :             poMode = new CryptoPP::CBC_CTS_Mode_ExternalCipher::Encryption(
     939           2 :                 *poEncCipher,
     940           2 :                 reinterpret_cast<const cryptopp_byte *>(osIV.c_str()));
     941             :     }
     942           0 :     catch (const std::exception &e)
     943             :     {
     944           0 :         CPLError(CE_Failure, CPLE_AppDefined, "cryptopp exception: %s",
     945           0 :                  e.what());
     946           0 :         return;
     947             :     }
     948       70139 :     CryptoPP::StringSink *poSink = new CryptoPP::StringSink(osRes);
     949             :     CryptoPP::StreamTransformationFilter *poEnc =
     950             :         new CryptoPP::StreamTransformationFilter(
     951       70139 :             *poMode, poSink, CryptoPP::StreamTransformationFilter::NO_PADDING);
     952       70139 :     poEnc->Put(pabyData, poHeader->nSectorSize);
     953       70139 :     poEnc->MessageEnd();
     954       70139 :     delete poEnc;
     955             : 
     956       70139 :     delete poMode;
     957             : 
     958       70139 :     CPLAssert(static_cast<int>(osRes.length()) == poHeader->nSectorSize);
     959       70139 :     memcpy(pabyData, osRes.c_str(), osRes.length());
     960             : }
     961             : 
     962             : /************************************************************************/
     963             : /*                          DecryptBlock()                              */
     964             : /************************************************************************/
     965             : 
     966       75247 : bool VSICryptFileHandle::DecryptBlock(GByte *pabyData, vsi_l_offset nOffset)
     967             : {
     968      150494 :     std::string osRes;
     969      150494 :     std::string osIV(VSICryptGenerateSectorIV(poHeader->osIV, nOffset));
     970       75247 :     CPLAssert(static_cast<int>(osIV.size()) == nBlockSize);
     971       75247 :     CryptoPP::StringSink *poSink = new CryptoPP::StringSink(osRes);
     972       75247 :     CryptoPP::StreamTransformation *poMode = nullptr;
     973       75247 :     CryptoPP::StreamTransformationFilter *poDec = nullptr;
     974             : 
     975             :     try
     976             :     {
     977             :         // Yes, some modes need the encryption cipher.
     978       75247 :         if (poHeader->eMode == MODE_CBC)
     979       75239 :             poMode = new CryptoPP::CBC_Mode_ExternalCipher::Decryption(
     980       75239 :                 *poDecCipher,
     981       75239 :                 reinterpret_cast<const cryptopp_byte *>(osIV.c_str()));
     982           8 :         else if (poHeader->eMode == MODE_CFB)
     983           2 :             poMode = new CryptoPP::CFB_Mode_ExternalCipher::Decryption(
     984           2 :                 *poEncCipher,
     985           2 :                 reinterpret_cast<const cryptopp_byte *>(osIV.c_str()));
     986           6 :         else if (poHeader->eMode == MODE_OFB)
     987           2 :             poMode = new CryptoPP::OFB_Mode_ExternalCipher::Decryption(
     988           2 :                 *poEncCipher,
     989           2 :                 reinterpret_cast<const cryptopp_byte *>(osIV.c_str()));
     990           4 :         else if (poHeader->eMode == MODE_CTR)
     991           2 :             poMode = new CryptoPP::CTR_Mode_ExternalCipher::Decryption(
     992           2 :                 *poEncCipher,
     993           2 :                 reinterpret_cast<const cryptopp_byte *>(osIV.c_str()));
     994             :         else
     995           2 :             poMode = new CryptoPP::CBC_CTS_Mode_ExternalCipher::Decryption(
     996           2 :                 *poDecCipher,
     997           2 :                 reinterpret_cast<const cryptopp_byte *>(osIV.c_str()));
     998       75247 :         poDec = new CryptoPP::StreamTransformationFilter(
     999       75247 :             *poMode, poSink, CryptoPP::StreamTransformationFilter::NO_PADDING);
    1000       75247 :         poDec->Put(reinterpret_cast<const cryptopp_byte *>(pabyData),
    1001       75247 :                    poHeader->nSectorSize);
    1002       75247 :         poDec->MessageEnd();
    1003       75247 :         delete poDec;
    1004       75247 :         delete poMode;
    1005             :     }
    1006           0 :     catch (const std::exception &e)
    1007             :     {
    1008           0 :         delete poDec;
    1009           0 :         delete poMode;
    1010             : 
    1011           0 :         CPLError(CE_Failure, CPLE_AppDefined, "CryptoPP exception: %s",
    1012           0 :                  e.what());
    1013           0 :         return false;
    1014             :     }
    1015             : 
    1016       75247 :     CPLAssert(static_cast<int>(osRes.length()) == poHeader->nSectorSize);
    1017       75247 :     memcpy(pabyData, osRes.c_str(), osRes.length());
    1018             : 
    1019       75247 :     return true;
    1020             : }
    1021             : 
    1022             : /************************************************************************/
    1023             : /*                             FlushDirty()                             */
    1024             : /************************************************************************/
    1025             : 
    1026       55327 : bool VSICryptFileHandle::FlushDirty()
    1027             : {
    1028       55327 :     if (!bWBDirty)
    1029       11096 :         return true;
    1030       44231 :     bWBDirty = false;
    1031             : 
    1032       44231 :     EncryptBlock(pabyWB, nWBOffset);
    1033       44231 :     poBaseHandle->Seek(poHeader->nHeaderSize + nWBOffset, SEEK_SET);
    1034             : 
    1035       44231 :     nWBOffset = 0;
    1036       44231 :     nWBSize = 0;
    1037             : 
    1038       44231 :     if (poBaseHandle->Write(pabyWB, poHeader->nSectorSize, 1) != 1)
    1039           0 :         return false;
    1040             : 
    1041       44231 :     return true;
    1042             : }
    1043             : 
    1044             : /************************************************************************/
    1045             : /*                                Seek()                                */
    1046             : /************************************************************************/
    1047             : 
    1048       30973 : int VSICryptFileHandle::Seek(vsi_l_offset nOffset, int nWhence)
    1049             : {
    1050             : #ifdef VERBOSE_VSICRYPT
    1051             :     CPLDebug("VSICRYPT", "Seek(nOffset=" CPL_FRMT_GUIB ", nWhence=%d)", nOffset,
    1052             :              nWhence);
    1053             : #endif
    1054             : 
    1055       30973 :     bEOF = false;
    1056             : 
    1057       30973 :     if (nWhence == SEEK_SET)
    1058       30971 :         nCurPos = nOffset;
    1059           2 :     else if (nWhence == SEEK_CUR)
    1060           0 :         nCurPos += nOffset;
    1061             :     else
    1062           2 :         nCurPos = poHeader->nPayloadFileSize;
    1063       30973 :     return 0;
    1064             : }
    1065             : 
    1066             : /************************************************************************/
    1067             : /*                                  Tell()                              */
    1068             : /************************************************************************/
    1069             : 
    1070           3 : vsi_l_offset VSICryptFileHandle::Tell()
    1071             : {
    1072             : #ifdef VERBOSE_VSICRYPT
    1073             :     CPLDebug("VSICRYPT", "Tell()=" CPL_FRMT_GUIB, nCurPos);
    1074             : #endif
    1075           3 :     return nCurPos;
    1076             : }
    1077             : 
    1078             : /************************************************************************/
    1079             : /*                                Read()                                */
    1080             : /************************************************************************/
    1081             : 
    1082       11003 : size_t VSICryptFileHandle::Read(void *pBuffer, size_t nSize, size_t nMemb)
    1083             : {
    1084       11003 :     size_t nToRead = nSize * nMemb;
    1085       11003 :     GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
    1086             : 
    1087             : #ifdef VERBOSE_VSICRYPT
    1088             :     CPLDebug("VSICRYPT", "Read(nCurPos=" CPL_FRMT_GUIB ", nToRead=%d)", nCurPos,
    1089             :              static_cast<int>(nToRead));
    1090             : #endif
    1091             : 
    1092       11003 :     if ((nPerms & VSICRYPT_READ) == 0)
    1093           0 :         return 0;
    1094             : 
    1095       11003 :     if (nCurPos >= poHeader->nPayloadFileSize)
    1096             :     {
    1097        3881 :         bEOF = true;
    1098        3881 :         return 0;
    1099             :     }
    1100             : 
    1101        7122 :     if (!FlushDirty())
    1102           0 :         return 0;
    1103             : 
    1104       52089 :     while (nToRead > 0)
    1105             :     {
    1106       52089 :         if (nCurPos >= nWBOffset && nCurPos < nWBOffset + nWBSize)
    1107             :         {
    1108             :             // TODO(schwehr): Can nToCopy be a size_t to simplify casting?
    1109             :             int nToCopy =
    1110       89938 :                 std::min(static_cast<int>(nToRead),
    1111       44969 :                          static_cast<int>(nWBSize - (nCurPos - nWBOffset)));
    1112       44969 :             if (nCurPos + nToCopy > poHeader->nPayloadFileSize)
    1113             :             {
    1114        1234 :                 bEOF = true;
    1115        1234 :                 nToCopy =
    1116        1234 :                     static_cast<int>(poHeader->nPayloadFileSize - nCurPos);
    1117             :             }
    1118       44969 :             memcpy(pabyBuffer, pabyWB + nCurPos - nWBOffset, nToCopy);
    1119       44969 :             pabyBuffer += nToCopy;
    1120       44969 :             nToRead -= nToCopy;
    1121       44969 :             nCurPos += nToCopy;
    1122       44969 :             if (bEOF || nToRead == 0)
    1123             :                 break;
    1124       37888 :             CPLAssert((nCurPos % poHeader->nSectorSize) == 0);
    1125             :         }
    1126             : 
    1127       45008 :         vsi_l_offset nSectorOffset =
    1128       45008 :             (nCurPos / poHeader->nSectorSize) * poHeader->nSectorSize;
    1129       45008 :         poBaseHandle->Seek(poHeader->nHeaderSize + nSectorOffset, SEEK_SET);
    1130       45008 :         if (poBaseHandle->Read(pabyWB, poHeader->nSectorSize, 1) != 1)
    1131             :         {
    1132          41 :             bEOF = true;
    1133          41 :             break;
    1134             :         }
    1135       44967 :         if (!DecryptBlock(pabyWB, nSectorOffset))
    1136             :         {
    1137           0 :             break;
    1138             :         }
    1139       44967 :         if ((nPerms & VSICRYPT_WRITE) &&
    1140       44933 :             nSectorOffset + poHeader->nSectorSize > poHeader->nPayloadFileSize)
    1141             :         {
    1142             :             // If the last sector was padded with random values, decrypt it to 0
    1143             :             // in case of update scenarios.
    1144        1347 :             CPLAssert(nSectorOffset < poHeader->nPayloadFileSize);
    1145        1347 :             memset(pabyWB + poHeader->nPayloadFileSize - nSectorOffset, 0,
    1146        1347 :                    nSectorOffset + poHeader->nSectorSize -
    1147        1347 :                        poHeader->nPayloadFileSize);
    1148             :         }
    1149       44967 :         nWBOffset = nSectorOffset;
    1150       44967 :         nWBSize = poHeader->nSectorSize;
    1151             :     }
    1152             : 
    1153        7122 :     int nRet = static_cast<int>((nSize * nMemb - nToRead) / nSize);
    1154             : #ifdef VERBOSE_VSICRYPT
    1155             :     CPLDebug("VSICRYPT", "Read ret = %d (nMemb = %d)", nRet,
    1156             :              static_cast<int>(nMemb));
    1157             : #endif
    1158        7122 :     return nRet;
    1159             : }
    1160             : 
    1161             : /************************************************************************/
    1162             : /*                                Write()                               */
    1163             : /************************************************************************/
    1164             : 
    1165       20040 : size_t VSICryptFileHandle::Write(const void *pBuffer, size_t nSize,
    1166             :                                  size_t nMemb)
    1167             : {
    1168       20040 :     size_t nToWrite = nSize * nMemb;
    1169       20040 :     const GByte *pabyBuffer = static_cast<const GByte *>(pBuffer);
    1170             : 
    1171             : #ifdef VERBOSE_VSICRYPT
    1172             :     CPLDebug("VSICRYPT",
    1173             :              "Write(nCurPos=" CPL_FRMT_GUIB ", nToWrite=%d,"
    1174             :              "nPayloadFileSize=" CPL_FRMT_GUIB
    1175             :              ",bWBDirty=%d,nWBOffset=" CPL_FRMT_GUIB ",nWBSize=%d)",
    1176             :              nCurPos, static_cast<int>(nToWrite), poHeader->nPayloadFileSize,
    1177             :              static_cast<int>(bWBDirty), nWBOffset, nWBSize);
    1178             : #endif
    1179             : 
    1180       20040 :     if ((nPerms & VSICRYPT_WRITE) == 0)
    1181           1 :         return 0;
    1182             : 
    1183       20039 :     if (nCurPos >= (poHeader->nPayloadFileSize / poHeader->nSectorSize) *
    1184       20039 :                        poHeader->nSectorSize)
    1185             :     {
    1186        3266 :         bLastSectorWasModified = true;
    1187             :     }
    1188             : 
    1189             :     // If seeking past end of file, we need to explicitly encrypt the
    1190             :     // padding zeroes.
    1191       20039 :     if (nCurPos > poHeader->nPayloadFileSize && nCurPos > nWBOffset + nWBSize)
    1192             :     {
    1193        2962 :         if (!FlushDirty())
    1194           0 :             return 0;
    1195        2962 :         vsi_l_offset nOffset =
    1196        2962 :             (poHeader->nPayloadFileSize + poHeader->nSectorSize - 1) /
    1197        2962 :             poHeader->nSectorSize * poHeader->nSectorSize;
    1198        2962 :         const vsi_l_offset nEndOffset =
    1199        2962 :             nCurPos / poHeader->nSectorSize * poHeader->nSectorSize;
    1200       27578 :         for (; nOffset < nEndOffset; nOffset += poHeader->nSectorSize)
    1201             :         {
    1202       24616 :             memset(pabyWB, 0, poHeader->nSectorSize);
    1203       24616 :             EncryptBlock(pabyWB, nOffset);
    1204       24616 :             poBaseHandle->Seek(poHeader->nHeaderSize + nOffset, SEEK_SET);
    1205       24616 :             if (poBaseHandle->Write(pabyWB, poHeader->nSectorSize, 1) != 1)
    1206           0 :                 return 0;
    1207       24616 :             poHeader->nPayloadFileSize = nOffset + poHeader->nSectorSize;
    1208       24616 :             bUpdateHeader = true;
    1209             :         }
    1210             :     }
    1211             : 
    1212       79522 :     while (nToWrite > 0)
    1213             :     {
    1214       79133 :         if (nCurPos >= nWBOffset && nCurPos < nWBOffset + nWBSize)
    1215             :         {
    1216       35066 :             bWBDirty = true;
    1217             :             const int nToCopy =
    1218       70132 :                 std::min(static_cast<int>(nToWrite),
    1219       35066 :                          static_cast<int>(nWBSize - (nCurPos - nWBOffset)));
    1220       35066 :             memcpy(pabyWB + nCurPos - nWBOffset, pabyBuffer, nToCopy);
    1221       35066 :             pabyBuffer += nToCopy;
    1222       35066 :             nToWrite -= nToCopy;
    1223       35066 :             nCurPos += nToCopy;
    1224       35066 :             if (nCurPos > poHeader->nPayloadFileSize)
    1225             :             {
    1226        6102 :                 bUpdateHeader = true;
    1227        6102 :                 poHeader->nPayloadFileSize = nCurPos;
    1228             :             }
    1229       35066 :             if (nToWrite == 0)
    1230       19650 :                 break;
    1231       15416 :             CPLAssert((nCurPos % poHeader->nSectorSize) == 0);
    1232             :         }
    1233       44067 :         else if ((nCurPos % poHeader->nSectorSize) == 0 &&
    1234       25241 :                  nToWrite >= static_cast<size_t>(poHeader->nSectorSize))
    1235             :         {
    1236        9558 :             if (!FlushDirty())
    1237           0 :                 break;
    1238             : 
    1239        9558 :             bWBDirty = true;
    1240        9558 :             nWBOffset = nCurPos;
    1241        9558 :             nWBSize = poHeader->nSectorSize;
    1242        9558 :             memcpy(pabyWB, pabyBuffer, poHeader->nSectorSize);
    1243        9558 :             pabyBuffer += poHeader->nSectorSize;
    1244        9558 :             nToWrite -= poHeader->nSectorSize;
    1245        9558 :             nCurPos += poHeader->nSectorSize;
    1246        9558 :             if (nCurPos > poHeader->nPayloadFileSize)
    1247             :             {
    1248        1837 :                 bUpdateHeader = true;
    1249        1837 :                 poHeader->nPayloadFileSize = nCurPos;
    1250             :             }
    1251             :         }
    1252             :         else
    1253             :         {
    1254       34509 :             if (!FlushDirty())
    1255           0 :                 break;
    1256             : 
    1257       34509 :             const vsi_l_offset nSectorOffset =
    1258       34509 :                 (nCurPos / poHeader->nSectorSize) * poHeader->nSectorSize;
    1259       34509 :             const vsi_l_offset nLastSectorOffset =
    1260       34509 :                 (poHeader->nPayloadFileSize / poHeader->nSectorSize) *
    1261       34509 :                 poHeader->nSectorSize;
    1262       34509 :             if (nSectorOffset > nLastSectorOffset &&
    1263         286 :                 (poHeader->nPayloadFileSize % poHeader->nSectorSize) != 0)
    1264             :             {
    1265         858 :                 if (poBaseHandle->Seek(
    1266         286 :                         poHeader->nHeaderSize + nLastSectorOffset, 0) == 0 &&
    1267         572 :                     poBaseHandle->Read(pabyWB, poHeader->nSectorSize, 1) == 1 &&
    1268         286 :                     DecryptBlock(pabyWB, nLastSectorOffset))
    1269             :                 {
    1270             : #ifdef VERBOSE_VSICRYPT
    1271             :                     CPLDebug("VSICRYPT", "Filling %d trailing bytes with 0",
    1272             :                              static_cast<int>(poHeader->nSectorSize -
    1273             :                                               (poHeader->nPayloadFileSize -
    1274             :                                                nLastSectorOffset)));
    1275             : #endif
    1276             :                     // Fill with 0.
    1277         286 :                     memset(
    1278         286 :                         pabyWB + poHeader->nPayloadFileSize - nLastSectorOffset,
    1279             :                         0,
    1280             :                         static_cast<int>(
    1281         286 :                             poHeader->nSectorSize -
    1282         286 :                             (poHeader->nPayloadFileSize - nLastSectorOffset)));
    1283             : 
    1284         572 :                     if (poBaseHandle->Seek(
    1285         286 :                             poHeader->nHeaderSize + nLastSectorOffset, 0) == 0)
    1286             :                     {
    1287         286 :                         EncryptBlock(pabyWB, nLastSectorOffset);
    1288         286 :                         poBaseHandle->Write(pabyWB, poHeader->nSectorSize, 1);
    1289             :                     }
    1290             :                 }
    1291             :             }
    1292       34509 :             poBaseHandle->Seek(poHeader->nHeaderSize + nSectorOffset, SEEK_SET);
    1293       63497 :             if (poBaseHandle->Read(pabyWB, poHeader->nSectorSize, 1) == 0 ||
    1294       28988 :                 !DecryptBlock(pabyWB, nSectorOffset))
    1295             :             {
    1296        5521 :                 memset(pabyWB, 0, poHeader->nSectorSize);
    1297             :             }
    1298       28988 :             else if (nSectorOffset + poHeader->nSectorSize >
    1299       28988 :                      poHeader->nPayloadFileSize)
    1300             :             {
    1301             :                 // If the last sector was padded with random values,
    1302             :                 // decrypt it to 0 in case of update scenarios.
    1303         735 :                 CPLAssert(nSectorOffset < poHeader->nPayloadFileSize);
    1304         735 :                 memset(pabyWB + poHeader->nPayloadFileSize - nSectorOffset, 0,
    1305         735 :                        nSectorOffset + poHeader->nSectorSize -
    1306         735 :                            poHeader->nPayloadFileSize);
    1307             :             }
    1308       34509 :             nWBOffset = nSectorOffset;
    1309       34509 :             nWBSize = poHeader->nSectorSize;
    1310             :         }
    1311             :     }
    1312             : 
    1313       20039 :     int nRet = static_cast<int>((nSize * nMemb - nToWrite) / nSize);
    1314             : #ifdef VERBOSE_VSICRYPT
    1315             :     CPLDebug("VSICRYPT", "Write ret = %d (nMemb = %d)", nRet,
    1316             :              static_cast<int>(nMemb));
    1317             : #endif
    1318       20039 :     return nRet;
    1319             : }
    1320             : 
    1321             : /************************************************************************/
    1322             : /*                             Truncate()                               */
    1323             : /************************************************************************/
    1324             : 
    1325             : // Returns 0 on success.  Returns -1 on error.
    1326           3 : int VSICryptFileHandle::Truncate(vsi_l_offset nNewSize)
    1327             : {
    1328             : #ifdef VERBOSE_VSICRYPT
    1329             :     CPLDebug("VSICRYPT", "Truncate(" CPL_FRMT_GUIB ")", nNewSize);
    1330             : #endif
    1331           3 :     if ((nPerms & VSICRYPT_WRITE) == 0)
    1332           1 :         return -1;
    1333             : 
    1334           2 :     if (!FlushDirty())
    1335           0 :         return -1;
    1336           4 :     if (poBaseHandle->Truncate(
    1337           2 :             poHeader->nHeaderSize +
    1338           2 :             ((nNewSize + poHeader->nSectorSize - 1) / poHeader->nSectorSize) *
    1339           2 :                 poHeader->nSectorSize) != 0)
    1340           0 :         return -1;
    1341           2 :     bUpdateHeader = true;
    1342           2 :     poHeader->nPayloadFileSize = nNewSize;
    1343           2 :     return 0;
    1344             : }
    1345             : 
    1346             : /************************************************************************/
    1347             : /*                                Eof()                                 */
    1348             : /************************************************************************/
    1349             : 
    1350           0 : int VSICryptFileHandle::Eof()
    1351             : {
    1352             : #ifdef VERBOSE_VSICRYPT
    1353             :     CPLDebug("VSICRYPT", "Eof() = %d", static_cast<int>(bEOF));
    1354             : #endif
    1355           0 :     return bEOF;
    1356             : }
    1357             : 
    1358             : /************************************************************************/
    1359             : /*                                 Flush()                              */
    1360             : /************************************************************************/
    1361             : 
    1362        1174 : int VSICryptFileHandle::Flush()
    1363             : {
    1364             : #ifdef VERBOSE_VSICRYPT
    1365             :     CPLDebug("VSICRYPT", "Flush()");
    1366             : #endif
    1367        1174 :     if (!FlushDirty())
    1368             :     {
    1369           0 :         return -1;
    1370             :     }
    1371        1174 :     if ((nPerms & VSICRYPT_WRITE))
    1372             :     {
    1373        1044 :         if (bLastSectorWasModified &&
    1374        1038 :             (poHeader->nPayloadFileSize % poHeader->nSectorSize) != 0)
    1375             :         {
    1376        1006 :             const vsi_l_offset nLastSectorOffset =
    1377        1006 :                 (poHeader->nPayloadFileSize / poHeader->nSectorSize) *
    1378        1006 :                 poHeader->nSectorSize;
    1379        3018 :             if (poBaseHandle->Seek(poHeader->nHeaderSize + nLastSectorOffset,
    1380        1006 :                                    0) == 0 &&
    1381        2012 :                 poBaseHandle->Read(pabyWB, poHeader->nSectorSize, 1) == 1 &&
    1382        1006 :                 DecryptBlock(pabyWB, nLastSectorOffset))
    1383             :             {
    1384             :                 // Fill with random
    1385             : #ifdef VERBOSE_VSICRYPT
    1386             :                 CPLDebug("VSICRYPT", "Filling %d trailing bytes with random",
    1387             :                          static_cast<int>(
    1388             :                              poHeader->nSectorSize -
    1389             :                              (poHeader->nPayloadFileSize - nLastSectorOffset)));
    1390             : #endif
    1391        1006 :                 CryptoPP::OS_GenerateRandomBlock(
    1392             :                     false,  // Do not need cryptographic randomness.
    1393             :                     reinterpret_cast<cryptopp_byte *>(
    1394        1006 :                         pabyWB + poHeader->nPayloadFileSize -
    1395             :                         nLastSectorOffset),
    1396             :                     static_cast<int>(
    1397        1006 :                         poHeader->nSectorSize -
    1398        1006 :                         (poHeader->nPayloadFileSize - nLastSectorOffset)));
    1399             : 
    1400        2012 :                 if (poBaseHandle->Seek(
    1401        1006 :                         poHeader->nHeaderSize + nLastSectorOffset, 0) == 0)
    1402             :                 {
    1403        1006 :                     EncryptBlock(pabyWB, nLastSectorOffset);
    1404        1006 :                     poBaseHandle->Write(pabyWB, poHeader->nSectorSize, 1);
    1405             :                 }
    1406             :             }
    1407             :         }
    1408        1044 :         bLastSectorWasModified = false;
    1409        1044 :         if (poBaseHandle->Flush() != 0)
    1410           0 :             return -1;
    1411             :     }
    1412        1174 :     if (bUpdateHeader)
    1413             :     {
    1414             : #ifdef VERBOSE_VSICRYPT
    1415             :         CPLDebug("VSICRYPT", "nPayloadFileSize = " CPL_FRMT_GUIB,
    1416             :                  poHeader->nPayloadFileSize);
    1417             : #endif
    1418        1038 :         if (!poHeader->WriteToFile(poBaseHandle, poEncCipher))
    1419           0 :             return -1;
    1420             :     }
    1421             : 
    1422        1174 :     return 0;
    1423             : }
    1424             : 
    1425             : /************************************************************************/
    1426             : /*                                  Close()                             */
    1427             : /************************************************************************/
    1428             : 
    1429        2339 : int VSICryptFileHandle::Close()
    1430             : {
    1431        2339 :     int nRet = 0;
    1432        2339 :     if (poBaseHandle != nullptr && poHeader != nullptr)
    1433             :     {
    1434        1173 :         if (Flush() != 0)
    1435           0 :             return -1;
    1436        1173 :         nRet = poBaseHandle->Close();
    1437        1173 :         delete poBaseHandle;
    1438        1173 :         poBaseHandle = nullptr;
    1439             :     }
    1440             : #ifdef VERBOSE_VSICRYPT
    1441             :     CPLDebug("VSICRYPT", "Close(%s)", osBaseFilename.c_str());
    1442             : #endif
    1443        2339 :     return nRet;
    1444             : }
    1445             : 
    1446             : /************************************************************************/
    1447             : /*                   VSICryptFilesystemHandler                          */
    1448             : /************************************************************************/
    1449             : 
    1450             : class VSICryptFilesystemHandler final : public VSIFilesystemHandler
    1451             : {
    1452             :   public:
    1453             :     VSICryptFilesystemHandler();
    1454             :     ~VSICryptFilesystemHandler() override;
    1455             : 
    1456             :     VSIVirtualHandle *Open(const char *pszFilename, const char *pszAccess,
    1457             :                            bool bSetError,
    1458             :                            CSLConstList /* papszOptions */) override;
    1459             :     int Stat(const char *pszFilename, VSIStatBufL *pStatBuf,
    1460             :              int nFlags) override;
    1461             :     int Unlink(const char *pszFilename) override;
    1462             :     int Rename(const char *oldpath, const char *newpath) override;
    1463             :     char **ReadDirEx(const char *pszDirname, int nMaxFiles) override;
    1464             : };
    1465             : 
    1466             : /************************************************************************/
    1467             : /*                   VSICryptFilesystemHandler()                        */
    1468             : /************************************************************************/
    1469             : 
    1470        1225 : VSICryptFilesystemHandler::VSICryptFilesystemHandler()
    1471             : {
    1472        1225 : }
    1473             : 
    1474             : /************************************************************************/
    1475             : /*                    ~VSICryptFilesystemHandler()                      */
    1476             : /************************************************************************/
    1477             : 
    1478        1698 : VSICryptFilesystemHandler::~VSICryptFilesystemHandler()
    1479             : {
    1480        1698 : }
    1481             : 
    1482             : /************************************************************************/
    1483             : /*                             GetFilename()                            */
    1484             : /************************************************************************/
    1485             : 
    1486        2294 : static CPLString GetFilename(const char *pszFilename)
    1487             : {
    1488        2294 :     if (strcmp(pszFilename, VSICRYPT_PREFIX_WITHOUT_SLASH) == 0)
    1489           0 :         pszFilename = VSICRYPT_PREFIX;
    1490             : 
    1491        2294 :     CPLAssert(strncmp(pszFilename, VSICRYPT_PREFIX, strlen(VSICRYPT_PREFIX)) ==
    1492             :               0);
    1493        2294 :     pszFilename += strlen(VSICRYPT_PREFIX);
    1494        2294 :     const char *pszFileArg = strstr(pszFilename, "file=");
    1495        2294 :     if (pszFileArg == nullptr)
    1496          13 :         return pszFilename;
    1497        4562 :     CPLString osRet(pszFileArg + strlen("file="));
    1498        2281 :     return osRet;
    1499             : }
    1500             : 
    1501             : /************************************************************************/
    1502             : /*                             GetArgument()                            */
    1503             : /************************************************************************/
    1504             : 
    1505        7554 : static CPLString GetArgument(const char *pszFilename, const char *pszParamName,
    1506             :                              const char *pszDefault = "")
    1507             : {
    1508       15108 :     CPLString osParamName(pszParamName);
    1509        7554 :     osParamName += "=";
    1510             : 
    1511        7554 :     const char *pszNeedle = strstr(pszFilename, osParamName);
    1512        7554 :     if (pszNeedle == nullptr)
    1513        5248 :         return pszDefault;
    1514             : 
    1515        4612 :     CPLString osRet(pszNeedle + osParamName.size());
    1516        2306 :     size_t nCommaPos = osRet.find(",");
    1517        2306 :     if (nCommaPos != std::string::npos)
    1518        2306 :         osRet.resize(nCommaPos);
    1519        2306 :     return osRet;
    1520             : }
    1521             : 
    1522             : /************************************************************************/
    1523             : /*                               GetKey()                               */
    1524             : /************************************************************************/
    1525             : 
    1526        1284 : static CPLString GetKey(const char *pszFilename)
    1527             : {
    1528        1284 :     CPLString osKey = GetArgument(pszFilename, "key");
    1529             :     // TODO(schwehr): Make 10U and 1024U into symbolic constants.
    1530        1284 :     if (osKey.empty())
    1531             :     {
    1532          11 :         const char *pszKey = CPLGetConfigOption("VSICRYPT_KEY", "");
    1533             :         // Do some form of validation to please Coverity
    1534          11 :         CPLAssert(strlen(pszKey) < 10U * 1024U);
    1535             :         // coverity [tainted_data_transitive]
    1536          11 :         osKey = pszKey;
    1537             :     }
    1538        1284 :     if (osKey.empty() || EQUAL(osKey, "GENERATE_IT"))
    1539             :     {
    1540          12 :         CPLString osKeyB64(GetArgument(pszFilename, "key_b64"));
    1541          12 :         if (osKeyB64.empty())
    1542             :         {
    1543          11 :             const char *pszKey = CPLGetConfigOption("VSICRYPT_KEY_B64", "");
    1544             :             // Do some form of validation to please Coverity
    1545          11 :             CPLAssert(strlen(pszKey) < 10U * 1024U);
    1546             :             // coverity [tainted_data_transitive]
    1547          11 :             osKeyB64 = pszKey;
    1548             :         }
    1549          12 :         if (!osKeyB64.empty())
    1550             :         {
    1551           2 :             GByte *key = reinterpret_cast<GByte *>(CPLStrdup(osKeyB64));
    1552           2 :             int nLength = CPLBase64DecodeInPlace(key);
    1553           2 :             osKey.assign(reinterpret_cast<const char *>(key), nLength);
    1554           2 :             memset(key, 0, osKeyB64.size());
    1555           2 :             CPLFree(key);
    1556             :         }
    1557             :         // coverity[tainted_data]
    1558          12 :         memset(const_cast<char *>(osKeyB64.c_str()), 0, osKeyB64.size());
    1559             :     }
    1560        1284 :     return osKey;
    1561             : }
    1562             : 
    1563             : /************************************************************************/
    1564             : /*                                Open()                                */
    1565             : /************************************************************************/
    1566             : 
    1567             : VSIVirtualHandle *
    1568        1280 : VSICryptFilesystemHandler::Open(const char *pszFilename, const char *pszAccess,
    1569             :                                 bool /* bSetError */,
    1570             :                                 CSLConstList /* papszOptions */)
    1571             : {
    1572             : #ifdef VERBOSE_VSICRYPT
    1573             :     CPLDebug("VSICRYPT", "Open(%s, %s)", pszFilename, pszAccess);
    1574             : #endif
    1575        2560 :     CPLString osFilename(GetFilename(pszFilename));
    1576             : 
    1577        2560 :     CPLString osKey(GetKey(pszFilename));
    1578        1280 :     if (osKey.empty() && pabyGlobalKey == nullptr)
    1579             :     {
    1580           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    1581             :                  "Encryption key not defined as key/key_b64 parameter, "
    1582             :                  "VSICRYPT_KEY/VSICRYPT_KEY_B64 configuration option or "
    1583             :                  "VSISetCryptKey() API");
    1584           2 :         return nullptr;
    1585             :     }
    1586             : 
    1587        1278 :     if (strchr(pszAccess, 'r'))
    1588             :     {
    1589         456 :         CPLString osAccess(pszAccess);
    1590         228 :         if (strchr(pszAccess, 'b') == nullptr)
    1591          14 :             osAccess += "b";
    1592         228 :         VSIVirtualHandle *fpBase = reinterpret_cast<VSIVirtualHandle *>(
    1593             :             VSIFOpenL(osFilename, osAccess));
    1594         228 :         if (fpBase == nullptr)
    1595           1 :             return nullptr;
    1596         227 :         VSICryptFileHeader *poHeader = new VSICryptFileHeader();
    1597         227 :         if (!poHeader->ReadFromFile(fpBase, osKey))
    1598             :         {
    1599          94 :             memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1600          94 :             fpBase->Close();
    1601          94 :             delete fpBase;
    1602          94 :             delete poHeader;
    1603          94 :             return nullptr;
    1604             :         }
    1605             : 
    1606             :         VSICryptFileHandle *poHandle = new VSICryptFileHandle(
    1607             :             osFilename, fpBase, poHeader,
    1608         133 :             strchr(pszAccess, '+') ? VSICRYPT_READ | VSICRYPT_WRITE
    1609         133 :                                    : VSICRYPT_READ);
    1610         133 :         if (!poHandle->Init(osKey, false))
    1611             :         {
    1612           4 :             memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1613           4 :             delete poHandle;
    1614           4 :             poHandle = nullptr;
    1615             :         }
    1616         133 :         memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1617         133 :         return poHandle;
    1618             :     }
    1619        1050 :     else if (strchr(pszAccess, 'w'))
    1620             :     {
    1621             :         CPLString osAlg(GetArgument(pszFilename, "alg",
    1622        2086 :                                     CPLGetConfigOption("VSICRYPT_ALG", "AES")));
    1623        1043 :         VSICryptAlg eAlg = GetAlg(osAlg);
    1624             : 
    1625        1043 :         VSICryptMode eMode = GetMode(GetArgument(
    1626             :             pszFilename, "mode", CPLGetConfigOption("VSICRYPT_MODE", "CBC")));
    1627             : 
    1628             :         CPLString osFreeText =
    1629             :             GetArgument(pszFilename, "freetext",
    1630        2086 :                         CPLGetConfigOption("VSICRYPT_FREETEXT", ""));
    1631             : 
    1632             :         CPLString osIV = GetArgument(pszFilename, "iv",
    1633        2086 :                                      CPLGetConfigOption("VSICRYPT_IV", ""));
    1634             : 
    1635        1043 :         int nSectorSize = atoi(
    1636        2086 :             GetArgument(pszFilename, "sector_size",
    1637             :                         CPLGetConfigOption("VSICRYPT_SECTOR_SIZE", "512")));
    1638        1043 :         if (nSectorSize <= 0 || nSectorSize >= 65535)
    1639             :         {
    1640           0 :             CPLError(CE_Warning, CPLE_NotSupported,
    1641             :                      "Invalid value for sector_size. Defaulting to 512.");
    1642           0 :             nSectorSize = 512;
    1643             :         }
    1644             : 
    1645        1043 :         const bool bAddKeyCheck = CPLTestBool(
    1646        2086 :             GetArgument(pszFilename, "add_key_check",
    1647             :                         CPLGetConfigOption("VSICRYPT_ADD_KEY_CHECK", "NO")));
    1648             : 
    1649             :         /* Generate random initial vector */
    1650        1043 :         CryptoPP::BlockCipher *poBlock = GetEncBlockCipher(eAlg);
    1651        1043 :         if (poBlock == nullptr)
    1652             :         {
    1653           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1654             :                      "Cipher algorithm not supported in this build: %s",
    1655             :                      osAlg.c_str());
    1656           0 :             memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1657           0 :             return nullptr;
    1658             :         }
    1659        1043 :         int nMinKeySize = static_cast<int>(poBlock->MinKeyLength());
    1660        1043 :         int nMaxKeySize = static_cast<int>(poBlock->MaxKeyLength());
    1661        1043 :         int nBlockSize = static_cast<int>(poBlock->BlockSize());
    1662        1043 :         delete poBlock;
    1663             : 
    1664        1043 :         if (!osIV.empty())
    1665             :         {
    1666           1 :             if (static_cast<int>(osIV.size()) != nBlockSize)
    1667             :             {
    1668           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1669             :                          "IV should be %d byte large", nBlockSize);
    1670           1 :                 memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1671           1 :                 return nullptr;
    1672             :             }
    1673             :         }
    1674             :         else
    1675             :         {
    1676        1042 :             osIV.resize(nBlockSize);
    1677        2084 :             CryptoPP::OS_GenerateRandomBlock(
    1678             :                 false,  // Do not need cryptographic randomness.
    1679             :                 reinterpret_cast<cryptopp_byte *>(
    1680        1042 :                     const_cast<char *>(osIV.c_str())),
    1681             :                 osIV.size());
    1682             :         }
    1683             : 
    1684        1042 :         if (EQUAL(osKey, "GENERATE_IT"))
    1685             :         {
    1686           1 :             osKey.resize(nMaxKeySize);
    1687           1 :             CPLDebug("VSICRYPT",
    1688             :                      "Generating key. This might take some time...");
    1689           1 :             CryptoPP::OS_GenerateRandomBlock(
    1690             :                 // Need cryptographic randomness.
    1691             :                 // Config option for speeding tests.
    1692           1 :                 CPLTestBool(
    1693             :                     CPLGetConfigOption("VSICRYPT_CRYPTO_RANDOM", "TRUE")),
    1694             :                 reinterpret_cast<cryptopp_byte *>(
    1695           1 :                     const_cast<char *>(osKey.c_str())),
    1696             :                 osKey.size());
    1697             : 
    1698             :             char *pszB64 =
    1699           1 :                 CPLBase64Encode(static_cast<int>(osKey.size()),
    1700           1 :                                 reinterpret_cast<const GByte *>(osKey.c_str()));
    1701           1 :             if (CPLTestBool(CPLGetConfigOption("VSICRYPT_DISPLAY_GENERATED_KEY",
    1702             :                                                "TRUE")))
    1703             :             {
    1704           1 :                 CPLError(CE_Failure, CPLE_AppDefined,
    1705             :                          "BASE64 key '%s' has been generated, and installed in "
    1706             :                          "the VSICRYPT_KEY_B64 configuration option.",
    1707             :                          pszB64);
    1708             :             }
    1709           1 :             CPLSetConfigOption("VSICRYPT_KEY_B64", pszB64);
    1710           1 :             CPLFree(pszB64);
    1711             :         }
    1712             : 
    1713             :         const int nKeyLength =
    1714        1042 :             !osKey.empty() ? static_cast<int>(osKey.size()) : nGlobalKeySize;
    1715        1042 :         if (nKeyLength < nMinKeySize)
    1716             :         {
    1717           2 :             CPLError(CE_Failure, CPLE_AppDefined,
    1718             :                      "Key is too short: %d bytes. Should be at least %d bytes",
    1719             :                      nKeyLength, nMinKeySize);
    1720           2 :             memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1721           2 :             return nullptr;
    1722             :         }
    1723             : 
    1724             :         VSIVirtualHandle *fpBase =
    1725        1040 :             reinterpret_cast<VSIVirtualHandle *>(VSIFOpenL(osFilename, "wb+"));
    1726        1040 :         if (fpBase == nullptr)
    1727             :         {
    1728           2 :             memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1729           2 :             return nullptr;
    1730             :         }
    1731             : 
    1732        1038 :         VSICryptFileHeader *poHeader = new VSICryptFileHeader();
    1733        1038 :         poHeader->osIV = osIV;
    1734        1038 :         CPL_IGNORE_RET_VAL(osIV);
    1735        1038 :         poHeader->eAlg = eAlg;
    1736        1038 :         poHeader->eMode = eMode;
    1737        1038 :         poHeader->nSectorSize = static_cast<GUInt16>(nSectorSize);
    1738        1038 :         poHeader->osFreeText = std::move(osFreeText);
    1739        1038 :         poHeader->bAddKeyCheck = bAddKeyCheck;
    1740             : 
    1741             :         VSICryptFileHandle *poHandle = new VSICryptFileHandle(
    1742             :             osFilename, fpBase, poHeader,
    1743        1038 :             strchr(pszAccess, '+') ? VSICRYPT_READ | VSICRYPT_WRITE
    1744        1038 :                                    : VSICRYPT_WRITE);
    1745        1038 :         if (!poHandle->Init(osKey, true))
    1746             :         {
    1747           2 :             memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1748           2 :             delete poHandle;
    1749           2 :             poHandle = nullptr;
    1750             :         }
    1751        1038 :         memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1752        1038 :         return poHandle;
    1753             :     }
    1754           7 :     else if (strchr(pszAccess, 'a'))
    1755             :     {
    1756             :         VSIVirtualHandle *fpBase =
    1757           6 :             reinterpret_cast<VSIVirtualHandle *>(VSIFOpenL(osFilename, "rb+"));
    1758           6 :         if (fpBase == nullptr)
    1759             :         {
    1760           2 :             memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1761           2 :             return VSIFilesystemHandler::Open(pszFilename, "wb+");
    1762             :         }
    1763           4 :         VSICryptFileHeader *poHeader = new VSICryptFileHeader();
    1764           4 :         if (!poHeader->ReadFromFile(fpBase, osKey))
    1765             :         {
    1766           2 :             memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1767           2 :             fpBase->Close();
    1768           2 :             delete fpBase;
    1769           2 :             delete poHeader;
    1770           2 :             return nullptr;
    1771             :         }
    1772             : 
    1773             :         VSICryptFileHandle *poHandle = new VSICryptFileHandle(
    1774           2 :             osFilename, fpBase, poHeader, VSICRYPT_READ | VSICRYPT_WRITE);
    1775           2 :         if (!poHandle->Init(osKey))
    1776             :         {
    1777           1 :             delete poHandle;
    1778           1 :             poHandle = nullptr;
    1779             :         }
    1780           2 :         memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1781           2 :         if (poHandle != nullptr)
    1782           1 :             poHandle->Seek(0, SEEK_END);
    1783           2 :         return poHandle;
    1784             :     }
    1785             : 
    1786           1 :     return nullptr;
    1787             : }
    1788             : 
    1789             : /************************************************************************/
    1790             : /*                                Stat()                                */
    1791             : /************************************************************************/
    1792             : 
    1793           5 : int VSICryptFilesystemHandler::Stat(const char *pszFilename,
    1794             :                                     VSIStatBufL *pStatBuf, int nFlags)
    1795             : {
    1796             : #ifdef VERBOSE_VSICRYPT
    1797             :     CPLDebug("VSICRYPT", "Stat(%s)", pszFilename);
    1798             : #endif
    1799          10 :     CPLString osFilename(GetFilename(pszFilename));
    1800           5 :     if (VSIStatExL(osFilename, pStatBuf, nFlags) != 0)
    1801           1 :         return -1;
    1802             :     VSIVirtualHandle *fp =
    1803           4 :         reinterpret_cast<VSIVirtualHandle *>(VSIFOpenL(osFilename, "rb"));
    1804           4 :     if (fp == nullptr)
    1805           0 :         return -1;
    1806           4 :     VSICryptFileHeader *poHeader = new VSICryptFileHeader();
    1807           8 :     CPLString osKey(GetKey(pszFilename));
    1808           4 :     if (!poHeader->ReadFromFile(fp, osKey))
    1809             :     {
    1810           1 :         memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1811           1 :         fp->Close();
    1812           1 :         delete fp;
    1813           1 :         delete poHeader;
    1814           1 :         return -1;
    1815             :     }
    1816           3 :     memset(const_cast<char *>(osKey.c_str()), 0, osKey.size());
    1817           3 :     fp->Close();
    1818           3 :     delete fp;
    1819           3 :     if (poHeader)
    1820             :     {
    1821           3 :         pStatBuf->st_size = poHeader->nPayloadFileSize;
    1822           3 :         delete poHeader;
    1823           3 :         return 0;
    1824             :     }
    1825             :     else
    1826           0 :         return -1;
    1827             : }
    1828             : 
    1829             : /************************************************************************/
    1830             : /*                               Unlink()                               */
    1831             : /************************************************************************/
    1832             : 
    1833        1005 : int VSICryptFilesystemHandler::Unlink(const char *pszFilename)
    1834             : {
    1835        1005 :     return VSIUnlink(GetFilename(pszFilename));
    1836             : }
    1837             : 
    1838             : /************************************************************************/
    1839             : /*                               Rename()                               */
    1840             : /************************************************************************/
    1841             : 
    1842           2 : int VSICryptFilesystemHandler::Rename(const char *oldpath, const char *newpath)
    1843             : {
    1844           2 :     CPLString osNewPath;
    1845           2 :     if (strncmp(newpath, VSICRYPT_PREFIX, strlen(VSICRYPT_PREFIX)) == 0)
    1846           1 :         osNewPath = GetFilename(newpath);
    1847             :     else
    1848           1 :         osNewPath = newpath;
    1849             : 
    1850           4 :     return VSIRename(GetFilename(oldpath), osNewPath);
    1851             : }
    1852             : 
    1853             : /************************************************************************/
    1854             : /*                               ReadDirEx()                            */
    1855             : /************************************************************************/
    1856             : 
    1857           1 : char **VSICryptFilesystemHandler::ReadDirEx(const char *pszDirname,
    1858             :                                             int nMaxFiles)
    1859             : {
    1860             : #ifdef VERBOSE_VSICRYPT
    1861             :     CPLDebug("VSICRYPT", "ReadDir(%s)", pszDirname);
    1862             : #endif
    1863           1 :     return VSIReadDirEx(GetFilename(pszDirname), nMaxFiles);
    1864             : }
    1865             : 
    1866             : #ifdef VSICRYPT_DRIVER
    1867             : 
    1868             : #include "gdal_priv.h"
    1869             : 
    1870             : /**
    1871             :  * \brief Evaluate if this is a crypt file.
    1872             :  *
    1873             :  * The function signature must match GDALDataset::Identify.
    1874             :  *
    1875             :  * @param poOpenInfo The header bytes used for file identification.
    1876             :  *
    1877             :  * @return 1 if this is a crypt file or 0 otherwise.
    1878             :  */
    1879             : 
    1880             : static int VSICryptIdentify(GDALOpenInfo *poOpenInfo)
    1881             : {
    1882             :     return poOpenInfo->nHeaderBytes > 8 &&
    1883             :            memcmp(poOpenInfo->pabyHeader, VSICRYPT_SIGNATURE, 8) == 0;
    1884             : }
    1885             : 
    1886             : static GDALDataset *VSICryptOpen(GDALOpenInfo *poOpenInfo)
    1887             : {
    1888             :     if (!VSICryptIdentify(poOpenInfo))
    1889             :         return nullptr;
    1890             :     return GDALOpen(
    1891             :         (CPLString(VSICRYPT_PREFIX) + poOpenInfo->pszFilename).c_str(),
    1892             :         poOpenInfo->eAccess);
    1893             : }
    1894             : 
    1895             : #endif
    1896             : 
    1897             : //! @endcond
    1898             : 
    1899             : /************************************************************************/
    1900             : /*                   VSIInstallCryptFileHandler()                       */
    1901             : /************************************************************************/
    1902             : 
    1903             : /**
    1904             :  * \brief Install /vsicrypt/ encrypted file system handler
    1905             :  * (requires <a href="http://www.cryptopp.com/">libcrypto++</a>)
    1906             :  *
    1907             :  * A special file handler is installed that allows reading/creating/update
    1908             :  * encrypted files on the fly, with random access capabilities.
    1909             :  *
    1910             :  * The cryptographic algorithms used are
    1911             :  * <a href="https://en.wikipedia.org/wiki/Block_cipher">block ciphers</a>,
    1912             :  * with symmetric key.
    1913             :  *
    1914             :  * In their simplest form, recognized filenames are of the form
    1915             :  * /vsicrypt//absolute_path/to/file, /vsicrypt/c:/absolute_path/to/file or
    1916             :  * /vsicrypt/relative/path/to/file.
    1917             :  *
    1918             :  * Options can also be used with the following format :
    1919             :  * /vsicrypt/option1=val1,option2=val2,...,file=/path/to/file
    1920             :  *
    1921             :  * They can also be passed as configuration option/environment variable, because
    1922             :  * in some use cases, the syntax with option in the filename might not properly
    1923             :  * work with some drivers.
    1924             :  *
    1925             :  * In all modes, the encryption key must be provided. There are several ways
    1926             :  * of doing so :
    1927             :  * <ul>
    1928             :  * <li>By adding a key= parameter to the filename, like
    1929             :  *     /vsicrypt/key=my_secret_key,file=/path/to/file.  Note that this restricts
    1930             :  *     the key to be in text format, whereas at its full power, it can be binary
    1931             :  *     content.</li>
    1932             :  * <li>By adding a key_b64= parameter to the filename, to specify a binary key
    1933             :  *     expressed in Base64 encoding, like
    1934             :  *     /vsicrypt/key_b64=th1sl00kslikebase64=,file=/path/to/file.</li>
    1935             :  * <li>By setting the VSICRYPT_KEY configuration option. The key should be in
    1936             :  * text format.</li>
    1937             :  * <li>By setting the VSICRYPT_KEY_B64 configuration option. The key should be
    1938             :  * encoded in Base64.</li>
    1939             :  * <li>By using the VSISetCryptKey() C function.</li>
    1940             :  * </ul>
    1941             :  *
    1942             :  * When creating a file, if key=GENERATE_IT or VSICRYPT_KEY=GENERATE_IT is
    1943             :  * passed, the encryption key will be generated from the pseudo-random number
    1944             :  * generator of the operating system. The key will be displayed on the standard
    1945             :  * error stream in a Base64 form (unless the VSICRYPT_DISPLAY_GENERATED_KEY
    1946             :  * configuration option is set to OFF), and the VSICRYPT_KEY_B64 configuration
    1947             :  * option will also be set with the Base64 form of the key (so that
    1948             :  * CPLGetConfigOption("VSICRYPT_KEY_B64", NULL) can be used to get it back).
    1949             :  *
    1950             :  * The available options are :
    1951             :  * <ul>
    1952             : 
    1953             :  * <li>alg=AES/Blowfish/Camellia/CAST256/DES_EDE2/DES_EDE3/MARS/IDEA/RC5/RC6/Serpent/SHACAL2/SKIPJACK/Twofish/XTEA:
    1954             :  *     to specify the <a href="https://en.wikipedia.org/wiki/Block_cipher">block
    1955             :  *     cipher</a> algorithm.  The default is AES.  Only used on
    1956             :  *     creation. Ignored otherwise.  Note: depending on how GDAL is build, if
    1957             :  *     linked against the DLL version of libcrypto++, only a subset of those
    1958             :  *     algorithms will be available, namely AES, DES_EDE2, DES_EDE3 and
    1959             :  *     SKIPJACK.  Also available as VSICRYPT_ALG configuration option.</li>
    1960             :  * <li>mode=CBC/CFB/OFB/CTR/CBC_CTS: to specify the
    1961             :  *     <a href="https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation">
    1962             :  *       block cipher mode of operation</a>.
    1963             :  *     The default is CBC.
    1964             :  *     Only used on creation. Ignored otherwise.
    1965             :  *     Also available as VSICRYPT_MODE configuration option.</li>
    1966             :  * <li>key=text_key: see above.</li>
    1967             :  * <li>key_b64=base64_encoded_key: see above.</li>
    1968             :  * <li>freetext=some_text: to specify a text content that will be written
    1969             :  *     *unencrypted* in the file header, for informational purposes. Default to
    1970             :  *     empty.  Only used on creation. Ignored otherwise.
    1971             :  *     Also available as VSICRYPT_FREETEXT configuration option.</li>
    1972             :  * <li>sector_size=int_value: to specify the size of the "sector", which is the
    1973             :  *     unit chunk of information that is encrypted/decrypted. Default to 512
    1974             :  *     bytes.  The valid values depend on the algorithm and block cipher mode of
    1975             :  *     operation.  Only used on creation. Ignored otherwise.  Also available as
    1976             :  *     VSICRYPT_SECTOR_SIZE configuration option.</li>
    1977             :  * <li>iv=initial_vector_as_text: to specify the Initial Vector. This is an
    1978             :  *     advanced option that should generally *NOT* be used. It is only useful to
    1979             :  *     get completely deterministic output given the plaintext, key and other
    1980             :  *     parameters, which in general *NOT* what you want to do. By default, a
    1981             :  *     random initial vector of the appropriate size will be generated for each
    1982             :  *     new file created.  Only used on creation. Ignored otherwise.  Also
    1983             :  *     available as VSICRYPT_IV configuration option.</li>
    1984             : 
    1985             :  * <li>add_key_check=YES/NO: whether a special value should be encrypted in the
    1986             :  *     header, so as to be quickly able to determine if the decryption key is
    1987             :  *     correct.  Defaults to NO.  Only used on creation. Ignored otherwise.
    1988             :  *     Also available as VSICRYPT_ADD_KEY_CHECK configuration option.</li>
    1989             :  * <li>file=filename. To specify the filename. This must be the last option put
    1990             :  *     in the option list (so as to make it possible to use filenames with comma
    1991             :  *     in them. )
    1992             :  * </ul>
    1993             :  *
    1994             :  * This special file handler can be combined with other virtual filesystems
    1995             :  * handlers, such as /vsizip. For example,
    1996             :  * /vsicrypt//vsicurl/path/to/remote/encrypted/file.tif
    1997             :  *
    1998             :  * Implementation details:
    1999             :  *
    2000             :  * The structure of encrypted files is the following: a header, immediately
    2001             :  * followed by the encrypted payload (by sectors, i.e. chunks of sector_size
    2002             :  * bytes).
    2003             :  *
    2004             :  * The header structure is the following :
    2005             :  * <ol>
    2006             :  * <li>8 bytes. Signature. Fixed value: VSICRYPT.</li>
    2007             :  * <li>UINT16_LE. Header size (including previous signature bytes).</li>
    2008             :  * <li>UINT8. Format major version. Current value: 1.</li>
    2009             :  * <li>UINT8. Format minor version. Current value: 0.</li>
    2010             :  * <li>UINT16. Sector size.</li>
    2011             :  * <li>UINT8. Cipher algorithm. Valid values are: 0 = AES (Rijndael), 1 =
    2012             :  *     Blowfish, 2 = Camellia, 3 = CAST256, 4 = DES_EDE2, 5 = DES_EDE3, 6 =
    2013             :  *     MARS, 7 = IDEA, 8 = RC5, 9 = RC6, 10 = Serpent, 11 = SHACAL2, 12 =
    2014             :  *     SKIPJACK, 13 = Twofish, 14 = XTEA.</li>
    2015             :  * <li>UINT8. Block cipher mode of operation. Valid values are: 0 = CBC, 1 =
    2016             :  *     CFB, 2 = OFB, 3 = CTR, 4 = CBC_CTS.</li>
    2017             :  * <li>UINT8. Size in bytes of the Initial Vector.</li>
    2018             :  * <li>N bytes with the content of the Initial Vector, where N is the value of
    2019             :  *     the previous field.</li>
    2020             :  * <li>UINT16_LE. Size in bytes of the free text.</li>
    2021             :  * <li>N bytes with the content of the free text, where N is the value of the
    2022             :  *     previous field.</li>
    2023             :  * <li>UINT8. Size in bytes of encrypted content (key check), or 0 if key check
    2024             :  *     is absent.</li>
    2025             :  * <li>N bytes with encrypted content (key check), where N is the value of the
    2026             :  *     previous field.</li>
    2027             :  * <li>UINT64_LE. Size of the unencrypted file, in bytes.</li>
    2028             :  * <li>UINT16_LE. Size in bytes of extra content (of unspecified semantics). For
    2029             :  *     v1.0, fixed value of 0</li>
    2030             :  * <li>N bytes with extra content (of unspecified semantics), where N is the
    2031             :  *     value of the previous field.</li>
    2032             :  * </ol>
    2033             :  *
    2034             :  * This design does not provide any means of authentication or integrity check.
    2035             :  *
    2036             :  * Each sector is encrypted/decrypted independently of other sectors.  For that,
    2037             :  * the Initial Vector contained in the header is XOR'ed with the file offset
    2038             :  * (relative to plain text file) of the start of the sector being processed, as
    2039             :  * a 8-byte integer.  More precisely, the first byte of the main IV is XOR'ed
    2040             :  * with the 8 least-significant bits of the sector offset, the second byte of
    2041             :  * the main IV is XOR'ed with the following 8 bits of the sector offset,
    2042             :  * etc... until the 8th byte.
    2043             :  *
    2044             :  * This design could potentially be prone to chosen-plaintext attack, for
    2045             :  * example if the attacker managed to get (part of) an existing encrypted file
    2046             :  * to be encrypted from plaintext he might have selected.
    2047             :  *
    2048             :  * Note: if "hostile" code can explore process content, or attach to it with a
    2049             :  * debugger, it might be relatively easy to retrieve the encryption key.  A GDAL
    2050             :  * plugin could for example get the content of configuration options, or list
    2051             :  * opened datasets and see the key/key_b64 values, so disabling plugin loading
    2052             :  * might be a first step, as well as linking statically GDAL to application
    2053             :  * code.  If plugin loading is enabled or GDAL dynamically linked, using
    2054             :  * VSISetCryptKey() to set the key might make it a bit more complicated to spy
    2055             :  * the key.  But, as said initially, this is in no way a perfect protection.
    2056             :  *
    2057             :  * @since GDAL 2.1.0
    2058             :  */
    2059        1225 : void VSIInstallCryptFileHandler(void)
    2060             : 
    2061             : {
    2062        1225 :     VSIFileManager::InstallHandler(VSICRYPT_PREFIX,
    2063        1225 :                                    new VSICryptFilesystemHandler);
    2064             : 
    2065             : #ifdef VSICRYPT_DRIVER
    2066             :     if (GDALGetDriverByName("VSICRYPT") != nullptr)
    2067             :         return;
    2068             : 
    2069             :     GDALDriver *poDriver = new GDALDriver();
    2070             : 
    2071             :     poDriver->SetDescription("VSICRYPT");
    2072             : #ifdef GDAL_DCAP_RASTER
    2073             :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    2074             :     poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
    2075             : #endif
    2076             :     poDriver->SetMetadataItem(
    2077             :         GDAL_DMD_LONGNAME, CPLSPrintf("Wrapper for %s files", VSICRYPT_PREFIX));
    2078             : 
    2079             :     poDriver->pfnOpen = VSICryptOpen;
    2080             :     poDriver->pfnIdentify = VSICryptIdentify;
    2081             : 
    2082             :     GetGDALDriverManager()->RegisterDriver(poDriver);
    2083             : #endif
    2084        1225 : }
    2085             : 
    2086             : #else /* HAVE_CRYPTOPP */
    2087             : 
    2088             : class VSIDummyCryptFilesystemHandler : public VSIFilesystemHandler
    2089             : {
    2090             :   public:
    2091             :     VSIDummyCryptFilesystemHandler()
    2092             :     {
    2093             :     }
    2094             : 
    2095             :     VSIVirtualHandle *Open(const char * /* pszFilename */,
    2096             :                            const char * /* pszAccess */, bool /* bSetError */,
    2097             :                            CSLConstList /* papszOptions */) override
    2098             :     {
    2099             :         CPLError(CE_Failure, CPLE_NotSupported,
    2100             :                  "%s support not available in this build", VSICRYPT_PREFIX);
    2101             :         return nullptr;
    2102             :     }
    2103             : 
    2104             :     int Stat(const char * /* pszFilename */, VSIStatBufL * /*pStatBuf */,
    2105             :              int /* nFlags */) override
    2106             :     {
    2107             :         CPLError(CE_Failure, CPLE_NotSupported,
    2108             :                  "%s support not available in this build", VSICRYPT_PREFIX);
    2109             :         return -1;
    2110             :     }
    2111             : };
    2112             : 
    2113             : void VSIInstallCryptFileHandler(void)
    2114             : {
    2115             :     VSIFileManager::InstallHandler(VSICRYPT_PREFIX,
    2116             :                                    new VSIDummyCryptFilesystemHandler);
    2117             : }
    2118             : 
    2119             : void VSISetCryptKey(const GByte * /* pabyKey */, int /* nKeySize */)
    2120             : {
    2121             :     // Not supported.
    2122             : }
    2123             : 
    2124             : #endif  // HAVE_CRYPTOPP
    2125             : 
    2126             : // Below is only useful if using as a plugin over GDAL >= 2.0.
    2127             : #ifdef VSICRYPT_AUTOLOAD
    2128             : 
    2129             : CPL_C_START
    2130             : void CPL_DLL GDALRegisterMe();
    2131             : CPL_C_END
    2132             : 
    2133             : void GDALRegisterMe()
    2134             : {
    2135             :     VSIFilesystemHandler *poExistingHandler =
    2136             :         VSIFileManager::GetHandler(VSICRYPT_PREFIX);
    2137             :     if (poExistingHandler == VSIFileManager::GetHandler("."))
    2138             :     {
    2139             :         // In the case where VSICRYPT_PREFIX is just handled by the regular
    2140             :         // handler, install the vsicrypt handler (shouldn't happen)
    2141             :         VSIInstallCryptFileHandler();
    2142             :     }
    2143             :     else
    2144             :     {
    2145             :         // If there's already an installed handler, then check if it is a
    2146             :         // dummy one (should normally be the case) or a real one
    2147             :         CPLErrorReset();
    2148             :         CPLPushErrorHandler(CPLQuietErrorHandler);
    2149             :         VSIStatBufL sStat;
    2150             :         CPL_IGNORE_RET_VAL(VSIStatL(
    2151             :             (CPLString(VSICRYPT_PREFIX) + "i_do_not_exist").c_str(), &sStat));
    2152             :         CPLPopErrorHandler();
    2153             :         if (strstr(CPLGetLastErrorMsg(), "support not available in this build"))
    2154             :         {
    2155             :             // Dummy handler. Register the new one, and delete the old one
    2156             :             VSIInstallCryptFileHandler();
    2157             :             delete poExistingHandler;
    2158             :         }
    2159             :         else
    2160             :         {
    2161             :             CPLDebug("VSICRYPT", "GDAL has already a working %s implementation",
    2162             :                      VSICRYPT_PREFIX);
    2163             :         }
    2164             :         CPLErrorReset();
    2165             :     }
    2166             : }
    2167             : 
    2168             : #endif /* VSICRYPT_AUTOLOAD */

Generated by: LCOV version 1.14