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