3
3
*/
4
4
package net .snowflake .client .jdbc .cloud .storage ;
5
5
6
- import static java .nio .file .StandardOpenOption .CREATE ;
7
- import static java .nio .file .StandardOpenOption .READ ;
6
+ import net .snowflake .client .core .SnowflakeJdbcInternalApi ;
7
+ import net .snowflake .client .jdbc .MatDesc ;
8
+ import net .snowflake .client .jdbc .cloud .storage .floe .AeadProvider ;
9
+ import net .snowflake .common .core .RemoteStoreFileEncryptionMaterial ;
8
10
11
+ import javax .crypto .BadPaddingException ;
12
+ import javax .crypto .Cipher ;
13
+ import javax .crypto .CipherInputStream ;
14
+ import javax .crypto .IllegalBlockSizeException ;
15
+ import javax .crypto .NoSuchPaddingException ;
16
+ import javax .crypto .SecretKey ;
17
+ import javax .crypto .spec .GCMParameterSpec ;
18
+ import javax .crypto .spec .SecretKeySpec ;
9
19
import java .io .File ;
10
20
import java .io .FileOutputStream ;
11
21
import java .io .IOException ;
12
22
import java .io .InputStream ;
13
23
import java .io .OutputStream ;
14
24
import java .nio .channels .FileChannel ;
15
25
import java .nio .file .Files ;
26
+ import java .security .GeneralSecurityException ;
16
27
import java .security .InvalidAlgorithmParameterException ;
17
28
import java .security .InvalidKeyException ;
18
29
import java .security .NoSuchAlgorithmException ;
19
30
import java .security .SecureRandom ;
20
31
import java .util .Base64 ;
21
- import javax .crypto .BadPaddingException ;
22
- import javax .crypto .Cipher ;
23
- import javax .crypto .CipherInputStream ;
24
- import javax .crypto .IllegalBlockSizeException ;
25
- import javax .crypto .NoSuchPaddingException ;
26
- import javax .crypto .SecretKey ;
27
- import javax .crypto .spec .GCMParameterSpec ;
28
- import javax .crypto .spec .SecretKeySpec ;
29
- import net .snowflake .client .jdbc .MatDesc ;
30
- import net .snowflake .common .core .RemoteStoreFileEncryptionMaterial ;
31
32
32
- class GcmEncryptionProvider {
33
+ import static java .nio .file .StandardOpenOption .CREATE ;
34
+ import static java .nio .file .StandardOpenOption .READ ;
35
+
36
+ @ SnowflakeJdbcInternalApi
37
+ public class GcmEncryptionProvider implements AeadProvider {
33
38
private static final int TAG_LENGTH_IN_BITS = 128 ;
34
39
private static final int IV_LENGTH_IN_BYTES = 12 ;
35
40
private static final String AES = "AES" ;
36
- private static final String FILE_CIPHER = "AES/GCM/NoPadding" ;
37
- private static final String KEY_CIPHER = "AES/GCM/NoPadding" ;
41
+ private static final String JCE_CIPHER_NAME = "AES/GCM/NoPadding" ;
38
42
private static final int BUFFER_SIZE = 8 * 1024 * 1024 ; // 2 MB
39
43
private static final ThreadLocal <SecureRandom > random =
40
44
ThreadLocal .withInitial (SecureRandom ::new );
@@ -85,7 +89,7 @@ private static byte[] encryptKey(byte[] kekBytes, byte[] keyBytes, byte[] keyIvD
85
89
BadPaddingException , NoSuchPaddingException , NoSuchAlgorithmException {
86
90
SecretKey kek = new SecretKeySpec (kekBytes , 0 , kekBytes .length , AES );
87
91
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_IN_BITS , keyIvData );
88
- Cipher keyCipher = Cipher .getInstance (KEY_CIPHER );
92
+ Cipher keyCipher = Cipher .getInstance (JCE_CIPHER_NAME );
89
93
keyCipher .init (Cipher .ENCRYPT_MODE , kek , gcmParameterSpec );
90
94
if (aad != null ) {
91
95
keyCipher .updateAAD (aad );
@@ -99,7 +103,7 @@ private static CipherInputStream encryptContent(
99
103
NoSuchAlgorithmException {
100
104
SecretKey fileKey = new SecretKeySpec (keyBytes , 0 , keyBytes .length , AES );
101
105
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_IN_BITS , dataIvBytes );
102
- Cipher fileCipher = Cipher .getInstance (FILE_CIPHER );
106
+ Cipher fileCipher = Cipher .getInstance (JCE_CIPHER_NAME );
103
107
fileCipher .init (Cipher .ENCRYPT_MODE , fileKey , gcmParameterSpec );
104
108
if (aad != null ) {
105
109
fileCipher .updateAAD (aad );
@@ -172,7 +176,7 @@ private static CipherInputStream decryptContentFromStream(
172
176
NoSuchAlgorithmException {
173
177
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_IN_BITS , ivBytes );
174
178
SecretKey fileKey = new SecretKeySpec (fileKeyBytes , AES );
175
- Cipher fileCipher = Cipher .getInstance (FILE_CIPHER );
179
+ Cipher fileCipher = Cipher .getInstance (JCE_CIPHER_NAME );
176
180
fileCipher .init (Cipher .DECRYPT_MODE , fileKey , gcmParameterSpec );
177
181
if (aad != null ) {
178
182
fileCipher .updateAAD (aad );
@@ -187,7 +191,7 @@ private static void decryptContentFromFile(
187
191
SecretKey fileKey = new SecretKeySpec (fileKeyBytes , AES );
188
192
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_IN_BITS , cekIvBytes );
189
193
byte [] buffer = new byte [BUFFER_SIZE ];
190
- Cipher fileCipher = Cipher .getInstance (FILE_CIPHER );
194
+ Cipher fileCipher = Cipher .getInstance (JCE_CIPHER_NAME );
191
195
fileCipher .init (Cipher .DECRYPT_MODE , fileKey , gcmParameterSpec );
192
196
if (aad != null ) {
193
197
fileCipher .updateAAD (aad );
@@ -215,11 +219,34 @@ private static byte[] decryptKey(byte[] kekBytes, byte[] ivBytes, byte[] keyByte
215
219
BadPaddingException , NoSuchPaddingException , NoSuchAlgorithmException {
216
220
SecretKey kek = new SecretKeySpec (kekBytes , 0 , kekBytes .length , AES );
217
221
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_IN_BITS , ivBytes );
218
- Cipher keyCipher = Cipher .getInstance (KEY_CIPHER );
222
+ Cipher keyCipher = Cipher .getInstance (JCE_CIPHER_NAME );
219
223
keyCipher .init (Cipher .DECRYPT_MODE , kek , gcmParameterSpec );
220
224
if (aad != null ) {
221
225
keyCipher .updateAAD (aad );
222
226
}
223
227
return keyCipher .doFinal (keyBytes );
224
228
}
229
+
230
+ // TODO refactor to reuse cipher (consider thread safety vs performance)
231
+ @ Override
232
+ public byte [] encrypt (SecretKey key , byte [] iv , byte [] aad , byte [] plaintext ) throws GeneralSecurityException {
233
+ GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_IN_BITS , iv );
234
+ Cipher keyCipher = Cipher .getInstance (JCE_CIPHER_NAME );
235
+ keyCipher .init (Cipher .ENCRYPT_MODE , key , gcmParameterSpec );
236
+ if (aad != null ) {
237
+ keyCipher .updateAAD (aad );
238
+ }
239
+ return keyCipher .doFinal (plaintext );
240
+ }
241
+
242
+ @ Override
243
+ public byte [] decrypt (SecretKey key , byte [] iv , byte [] aad , byte [] ciphertext ) throws GeneralSecurityException {
244
+ GCMParameterSpec gcmParameterSpec = new GCMParameterSpec (TAG_LENGTH_IN_BITS , iv );
245
+ Cipher keyCipher = Cipher .getInstance (JCE_CIPHER_NAME );
246
+ keyCipher .init (Cipher .DECRYPT_MODE , key , gcmParameterSpec );
247
+ if (aad != null ) {
248
+ keyCipher .updateAAD (aad );
249
+ }
250
+ return keyCipher .doFinal (ciphertext );
251
+ }
225
252
}
0 commit comments