1
|
1 # README #
|
|
2
|
|
3 Orthanc object-storages plugin for main cloud providers (Google/Azure/AWS)
|
|
4
|
|
5 ## Encryption ##
|
|
6
|
|
7 ### Encryption rationale ###
|
|
8
|
|
9 Although all cloud providers already provide encryption at rest, the plugins provide an optional layer of client-side encryption . It is very important that you understand the scope and benefits of this additional layer of encryption.
|
|
10
|
|
11 Encryption at rest provided by cloud providers basically compares with a file-system disk encryption. If someone has access to the disk, he won't have access to your data without the encryption key.
|
|
12
|
|
13 With cloud encryption at rest only, if someone has access to the "api-key" of your storage or if one of your admin inadvertently make your storage public, PHI will leak.
|
|
14
|
|
15 Once you use client-side encryption, you'll basically store packets of meaningless bytes on the cloud infrastructure. So, if an "api-key" leaks or if the storage is misconfigured, packet of bytes will leak but not PHI.
|
|
16
|
|
17 These packets of bytes might eventually not be considered as Personal Health Information (PHI) anymore and eventually help you meet your local regulations (Please check your local regulations).
|
|
18
|
|
19 However, note that, if you're running entirely in a cloud environment, your decryption keys will still be stored on the cloud infrastructure (VM disks - process RAM) and an attacker could still eventually gain access to this keys. Furthermore, in the scope of the [Cloud Act](https://bitbucket.org/osimis/orthanc-cloud-storages/src/master/UnitTestsSources/EncryptionTests.cpp), the cloud provider might still have the possibility to retrieve your data and encryption key (while it will still be more complex than with standard encryption at rest).
|
|
20
|
|
21 If Orthanc is running in your infrastructure with the Index DB on your infrastructure, and files are store in the cloud, the master keys will remain on your infrastructure only and there's no way the data stored in the cloud could be decrypted outside your infrastructure.
|
|
22
|
|
23
|
|
24 Also note that, although the cloud providers also provide client-side encryption, we, as an open-source project, wanted to provide our own implementation on which you'll have full control and extension capabilities. This also allows us to implement the same logic on all cloud providers.
|
|
25
|
|
26 Our encryption is based on well-known standards (see below). Since it is documented and the source code is open-source, feel-free to have your security expert review it before using it in a production environment.
|
|
27
|
|
28 ### Encryption technical overview ###
|
|
29
|
|
30 Orthanc saves 2 kind of files: DICOM files and JSON summaries of DICOM files. Both files contain PHI.
|
|
31
|
|
32 When configuring the plugin, you'll have to provide a `Master Key` that we can also call `Key Encryption Key` (KEK).
|
|
33
|
|
34 For each file being saved, the plugin will generate a new `Data Encryption Key` (DEK). This DEK, encrypted with the KEK will be pre-pended to the file.
|
|
35
|
|
36 If, at any point, your KEK leaks or you want to rotate your KEKs, you'll be able to use a new one to encrypt new files that are being added and still use the old ones to decrypt data. You could then eventually start a side script to remove usages of the leaked/obsolete KEKs.
|
|
37
|
|
38 To summarize:
|
|
39
|
|
40 - We use (Crypto++)[https://www.cryptopp.com/] to perform all encryptions.
|
|
41 - All keys (KEK and DEK) are AES-256 keys.
|
|
42 - DEKs and IVs are encrypted by KEK using CTR block cipher using a null IV.
|
|
43 - data is encrypted by DEK using GCM block cipher that will also perform integrity check on the whole file.
|
|
44
|
|
45 The format of data stored on disk is therefore the following:
|
|
46 - `VERSION HEADER`: 2 bytes: identify the structure of the following data
|
|
47 - `MASTER KEY ID`: 4 bytes: a numerical ID of the KEK that was used to encrypt the DEK
|
|
48 - `EIV`: 32 bytes: IV used by DEK for data encryption; encrypted by KEK
|
|
49 - `EDEK`: 32 bytes: the DEK encrypted by the KEK.
|
|
50 - `CIPHER TEXT`: variable length: the DICOM/JSON file encrypted by the DEK
|
|
51 - `TAG`: 16 bytes: integrity check performed on the whole encrypted file (including header, master key id, EIV and EDEK)
|
|
52
|
|
53 ### Configuration ###
|
|
54
|
|
55 AES Keys shall be 32 bytes long (256 bits) and encoded in base64. Here's a sample OpenSSL command to generate such a key:
|
|
56
|
|
57 ```
|
|
58 openssl rand -base64 -out /tmp/test.key 32
|
|
59 ```
|
|
60
|
|
61 Each key must have a unique id that is a uint32 number.
|
|
62
|
|
63 Here's a sample configuration file of the `StorageEncryption` section of the plugins:
|
|
64
|
|
65 ```
|
|
66 {
|
|
67 "StorageEncryption" : {
|
|
68 "Enable": true,
|
|
69 "MasterKey": [3, "/path/to/master.key"], // key id - path to the base64 encoded key
|
|
70 "PreviousMasterKeys" : [
|
|
71 [ 1, "/path/to/previous1.key"],
|
|
72 [ 2, "/path/to/previous2.key"]
|
|
73 ],
|
|
74 "MaxConcurrentInputSize" : 1024 // size in MB
|
|
75 }
|
|
76 }
|
|
77 ```
|
|
78
|
|
79 *MaxConcurrentInputSize*: Since the memory used during encryption/decryption can grow up to a bit more than 2 times the input, we want to limit the number of threads doing concurrent processing according to the available memory instead of the number of concurrent threads. Therefore, if you're currently
|
|
80 ingesting small files, you can have a lot of thread working together while, if you're ingesting large files, threads might have to wait before receiving a "slot" to access the encryption module.
|
|
81
|
|
82
|
|
83 ## Google Cloud Storage plugin ##
|
|
84
|
|
85 ### Prerequisites ###
|
|
86
|
|
87 * Install [vcpkg](https://github.com/Microsoft/vcpkg)
|
|
88
|
|
89 ### Compile Google plugin ###
|
|
90
|
|
91 * `./vcpkg install google-cloud-cpp`
|
|
92 * `./vcpkg install cryptopp`
|
|
93 * `hg clone ...`
|
|
94 * `mkdir -p build/google`
|
|
95 * `cd build/google`
|
|
96 * `cmake -DCMAKE_TOOLCHAIN_FILE=[vcpkg root]\scripts\buildsystems\vcpkg.cmake ../../orthanc-cloud-storages/google`
|
|
97
|
|
98 ### Google plugin configuration ###
|
|
99
|
|
100 ```
|
|
101 "GoogleCloudStorage" : {
|
|
102 "ServiceAccountFile": "/.../googleServiceAccountFile.json",
|
|
103 "BucketName": "test-orthanc-storage-plugin"
|
|
104 }
|
|
105
|
|
106 ```
|
|
107
|
|
108 ## Azure Blob Storage plugin ##
|
|
109
|
|
110 ### Prerequisites ###
|
|
111
|
|
112 * Install [vcpkg](https://github.com/Microsoft/vcpkg)
|
|
113
|
|
114 ### Compile Azure plugin ###
|
|
115
|
|
116 * `./vcpkg install cpprestsdk`
|
|
117 * `hg clone ...`
|
|
118 * `mkdir -p build/azure`
|
|
119 * `cd build/azure`
|
|
120 * `cmake -DCMAKE_TOOLCHAIN_FILE=[vcpkg root]\scripts\buildsystems\vcpkg.cmake ../../orthanc-cloud-storages/Azure`
|
|
121
|
|
122 ### Azure plugin configuration ###
|
|
123
|
|
124 ```
|
|
125 "AzureBlobStorage" : {
|
|
126 "ConnectionString": "DefaultEndpointsProtocol=https;AccountName=xxxxxxxxx;AccountKey=yyyyyyyy===;EndpointSuffix=core.windows.net",
|
|
127 "ContainerName" : "test-orthanc-storage-plugin"
|
|
128 }
|
|
129 ```
|
|
130
|
|
131 ## AWS S3 Storage plugin ##
|
|
132
|
|
133 ### Prerequisites ###
|
|
134
|
|
135 * Install [vcpkg](https://github.com/Microsoft/vcpkg)
|
|
136
|
|
137 * compile the AWS C++ SDK
|
|
138
|
|
139 ```
|
|
140
|
|
141 mkdir ~/aws
|
|
142 cd ~/aws
|
|
143 git clone https://github.com/aws/aws-sdk-cpp.git
|
|
144
|
|
145 mkdir -p ~/aws/builds/aws-sdk-cpp
|
|
146 cd ~/aws/builds/aws-sdk-cpp
|
|
147 cmake -DBUILD_ONLY="s3;transfer" ~/aws/aws-sdk-cpp
|
|
148 make -j 4
|
|
149 make install
|
|
150 ```
|
|
151
|
|
152 ### Compile AWS S3 plugin ###
|
|
153
|
|
154 * `./vcpkg install cryptopp`
|
|
155 * `hg clone ...`
|
|
156 * `mkdir -p build/aws`
|
|
157 * `cd build/aws`
|
|
158 * `cmake -DCMAKE_TOOLCHAIN_FILE=[vcpkg root]\scripts\buildsystems\vcpkg.cmake ../../orthanc-cloud-storages/Aws`
|
|
159
|
|
160 ### Azure plugin configuration ###
|
|
161
|
|
162 ```
|
|
163 "AwsS3Storage" : {
|
|
164 "BucketName": "test-orthanc-s3-plugin",
|
|
165 "Region" : "eu-central-1",
|
|
166 "AccessKey" : "AKXXX",
|
|
167 "SecretKey" : "RhYYYY"
|
|
168 }
|
|
169 ```
|