Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java
41161 views
1
/*
2
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
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
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package com.sun.crypto.provider;
27
28
import sun.nio.ch.DirectBuffer;
29
import sun.security.util.ArrayUtil;
30
31
import javax.crypto.AEADBadTagException;
32
import javax.crypto.IllegalBlockSizeException;
33
import javax.crypto.ShortBufferException;
34
import java.io.ByteArrayOutputStream;
35
import java.io.IOException;
36
import java.nio.ByteBuffer;
37
import java.security.InvalidAlgorithmParameterException;
38
import java.security.InvalidKeyException;
39
import java.security.ProviderException;
40
41
import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
42
43
44
/**
45
* This class represents ciphers in GaloisCounter (GCM) mode.
46
*
47
* <p>This mode currently should only be used w/ AES cipher.
48
* Although no checking is done, caller should only pass AES
49
* Cipher to the constructor.
50
*
51
* <p>NOTE: Unlike other modes, when used for decryption, this class
52
* will buffer all processed outputs internally and won't return them
53
* until the tag has been successfully verified.
54
*
55
* @since 1.8
56
*/
57
final class GaloisCounterMode extends FeedbackCipher {
58
59
static int DEFAULT_TAG_LEN = AES_BLOCK_SIZE;
60
static int DEFAULT_IV_LEN = 12; // in bytes
61
62
// In NIST SP 800-38D, GCM input size is limited to be no longer
63
// than (2^36 - 32) bytes. Otherwise, the counter will wrap
64
// around and lead to a leak of plaintext.
65
// However, given the current GCM spec requirement that recovered
66
// text can only be returned after successful tag verification,
67
// we are bound by limiting the data size to the size limit of
68
// java byte array, e.g. Integer.MAX_VALUE, since all data
69
// can only be returned by the doFinal(...) call.
70
private static final int MAX_BUF_SIZE = Integer.MAX_VALUE;
71
72
// data size when buffer is divided up to aid in intrinsics
73
private static final int TRIGGERLEN = 65536; // 64k
74
75
// buffer for AAD data; if null, meaning update has been called
76
private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream();
77
private int sizeOfAAD = 0;
78
79
// buffer data for crypto operation
80
private ByteArrayOutputStream ibuffer = null;
81
82
// Original dst buffer if there was an overlap situation
83
private ByteBuffer originalDst = null;
84
85
// in bytes; need to convert to bits (default value 128) when needed
86
private int tagLenBytes = DEFAULT_TAG_LEN;
87
88
// these following 2 fields can only be initialized after init() is
89
// called, e.g. after cipher key k is set, and STAY UNCHANGED
90
private byte[] subkeyH = null;
91
private byte[] preCounterBlock = null;
92
93
private GCTR gctrPAndC = null;
94
private GHASH ghashAllToS = null;
95
96
// length of total data, i.e. len(C)
97
private int processed = 0;
98
99
// additional variables for save/restore calls
100
private byte[] aadBufferSave = null;
101
private int sizeOfAADSave = 0;
102
private byte[] ibufferSave = null;
103
private int processedSave = 0;
104
105
// value must be 16-byte long; used by GCTR and GHASH as well
106
static void increment32(byte[] value) {
107
if (value.length != AES_BLOCK_SIZE) {
108
// should never happen
109
throw new ProviderException("Illegal counter block length");
110
}
111
// start from last byte and only go over 4 bytes, i.e. total 32 bits
112
int n = value.length - 1;
113
while ((n >= value.length - 4) && (++value[n] == 0)) {
114
n--;
115
}
116
}
117
118
private static byte[] getLengthBlock(int ivLenInBytes) {
119
long ivLen = ((long)ivLenInBytes) << 3;
120
byte[] out = new byte[AES_BLOCK_SIZE];
121
out[8] = (byte)(ivLen >>> 56);
122
out[9] = (byte)(ivLen >>> 48);
123
out[10] = (byte)(ivLen >>> 40);
124
out[11] = (byte)(ivLen >>> 32);
125
out[12] = (byte)(ivLen >>> 24);
126
out[13] = (byte)(ivLen >>> 16);
127
out[14] = (byte)(ivLen >>> 8);
128
out[15] = (byte)ivLen;
129
return out;
130
}
131
132
private static byte[] getLengthBlock(int aLenInBytes, int cLenInBytes) {
133
long aLen = ((long)aLenInBytes) << 3;
134
long cLen = ((long)cLenInBytes) << 3;
135
byte[] out = new byte[AES_BLOCK_SIZE];
136
out[0] = (byte)(aLen >>> 56);
137
out[1] = (byte)(aLen >>> 48);
138
out[2] = (byte)(aLen >>> 40);
139
out[3] = (byte)(aLen >>> 32);
140
out[4] = (byte)(aLen >>> 24);
141
out[5] = (byte)(aLen >>> 16);
142
out[6] = (byte)(aLen >>> 8);
143
out[7] = (byte)aLen;
144
out[8] = (byte)(cLen >>> 56);
145
out[9] = (byte)(cLen >>> 48);
146
out[10] = (byte)(cLen >>> 40);
147
out[11] = (byte)(cLen >>> 32);
148
out[12] = (byte)(cLen >>> 24);
149
out[13] = (byte)(cLen >>> 16);
150
out[14] = (byte)(cLen >>> 8);
151
out[15] = (byte)cLen;
152
return out;
153
}
154
155
private static byte[] expandToOneBlock(byte[] in, int inOfs, int len) {
156
if (len > AES_BLOCK_SIZE) {
157
throw new ProviderException("input " + len + " too long");
158
}
159
if (len == AES_BLOCK_SIZE && inOfs == 0) {
160
return in;
161
} else {
162
byte[] paddedIn = new byte[AES_BLOCK_SIZE];
163
System.arraycopy(in, inOfs, paddedIn, 0, len);
164
return paddedIn;
165
}
166
}
167
168
private static byte[] getJ0(byte[] iv, byte[] subkeyH) {
169
byte[] j0;
170
if (iv.length == 12) { // 96 bits
171
j0 = expandToOneBlock(iv, 0, iv.length);
172
j0[AES_BLOCK_SIZE - 1] = 1;
173
} else {
174
GHASH g = new GHASH(subkeyH);
175
int lastLen = iv.length % AES_BLOCK_SIZE;
176
if (lastLen != 0) {
177
g.update(iv, 0, iv.length - lastLen);
178
byte[] padded =
179
expandToOneBlock(iv, iv.length - lastLen, lastLen);
180
g.update(padded);
181
} else {
182
g.update(iv);
183
}
184
byte[] lengthBlock = getLengthBlock(iv.length);
185
g.update(lengthBlock);
186
j0 = g.digest();
187
}
188
return j0;
189
}
190
191
/**
192
* Calculate if the given data lengths and the already processed data
193
* exceeds the maximum allowed processed data by GCM.
194
* @param lengths lengths of unprocessed data.
195
*/
196
private void checkDataLength(int ... lengths) {
197
int max = MAX_BUF_SIZE;
198
for (int len : lengths) {
199
max = Math.subtractExact(max, len);
200
}
201
if (processed > max) {
202
throw new ProviderException("SunJCE provider only supports " +
203
"input size up to " + MAX_BUF_SIZE + " bytes");
204
}
205
}
206
207
GaloisCounterMode(SymmetricCipher embeddedCipher) {
208
super(embeddedCipher);
209
aadBuffer = new ByteArrayOutputStream();
210
}
211
212
/**
213
* Gets the name of the feedback mechanism
214
*
215
* @return the name of the feedback mechanism
216
*/
217
String getFeedback() {
218
return "GCM";
219
}
220
221
/**
222
* Resets the cipher object to its original state.
223
* This is used when doFinal is called in the Cipher class, so that the
224
* cipher can be reused (with its original key and iv).
225
*/
226
void reset() {
227
if (aadBuffer == null) {
228
aadBuffer = new ByteArrayOutputStream();
229
} else {
230
aadBuffer.reset();
231
}
232
if (gctrPAndC != null) gctrPAndC.reset();
233
if (ghashAllToS != null) ghashAllToS.reset();
234
processed = 0;
235
sizeOfAAD = 0;
236
if (ibuffer != null) {
237
ibuffer.reset();
238
}
239
}
240
241
/**
242
* Save the current content of this cipher.
243
*/
244
void save() {
245
processedSave = processed;
246
sizeOfAADSave = sizeOfAAD;
247
aadBufferSave =
248
((aadBuffer == null || aadBuffer.size() == 0)?
249
null : aadBuffer.toByteArray());
250
if (gctrPAndC != null) gctrPAndC.save();
251
if (ghashAllToS != null) ghashAllToS.save();
252
if (ibuffer != null) {
253
ibufferSave = ibuffer.toByteArray();
254
}
255
}
256
257
/**
258
* Restores the content of this cipher to the previous saved one.
259
*/
260
void restore() {
261
processed = processedSave;
262
sizeOfAAD = sizeOfAADSave;
263
if (aadBuffer != null) {
264
aadBuffer.reset();
265
if (aadBufferSave != null) {
266
aadBuffer.write(aadBufferSave, 0, aadBufferSave.length);
267
}
268
}
269
if (gctrPAndC != null) gctrPAndC.restore();
270
if (ghashAllToS != null) ghashAllToS.restore();
271
if (ibuffer != null) {
272
ibuffer.reset();
273
ibuffer.write(ibufferSave, 0, ibufferSave.length);
274
}
275
}
276
277
/**
278
* Initializes the cipher in the specified mode with the given key
279
* and iv.
280
*
281
* @param decrypting flag indicating encryption or decryption
282
* @param algorithm the algorithm name
283
* @param key the key
284
* @param iv the iv
285
* @exception InvalidKeyException if the given key is inappropriate for
286
* initializing this cipher
287
*/
288
@Override
289
void init(boolean decrypting, String algorithm, byte[] key, byte[] iv)
290
throws InvalidKeyException, InvalidAlgorithmParameterException {
291
init(decrypting, algorithm, key, iv, DEFAULT_TAG_LEN);
292
}
293
294
/**
295
* Initializes the cipher in the specified mode with the given key
296
* and iv.
297
*
298
* @param decrypting flag indicating encryption or decryption
299
* @param algorithm the algorithm name
300
* @param keyValue the key
301
* @param ivValue the iv
302
* @param tagLenBytes the length of tag in bytes
303
*
304
* @exception InvalidKeyException if the given key is inappropriate for
305
* initializing this cipher
306
*/
307
void init(boolean decrypting, String algorithm, byte[] keyValue,
308
byte[] ivValue, int tagLenBytes)
309
throws InvalidKeyException, InvalidAlgorithmParameterException {
310
if (keyValue == null) {
311
throw new InvalidKeyException("Internal error");
312
}
313
if (ivValue == null) {
314
throw new InvalidAlgorithmParameterException("Internal error");
315
}
316
if (ivValue.length == 0) {
317
throw new InvalidAlgorithmParameterException("IV is empty");
318
}
319
320
// always encrypt mode for embedded cipher
321
this.embeddedCipher.init(false, algorithm, keyValue);
322
this.subkeyH = new byte[AES_BLOCK_SIZE];
323
this.embeddedCipher.encryptBlock(new byte[AES_BLOCK_SIZE], 0,
324
this.subkeyH, 0);
325
326
this.iv = ivValue.clone();
327
preCounterBlock = getJ0(iv, subkeyH);
328
byte[] j0Plus1 = preCounterBlock.clone();
329
increment32(j0Plus1);
330
gctrPAndC = new GCTR(embeddedCipher, j0Plus1);
331
ghashAllToS = new GHASH(subkeyH);
332
333
this.tagLenBytes = tagLenBytes;
334
if (aadBuffer == null) {
335
aadBuffer = new ByteArrayOutputStream();
336
} else {
337
aadBuffer.reset();
338
}
339
processed = 0;
340
sizeOfAAD = 0;
341
if (decrypting) {
342
ibuffer = new ByteArrayOutputStream();
343
}
344
}
345
346
/**
347
* Continues a multi-part update of the Additional Authentication
348
* Data (AAD), using a subset of the provided buffer. If this
349
* cipher is operating in either GCM or CCM mode, all AAD must be
350
* supplied before beginning operations on the ciphertext (via the
351
* {@code update} and {@code doFinal} methods).
352
* <p>
353
* NOTE: Given most modes do not accept AAD, default impl for this
354
* method throws IllegalStateException.
355
*
356
* @param src the buffer containing the AAD
357
* @param offset the offset in {@code src} where the AAD input starts
358
* @param len the number of AAD bytes
359
*
360
* @throws IllegalStateException if this cipher is in a wrong state
361
* (e.g., has not been initialized), does not accept AAD, or if
362
* operating in either GCM or CCM mode and one of the {@code update}
363
* methods has already been called for the active
364
* encryption/decryption operation
365
* @throws UnsupportedOperationException if this method
366
* has not been overridden by an implementation
367
*
368
* @since 1.8
369
*/
370
void updateAAD(byte[] src, int offset, int len) {
371
if (aadBuffer != null) {
372
aadBuffer.write(src, offset, len);
373
} else {
374
// update has already been called
375
throw new IllegalStateException
376
("Update has been called; no more AAD data");
377
}
378
}
379
380
// Feed the AAD data to GHASH, pad if necessary
381
void processAAD() {
382
if (aadBuffer != null) {
383
if (aadBuffer.size() > 0) {
384
byte[] aad = aadBuffer.toByteArray();
385
sizeOfAAD = aad.length;
386
387
int lastLen = aad.length % AES_BLOCK_SIZE;
388
if (lastLen != 0) {
389
ghashAllToS.update(aad, 0, aad.length - lastLen);
390
byte[] padded = expandToOneBlock(aad, aad.length - lastLen,
391
lastLen);
392
ghashAllToS.update(padded);
393
} else {
394
ghashAllToS.update(aad);
395
}
396
}
397
aadBuffer = null;
398
}
399
}
400
401
// Utility to process the last block; used by encryptFinal and decryptFinal
402
void doLastBlock(byte[] in, int inOfs, int len, byte[] out, int outOfs,
403
boolean isEncrypt) throws IllegalBlockSizeException {
404
byte[] ct;
405
int ctOfs;
406
int ilen = len; // internal length
407
408
if (isEncrypt) {
409
ct = out;
410
ctOfs = outOfs;
411
} else {
412
ct = in;
413
ctOfs = inOfs;
414
}
415
416
// Divide up larger data sizes to trigger CTR & GHASH intrinsic quicker
417
if (len > TRIGGERLEN) {
418
int i = 0;
419
int tlen; // incremental lengths
420
final int plen = AES_BLOCK_SIZE * 6;
421
// arbitrary formula to aid intrinsic without reaching buffer end
422
final int count = len / 1024;
423
424
while (count > i) {
425
tlen = gctrPAndC.update(in, inOfs, plen, out, outOfs);
426
ghashAllToS.update(ct, ctOfs, tlen);
427
inOfs += tlen;
428
outOfs += tlen;
429
ctOfs += tlen;
430
i++;
431
}
432
ilen -= count * plen;
433
processed += count * plen;
434
}
435
436
gctrPAndC.doFinal(in, inOfs, ilen, out, outOfs);
437
processed += ilen;
438
439
int lastLen = ilen % AES_BLOCK_SIZE;
440
if (lastLen != 0) {
441
ghashAllToS.update(ct, ctOfs, ilen - lastLen);
442
ghashAllToS.update(
443
expandToOneBlock(ct, (ctOfs + ilen - lastLen), lastLen));
444
} else {
445
ghashAllToS.update(ct, ctOfs, ilen);
446
}
447
}
448
449
// Process en/decryption all the way to the last block. It takes both
450
// For input it takes the ibuffer which is wrapped in 'buffer' and 'src'
451
// from doFinal.
452
void doLastBlock(ByteBuffer buffer, ByteBuffer src, ByteBuffer dst)
453
throws IllegalBlockSizeException {
454
455
if (buffer != null && buffer.remaining() > 0) {
456
// en/decrypt on how much buffer there is in AES_BLOCK_SIZE
457
processed += gctrPAndC.update(buffer, dst);
458
459
// Process the remainder in the buffer
460
if (buffer.remaining() > 0) {
461
// Copy the remainder of the buffer into the extra block
462
byte[] block = new byte[AES_BLOCK_SIZE];
463
int over = buffer.remaining();
464
int len = over; // how much is processed by in the extra block
465
buffer.get(block, 0, over);
466
467
// if src is empty, update the final block and wait for later
468
// to finalize operation
469
if (src.remaining() > 0) {
470
// Fill out block with what is in data
471
if (src.remaining() > AES_BLOCK_SIZE - over) {
472
src.get(block, over, AES_BLOCK_SIZE - over);
473
len += AES_BLOCK_SIZE - over;
474
} else {
475
// If the remaining in buffer + data does not fill a
476
// block, complete the ghash operation
477
int l = src.remaining();
478
src.get(block, over, l);
479
len += l;
480
}
481
}
482
gctrPAndC.update(block, 0, AES_BLOCK_SIZE, dst);
483
processed += len;
484
}
485
}
486
487
// en/decrypt whatever remains in src.
488
// If src has been consumed, this will be a no-op
489
processed += gctrPAndC.doFinal(src, dst);
490
}
491
492
/*
493
* This method is for CipherCore to insert the remainder of its buffer
494
* into the ibuffer before a doFinal(ByteBuffer, ByteBuffer) operation
495
*/
496
int encrypt(byte[] in, int inOfs, int len) {
497
if (len > 0) {
498
// store internally until encryptFinal
499
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
500
if (ibuffer == null) {
501
ibuffer = new ByteArrayOutputStream();
502
}
503
ibuffer.write(in, inOfs, len);
504
}
505
return len;
506
}
507
508
/**
509
* Performs encryption operation.
510
*
511
* <p>The input plain text <code>in</code>, starting at <code>inOfs</code>
512
* and ending at <code>(inOfs + len - 1)</code>, is encrypted. The result
513
* is stored in <code>out</code>, starting at <code>outOfs</code>.
514
*
515
* @param in the buffer with the input data to be encrypted
516
* @param inOfs the offset in <code>in</code>
517
* @param inLen the length of the input data
518
* @param out the buffer for the result
519
* @param outOfs the offset in <code>out</code>
520
* @return the number of bytes placed into the <code>out</code> buffer
521
*/
522
int encrypt(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) {
523
checkDataLength(inLen, getBufferedLength());
524
ArrayUtil.nullAndBoundsCheck(in, inOfs, inLen);
525
ArrayUtil.nullAndBoundsCheck(out, outOfs, inLen);
526
527
processAAD();
528
// 'inLen' stores the length to use with buffer 'in'.
529
// 'len' stores the length returned by the method.
530
int len = inLen;
531
532
// if there is enough data in the ibuffer and 'in', encrypt it.
533
if (ibuffer != null && ibuffer.size() > 0) {
534
byte[] buffer = ibuffer.toByteArray();
535
// number of bytes not filling a block
536
int remainder = ibuffer.size() % blockSize;
537
// number of bytes along block boundary
538
int blen = ibuffer.size() - remainder;
539
540
// If there is enough bytes in ibuffer for a block or more,
541
// encrypt that first.
542
if (blen > 0) {
543
encryptBlocks(buffer, 0, blen, out, outOfs);
544
outOfs += blen;
545
}
546
547
// blen is now the offset for 'buffer'
548
549
// Construct and encrypt a block if there is enough 'buffer' and
550
// 'in' to make one
551
if ((inLen + remainder) >= blockSize) {
552
byte[] block = new byte[blockSize];
553
554
System.arraycopy(buffer, blen, block, 0, remainder);
555
int inLenUsed = blockSize - remainder;
556
System.arraycopy(in, inOfs, block, remainder, inLenUsed);
557
558
encryptBlocks(block, 0, blockSize, out, outOfs);
559
inOfs += inLenUsed;
560
inLen -= inLenUsed;
561
len += (blockSize - inLenUsed);
562
outOfs += blockSize;
563
ibuffer.reset();
564
// Code below will write the remainder from 'in' to ibuffer
565
} else if (remainder > 0) {
566
// If a block or more was encrypted from 'buffer' only, but the
567
// rest of 'buffer' with 'in' could not construct a block, then
568
// put the rest of 'buffer' back into ibuffer.
569
ibuffer.reset();
570
ibuffer.write(buffer, blen, remainder);
571
// Code below will write the remainder from 'in' to ibuffer
572
}
573
// If blen == 0 and there was not enough to construct a block
574
// from 'buffer' and 'in', then let the below code append 'in' to
575
// the ibuffer.
576
}
577
578
// Write any remaining bytes outside the blockSize into ibuffer.
579
int remainder = inLen % blockSize;
580
if (remainder > 0) {
581
if (ibuffer == null) {
582
ibuffer = new ByteArrayOutputStream(inLen % blockSize);
583
}
584
len -= remainder;
585
inLen -= remainder;
586
// remainder offset is based on original buffer length
587
ibuffer.write(in, inOfs + inLen, remainder);
588
}
589
590
// Encrypt the remaining blocks inside of 'in'
591
if (inLen > 0) {
592
encryptBlocks(in, inOfs, inLen, out, outOfs);
593
}
594
595
return len;
596
}
597
598
void encryptBlocks(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
599
gctrPAndC.update(in, inOfs, len, out, outOfs);
600
processed += len;
601
ghashAllToS.update(out, outOfs, len);
602
}
603
604
/**
605
* Performs encryption operation for the last time.
606
*
607
* @param in the input buffer with the data to be encrypted
608
* @param inOfs the offset in <code>in</code>
609
* @param len the length of the input data
610
* @param out the buffer for the encryption result
611
* @param outOfs the offset in <code>out</code>
612
* @return the number of bytes placed into the <code>out</code> buffer
613
*/
614
int encryptFinal(byte[] in, int inOfs, int len, byte[] out, int outOfs)
615
throws IllegalBlockSizeException, ShortBufferException {
616
checkDataLength(len, getBufferedLength(), tagLenBytes);
617
618
try {
619
ArrayUtil.nullAndBoundsCheck(out, outOfs,
620
(len + tagLenBytes));
621
} catch (ArrayIndexOutOfBoundsException aiobe) {
622
throw new ShortBufferException("Output buffer too small");
623
}
624
625
processAAD();
626
if (len > 0) {
627
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
628
629
doLastBlock(in, inOfs, len, out, outOfs, true);
630
}
631
632
byte[] block = getLengthBlock(sizeOfAAD, processed);
633
ghashAllToS.update(block);
634
block = ghashAllToS.digest();
635
GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock);
636
gctrForSToTag.doFinal(block, 0, tagLenBytes, block, 0);
637
638
System.arraycopy(block, 0, out, (outOfs + len), tagLenBytes);
639
return (len + tagLenBytes);
640
}
641
642
int encryptFinal(ByteBuffer src, ByteBuffer dst)
643
throws IllegalBlockSizeException, ShortBufferException {
644
dst = overlapDetection(src, dst);
645
int len = src.remaining();
646
len += getBufferedLength();
647
648
// 'len' includes ibuffer data
649
checkDataLength(len, tagLenBytes);
650
dst.mark();
651
if (dst.remaining() < len + tagLenBytes) {
652
throw new ShortBufferException("Output buffer too small");
653
}
654
655
processAAD();
656
if (len > 0) {
657
doLastBlock((ibuffer == null || ibuffer.size() == 0) ?
658
null : ByteBuffer.wrap(ibuffer.toByteArray()), src, dst);
659
dst.reset();
660
ghashAllToS.doLastBlock(dst, len);
661
}
662
663
byte[] block = getLengthBlock(sizeOfAAD, processed);
664
ghashAllToS.update(block);
665
block = ghashAllToS.digest();
666
GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock);
667
gctrForSToTag.doFinal(block, 0, tagLenBytes, block, 0);
668
dst.put(block, 0, tagLenBytes);
669
restoreDst(dst);
670
671
return (len + tagLenBytes);
672
}
673
674
/**
675
* Performs decryption operation.
676
*
677
* <p>The input cipher text <code>in</code>, starting at
678
* <code>inOfs</code> and ending at <code>(inOfs + len - 1)</code>,
679
* is decrypted. The result is stored in <code>out</code>, starting at
680
* <code>outOfs</code>.
681
*
682
* @param in the buffer with the input data to be decrypted
683
* @param inOfs the offset in <code>in</code>
684
* @param len the length of the input data
685
* @param out the buffer for the result
686
* @param outOfs the offset in <code>out</code>
687
* @exception ProviderException if <code>len</code> is not
688
* a multiple of the block size
689
* @return the number of bytes placed into the <code>out</code> buffer
690
*/
691
int decrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
692
processAAD();
693
694
if (len > 0) {
695
// store internally until decryptFinal is called because
696
// spec mentioned that only return recovered data after tag
697
// is successfully verified
698
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
699
ibuffer.write(in, inOfs, len);
700
}
701
return 0;
702
}
703
704
int decrypt(ByteBuffer src, ByteBuffer dst) {
705
if (src.remaining() > 0) {
706
byte[] b = new byte[src.remaining()];
707
src.get(b);
708
try {
709
ibuffer.write(b);
710
} catch (IOException e) {
711
throw new ProviderException("Unable to add remaining input to the buffer", e);
712
}
713
}
714
return 0;
715
}
716
717
/**
718
* Performs decryption operation for the last time.
719
*
720
* <p>NOTE: For cipher feedback modes which does not perform
721
* special handling for the last few blocks, this is essentially
722
* the same as <code>encrypt(...)</code>. Given most modes do
723
* not do special handling, the default impl for this method is
724
* to simply call <code>decrypt(...)</code>.
725
*
726
* @param in the input buffer with the data to be decrypted
727
* @param inOfs the offset in <code>cipher</code>
728
* @param len the length of the input data
729
* @param out the buffer for the decryption result
730
* @param outOfs the offset in <code>plain</code>
731
* @return the number of bytes placed into the <code>out</code> buffer
732
*/
733
int decryptFinal(byte[] in, int inOfs, int len,
734
byte[] out, int outOfs)
735
throws IllegalBlockSizeException, AEADBadTagException,
736
ShortBufferException {
737
if (len < tagLenBytes) {
738
throw new AEADBadTagException("Input too short - need tag");
739
}
740
741
// do this check here can also catch the potential integer overflow
742
// scenario for the subsequent output buffer capacity check.
743
checkDataLength(getBufferedLength(), (len - tagLenBytes));
744
745
try {
746
ArrayUtil.nullAndBoundsCheck(out, outOfs,
747
(getBufferedLength() + len) - tagLenBytes);
748
} catch (ArrayIndexOutOfBoundsException aiobe) {
749
throw new ShortBufferException("Output buffer too small");
750
}
751
752
processAAD();
753
754
ArrayUtil.nullAndBoundsCheck(in, inOfs, len);
755
756
// get the trailing tag bytes from 'in'
757
byte[] tag = new byte[tagLenBytes];
758
System.arraycopy(in, inOfs + len - tagLenBytes, tag, 0, tagLenBytes);
759
len -= tagLenBytes;
760
761
// If decryption is in-place or there is buffered "ibuffer" data, copy
762
// the "in" byte array into the ibuffer before proceeding.
763
if (in == out || getBufferedLength() > 0) {
764
if (len > 0) {
765
ibuffer.write(in, inOfs, len);
766
}
767
768
// refresh 'in' to all buffered-up bytes
769
in = ibuffer.toByteArray();
770
inOfs = 0;
771
len = in.length;
772
ibuffer.reset();
773
}
774
775
if (len > 0) {
776
doLastBlock(in, inOfs, len, out, outOfs, false);
777
}
778
779
byte[] block = getLengthBlock(sizeOfAAD, processed);
780
ghashAllToS.update(block);
781
block = ghashAllToS.digest();
782
GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock);
783
gctrForSToTag.doFinal(block, 0, tagLenBytes, block, 0);
784
785
// check entire authentication tag for time-consistency
786
int mismatch = 0;
787
for (int i = 0; i < tagLenBytes; i++) {
788
mismatch |= tag[i] ^ block[i];
789
}
790
791
if (mismatch != 0) {
792
throw new AEADBadTagException("Tag mismatch!");
793
}
794
795
return len;
796
}
797
798
// Note: In-place operations do not need an intermediary copy because
799
// the GHASH check was performed before the decryption.
800
int decryptFinal(ByteBuffer src, ByteBuffer dst)
801
throws IllegalBlockSizeException, AEADBadTagException,
802
ShortBufferException {
803
804
dst = overlapDetection(src, dst);
805
// Length of the input
806
ByteBuffer tag;
807
ByteBuffer ct = src.duplicate();
808
809
ByteBuffer buffer = ((ibuffer == null || ibuffer.size() == 0) ? null :
810
ByteBuffer.wrap(ibuffer.toByteArray()));
811
int len;
812
813
if (ct.remaining() >= tagLenBytes) {
814
tag = src.duplicate();
815
tag.position(ct.limit() - tagLenBytes);
816
ct.limit(ct.limit() - tagLenBytes);
817
len = ct.remaining();
818
if (buffer != null) {
819
len += buffer.remaining();
820
}
821
} else if (buffer != null && ct.remaining() < tagLenBytes) {
822
// It's unlikely the tag will be between the buffer and data
823
tag = ByteBuffer.allocate(tagLenBytes);
824
int limit = buffer.remaining() - (tagLenBytes - ct.remaining());
825
buffer.mark();
826
buffer.position(limit);
827
// Read from "new" limit to buffer's end
828
tag.put(buffer);
829
// reset buffer to data only
830
buffer.reset();
831
buffer.limit(limit);
832
tag.put(ct);
833
tag.flip();
834
// Limit is how much of the ibuffer has been chopped off.
835
len = buffer.remaining();
836
} else {
837
throw new AEADBadTagException("Input too short - need tag");
838
}
839
840
// 'len' contains the length in ibuffer and src
841
checkDataLength(len);
842
843
if (len > dst.remaining()) {
844
throw new ShortBufferException("Output buffer too small");
845
}
846
847
processAAD();
848
// Set the mark for a later reset. Either it will be zero, or the tag
849
// buffer creation above will have consume some or all of it.
850
ct.mark();
851
852
// If there is data stored in the buffer
853
if (buffer != null && buffer.remaining() > 0) {
854
ghashAllToS.update(buffer, buffer.remaining());
855
// Process the overage
856
if (buffer.remaining() > 0) {
857
// Fill out block between two buffers
858
if (ct.remaining() > 0) {
859
int over = buffer.remaining();
860
byte[] block = new byte[AES_BLOCK_SIZE];
861
// Copy the remainder of the buffer into the extra block
862
buffer.get(block, 0, over);
863
864
// Fill out block with what is in data
865
if (ct.remaining() > AES_BLOCK_SIZE - over) {
866
ct.get(block, over, AES_BLOCK_SIZE - over);
867
ghashAllToS.update(block, 0, AES_BLOCK_SIZE);
868
} else {
869
// If the remaining in buffer + data does not fill a
870
// block, complete the ghash operation
871
int l = ct.remaining();
872
ct.get(block, over, l);
873
ghashAllToS.doLastBlock(ByteBuffer.wrap(block), over + l);
874
}
875
} else {
876
// data is empty, so complete the ghash op with the
877
// remaining buffer
878
ghashAllToS.doLastBlock(buffer, buffer.remaining());
879
}
880
}
881
// Prepare buffer for decryption
882
buffer.flip();
883
}
884
885
if (ct.remaining() > 0) {
886
ghashAllToS.doLastBlock(ct, ct.remaining());
887
}
888
// Prepare buffer for decryption if available
889
ct.reset();
890
891
byte[] block = getLengthBlock(sizeOfAAD, len);
892
ghashAllToS.update(block);
893
block = ghashAllToS.digest();
894
GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock);
895
gctrForSToTag.doFinal(block, 0, tagLenBytes, block, 0);
896
897
// check entire authentication tag for time-consistency
898
int mismatch = 0;
899
for (int i = 0; i < tagLenBytes; i++) {
900
mismatch |= tag.get() ^ block[i];
901
}
902
903
if (mismatch != 0) {
904
throw new AEADBadTagException("Tag mismatch!");
905
}
906
907
// Decrypt the all the input data and put it into dst
908
doLastBlock(buffer, ct, dst);
909
restoreDst(dst);
910
src.position(src.limit());
911
// 'processed' from the gctr decryption operation, not ghash
912
return processed;
913
}
914
915
// return tag length in bytes
916
int getTagLen() {
917
return this.tagLenBytes;
918
}
919
920
int getBufferedLength() {
921
if (ibuffer == null) {
922
return 0;
923
} else {
924
return ibuffer.size();
925
}
926
}
927
928
/**
929
* Check for overlap. If the src and dst buffers are using shared data and
930
* if dst will overwrite src data before src can be processed. If so, make
931
* a copy to put the dst data in.
932
*/
933
ByteBuffer overlapDetection(ByteBuffer src, ByteBuffer dst) {
934
if (src.isDirect() && dst.isDirect()) {
935
DirectBuffer dsrc = (DirectBuffer) src;
936
DirectBuffer ddst = (DirectBuffer) dst;
937
938
// Get the current memory address for the given ByteBuffers
939
long srcaddr = dsrc.address();
940
long dstaddr = ddst.address();
941
942
// Find the lowest attachment that is the base memory address of the
943
// shared memory for the src object
944
while (dsrc.attachment() != null) {
945
srcaddr = ((DirectBuffer) dsrc.attachment()).address();
946
dsrc = (DirectBuffer) dsrc.attachment();
947
}
948
949
// Find the lowest attachment that is the base memory address of the
950
// shared memory for the dst object
951
while (ddst.attachment() != null) {
952
dstaddr = ((DirectBuffer) ddst.attachment()).address();
953
ddst = (DirectBuffer) ddst.attachment();
954
}
955
956
// If the base addresses are not the same, there is no overlap
957
if (srcaddr != dstaddr) {
958
return dst;
959
}
960
// At this point we know these objects share the same memory.
961
// This checks the starting position of the src and dst address for
962
// overlap.
963
// It uses the base address minus the passed object's address to get
964
// the offset from the base address, then add the position() from
965
// the passed object. That gives up the true offset from the base
966
// address. As long as the src side is >= the dst side, we are not
967
// in overlap.
968
if (((DirectBuffer) src).address() - srcaddr + src.position() >=
969
((DirectBuffer) dst).address() - dstaddr + dst.position()) {
970
return dst;
971
}
972
973
} else if (!src.isDirect() && !dst.isDirect()) {
974
if (!src.isReadOnly()) {
975
// If using the heap, check underlying byte[] address.
976
if (src.array() != dst.array()) {
977
return dst;
978
}
979
980
// Position plus arrayOffset() will give us the true offset from
981
// the underlying byte[] address.
982
if (src.position() + src.arrayOffset() >=
983
dst.position() + dst.arrayOffset()) {
984
return dst;
985
}
986
}
987
} else {
988
// buffer types aren't the same
989
return dst;
990
}
991
992
// Create a copy
993
ByteBuffer tmp = dst.duplicate();
994
// We can use a heap buffer for internal use, save on alloc cost
995
ByteBuffer bb = ByteBuffer.allocate(dst.remaining());
996
tmp.limit(dst.limit());
997
tmp.position(dst.position());
998
bb.put(tmp);
999
bb.flip();
1000
originalDst = dst;
1001
return bb;
1002
}
1003
1004
/**
1005
* If originalDst exists, dst is an internal dst buffer, then copy the data
1006
* into the original dst buffer
1007
*/
1008
void restoreDst(ByteBuffer dst) {
1009
if (originalDst == null) {
1010
return;
1011
}
1012
1013
dst.flip();
1014
originalDst.put(dst);
1015
originalDst = null;
1016
}
1017
}
1018
1019