changeset 75:ac596874d997

fix client side encryption
author Alain Mazy <am@osimis.io>
date Tue, 30 Aug 2022 14:59:58 +0200
parents a25b4140e7e4
children dee640a31111 80792bb9600e
files Common/EncryptionHelpers.cpp Dockerfile NEWS
diffstat 3 files changed, 62 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/Common/EncryptionHelpers.cpp	Tue Feb 15 06:01:47 2022 +0100
+++ b/Common/EncryptionHelpers.cpp	Tue Aug 30 14:59:58 2022 +0200
@@ -26,6 +26,7 @@
 #include <cryptopp/cryptlib.h>
 #include <cryptopp/modes.h>
 #include <cryptopp/hex.h>
+#include <cryptopp/base64.h>
 #include <cryptopp/gcm.h>
 #include <cryptopp/files.h>
 #include <cryptopp/filters.h>
@@ -73,10 +74,12 @@
   try
   {
     FileSource fs(path.c_str(), true,
-                  new HexDecoder(
+                  new Base64Decoder(
                     new ArraySink(key.begin(), key.size())
                     )
                   );
+
+    // std::cout << "ReadKey " << ToHexString(key) << std::endl;
   }
   catch (CryptoPP::Exception& ex)
   {
@@ -259,20 +262,26 @@
 
 void EncryptionHelpers::EncryptInternal(std::string& output, const char* data, size_t size, const CryptoPP::SecByteBlock& masterKey)
 {
+  // std::cout << "EncryptInternal" << std::endl;
+  // std::cout << "masterKey " << ToHexString(masterKey) << std::endl;
+
   SecByteBlock iv(IV_SIZE);
   randomGenerator_.GenerateBlock(iv, iv.size());  // with GCM, the iv is supposed to be a nonce (not a random number).  However, since each dataKey is used only once, we consider a random number is fine.
 
   SecByteBlock dataKey;
   GenerateKey(dataKey);
 
-//  std::cout << ToHexString(dataKey) << std::endl;
-//  std::cout << ToHexString(iv) << std::endl;
+  // std::cout << "dataKey " << ToHexString(dataKey) << std::endl;
+  // std::cout << "iv " << ToHexString(iv) << std::endl;
   std::string encryptedDataKey;
   std::string encryptedIv;
 
   EncryptPrefixSecBlock(encryptedIv, iv, masterKey);
   EncryptPrefixSecBlock(encryptedDataKey, dataKey, masterKey);
 
+  // std::cout << "encryptedIv " << ToHexString(encryptedIv) << std::endl;
+  // std::cout << "encryptedDataKey " << ToHexString(encryptedDataKey) << std::endl;
+
   std::string prefix = HEADER_VERSION + encryptionMasterKeyId_ + encryptedIv + encryptedDataKey;
 
   try
@@ -309,21 +318,30 @@
 
 void EncryptionHelpers::DecryptInternal(char* output, const char* data, size_t size, const CryptoPP::SecByteBlock& masterKey)
 {
+  // std::cout << "DecryptInternal" << std::endl;
+  // std::cout << "masterKey " << ToHexString(masterKey) << std::endl;
+
   size_t prefixSize = HEADER_VERSION_SIZE + MASTER_KEY_ID_SIZE + IV_SIZE + AES_KEY_SIZE;
 
   std::string prefix = std::string(data, prefixSize);
   std::string mac = std::string(data + size - INTEGRITY_CHECK_TAG_SIZE, INTEGRITY_CHECK_TAG_SIZE);
 
+  // std::cout << "prefix " << ToHexString(prefix) << std::endl;
+  // std::cout << "mac " << ToHexString(mac) << std::endl;
+
   std::string encryptedIv = prefix.substr(HEADER_VERSION_SIZE + MASTER_KEY_ID_SIZE, IV_SIZE);
   std::string encryptedDataKey = prefix.substr(HEADER_VERSION_SIZE + MASTER_KEY_ID_SIZE + IV_SIZE, AES_KEY_SIZE);
 
+  // std::cout << "encryptedIv " << ToHexString(encryptedIv) << std::endl;
+  // std::cout << "encryptedDataKey " << ToHexString(encryptedDataKey) << std::endl;
+
   SecByteBlock dataKey;
   SecByteBlock iv;
 
   DecryptPrefixSecBlock(iv, encryptedIv, masterKey);
   DecryptPrefixSecBlock(dataKey, encryptedDataKey, masterKey);
-//  std::cout << ToHexString(dataKey) << std::endl;
-//  std::cout << ToHexString(iv) << std::endl;
+  // std::cout << "dataKey " << ToHexString(dataKey) << std::endl;
+  // std::cout << "iv " << ToHexString(iv) << std::endl;
 
   GCM<AES>::Decryption d;
   d.SetKeyWithIV(dataKey, dataKey.size(), iv, iv.size());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Dockerfile	Tue Aug 30 14:59:58 2022 +0200
@@ -0,0 +1,31 @@
+# This is a dev Dockerfile in case you need to rebuild an osimis/orthanc image with a test
+# version of the s3 plugin
+# docker build -t osimis/orthanc:s3test . 
+
+FROM osimis/orthanc-builder-base:bullseye-20220328-slim-stable as orthanc-builder-base
+
+FROM orthanc-builder-base as build-s3-object-storage
+
+WORKDIR /
+
+WORKDIR /sources
+
+# (framework version used to build the cloud storage plugins)
+RUN hg clone https://hg.orthanc-server.com/orthanc/ -r "Orthanc-1.10.1" 
+
+RUN mkdir orthanc-object-storage
+
+COPY . /sources/orthanc-object-storage
+
+
+RUN mkdir -p /build/cloud-storage/aws
+WORKDIR /build/cloud-storage/aws
+RUN cmake -DCMAKE_BUILD_TYPE:STRING=Release -DUSE_VCPKG_PACKAGES=OFF -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=/sources/orthanc/OrthancFramework/Sources /sources/orthanc-object-storage/Aws/
+RUN make -j 8
+
+
+FROM osimis/orthanc:22.7.0
+
+COPY --from=build-s3-object-storage /build/cloud-storage/aws/libOrthancAwsS3Storage.so /usr/share/orthanc/plugins-available/
+
+RUN chmod +x /usr/share/orthanc/plugins-available/*
\ No newline at end of file
--- a/NEWS	Tue Feb 15 06:01:47 2022 +0100
+++ b/NEWS	Tue Aug 30 14:59:58 2022 +0200
@@ -1,6 +1,12 @@
-Pending changes in the mainline
-===============================
+2022-08-30 - v 2.0.0
+====================
 
+* AWS, Google & Azure: BREAKING CHANGE with client-side encryption:
+  Fixed reading the master key.  Although the documentation stated that the master key had to be
+  encoded in Base64, the master key was interpreted as an Hex string.  All non hex characters were
+  ignored and could even end up in a non-deterministic master key (see details in https://groups.google.com/g/orthanc-users/c/FKmq9EuvQkU/m/gbz_bSuwBwAJ).
+  The plugin v 2.0.0 won't be able to read data encrypted with v 1.3.3.  You'll have to start a new Orthanc instance
+  and transfer all data from old to new Orthanc.
 * AWS: added the content MD5 in the request when writing.  This adds integrity check and enables some feature on AWS side
   like https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock-overview.html