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