1 /* |
1 /* |
2 * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
57 |
57 |
58 private static final int DEFAULT_TAG_LEN = 128; // same as SunJCE provider |
58 private static final int DEFAULT_TAG_LEN = 128; // same as SunJCE provider |
59 |
59 |
60 // buffer for storing AAD data; if null, meaning buffer content has been |
60 // buffer for storing AAD data; if null, meaning buffer content has been |
61 // supplied to native context |
61 // supplied to native context |
62 private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream(); |
62 private ByteArrayOutputStream aadBuffer; |
63 |
63 |
64 // buffer for storing input in decryption, not used for encryption |
64 // buffer for storing input in decryption, not used for encryption |
65 private ByteArrayOutputStream ibuffer = null; |
65 private ByteArrayOutputStream ibuffer; |
66 |
66 |
67 private int tagLen = DEFAULT_TAG_LEN; |
67 private int tagLen = DEFAULT_TAG_LEN; |
68 |
68 |
69 /* |
69 /* |
70 * variables used for performing the GCM (key+iv) uniqueness check. |
70 * variables used for performing the GCM (key+iv) uniqueness check. |
73 * ENCRYPTION operation. However, checking all past key + iv values |
73 * ENCRYPTION operation. However, checking all past key + iv values |
74 * isn't feasible. Thus, we only do a per-instance check of the |
74 * isn't feasible. Thus, we only do a per-instance check of the |
75 * key + iv values used in previous encryption. |
75 * key + iv values used in previous encryption. |
76 * For decryption operations, no checking is necessary. |
76 * For decryption operations, no checking is necessary. |
77 */ |
77 */ |
78 private boolean requireReinit = false; |
78 private boolean requireReinit; |
79 private byte[] lastEncKey = null; |
79 private byte[] lastEncKey = null; |
80 private byte[] lastEncIv = null; |
80 private byte[] lastEncIv = null; |
81 |
81 |
82 NativeGCMCipher(int fixedKeySize) throws NoSuchAlgorithmException { |
82 NativeGCMCipher(int fixedKeySize) throws NoSuchAlgorithmException { |
83 super(UcryptoMech.CRYPTO_AES_GCM, fixedKeySize); |
83 super(UcryptoMech.CRYPTO_AES_GCM, fixedKeySize); |
84 } |
84 } |
85 |
85 |
86 @Override |
86 @Override |
87 protected void ensureInitialized() { |
87 protected void ensureInitialized() { |
88 if (!initialized) { |
88 if (!initialized) { |
89 if (aadBuffer != null && aadBuffer.size() > 0) { |
89 byte[] aad = null; |
90 init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray()); |
90 if (aadBuffer != null) { |
91 aadBuffer = null; |
91 if (aadBuffer.size() > 0) { |
92 } else { |
92 aad = aadBuffer.toByteArray(); |
93 init(encrypt, keyValue, iv, tagLen, null); |
93 } |
94 } |
94 } |
|
95 init(encrypt, keyValue, iv, tagLen, aad); |
|
96 aadBuffer = null; |
95 if (!initialized) { |
97 if (!initialized) { |
96 throw new UcryptoException("Cannot initialize Cipher"); |
98 throw new UcryptoException("Cannot initialize Cipher"); |
97 } |
99 } |
98 } |
100 } |
99 } |
101 } |
183 opmode != Cipher.WRAP_MODE && |
185 opmode != Cipher.WRAP_MODE && |
184 opmode != Cipher.UNWRAP_MODE) { |
186 opmode != Cipher.UNWRAP_MODE) { |
185 throw new InvalidAlgorithmParameterException |
187 throw new InvalidAlgorithmParameterException |
186 ("Unsupported mode: " + opmode); |
188 ("Unsupported mode: " + opmode); |
187 } |
189 } |
|
190 aadBuffer = new ByteArrayOutputStream(); |
188 boolean doEncrypt = (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE); |
191 boolean doEncrypt = (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE); |
189 byte[] keyBytes = key.getEncoded().clone(); |
192 byte[] keyBytes = key.getEncoded().clone(); |
190 byte[] ivBytes = null; |
193 byte[] ivBytes = null; |
191 if (params != null) { |
194 if (params != null) { |
192 if (!(params instanceof GCMParameterSpec)) { |
195 if (!(params instanceof GCMParameterSpec)) { |
217 throw new InvalidAlgorithmParameterException |
220 throw new InvalidAlgorithmParameterException |
218 ("Cannot reuse iv for GCM encryption"); |
221 ("Cannot reuse iv for GCM encryption"); |
219 } |
222 } |
220 lastEncIv = ivBytes; |
223 lastEncIv = ivBytes; |
221 lastEncKey = keyBytes; |
224 lastEncKey = keyBytes; |
|
225 ibuffer = null; |
222 } else { |
226 } else { |
223 requireReinit = false; |
227 requireReinit = false; |
224 ibuffer = new ByteArrayOutputStream(); |
228 ibuffer = new ByteArrayOutputStream(); |
225 } |
229 } |
226 init(doEncrypt, keyBytes, ivBytes, tagLen, null); |
230 init(doEncrypt, keyBytes, ivBytes, tagLen, null); |
244 } |
248 } |
245 |
249 |
246 // see JCE spec |
250 // see JCE spec |
247 @Override |
251 @Override |
248 protected synchronized byte[] engineUpdate(byte[] in, int inOfs, int inLen) { |
252 protected synchronized byte[] engineUpdate(byte[] in, int inOfs, int inLen) { |
249 if (aadBuffer != null && aadBuffer.size() > 0) { |
253 if (aadBuffer != null) { |
250 // init again with AAD data |
254 if (aadBuffer.size() > 0) { |
251 init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray()); |
255 // init again with AAD data |
|
256 init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray()); |
|
257 } |
252 aadBuffer = null; |
258 aadBuffer = null; |
253 } |
259 } |
254 if (requireReinit) { |
260 if (requireReinit) { |
255 throw new IllegalStateException |
261 throw new IllegalStateException |
256 ("Must use either different key or iv for GCM encryption"); |
262 ("Must use either different key or iv for GCM encryption"); |
272 if (out.length - outOfs < len) { |
278 if (out.length - outOfs < len) { |
273 throw new ShortBufferException("Output buffer must be " + |
279 throw new ShortBufferException("Output buffer must be " + |
274 "(at least) " + len + " bytes long. Got: " + |
280 "(at least) " + len + " bytes long. Got: " + |
275 (out.length - outOfs)); |
281 (out.length - outOfs)); |
276 } |
282 } |
277 if (aadBuffer != null && aadBuffer.size() > 0) { |
283 if (aadBuffer != null) { |
278 // init again with AAD data |
284 if (aadBuffer.size() > 0) { |
279 init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray()); |
285 // init again with AAD data |
|
286 init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray()); |
|
287 } |
280 aadBuffer = null; |
288 aadBuffer = null; |
281 } |
289 } |
282 if (requireReinit) { |
290 if (requireReinit) { |
283 throw new IllegalStateException |
291 throw new IllegalStateException |
284 ("Must use either different key or iv for GCM encryption"); |
292 ("Must use either different key or iv for GCM encryption"); |
372 if (out.length - outOfs < len) { |
380 if (out.length - outOfs < len) { |
373 throw new ShortBufferException("Output buffer must be " |
381 throw new ShortBufferException("Output buffer must be " |
374 + "(at least) " + len + " bytes long. Got: " + |
382 + "(at least) " + len + " bytes long. Got: " + |
375 (out.length - outOfs)); |
383 (out.length - outOfs)); |
376 } |
384 } |
377 if (aadBuffer != null && aadBuffer.size() > 0) { |
385 if (aadBuffer != null) { |
378 // init again with AAD data |
386 if (aadBuffer.size() > 0) { |
379 init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray()); |
387 // init again with AAD data |
|
388 init(encrypt, keyValue, iv, tagLen, aadBuffer.toByteArray()); |
|
389 } |
380 aadBuffer = null; |
390 aadBuffer = null; |
381 } |
391 } |
382 if (requireReinit) { |
392 if (requireReinit) { |
383 throw new IllegalStateException |
393 throw new IllegalStateException |
384 ("Must use either different key or iv for GCM encryption"); |
394 ("Must use either different key or iv for GCM encryption"); |