Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/crypto/provider/GaloisCounterMode.java
38922 views
1
/*
2
* Copyright (c) 2013, 2019, 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 java.util.Arrays;
29
import java.io.*;
30
import java.security.*;
31
import javax.crypto.*;
32
import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
33
34
35
/**
36
* This class represents ciphers in GaloisCounter (GCM) mode.
37
*
38
* <p>This mode currently should only be used w/ AES cipher.
39
* Although no checking is done, caller should only pass AES
40
* Cipher to the constructor.
41
*
42
* <p>NOTE: Unlike other modes, when used for decryption, this class
43
* will buffer all processed outputs internally and won't return them
44
* until the tag has been successfully verified.
45
*
46
* @since 1.8
47
*/
48
final class GaloisCounterMode extends FeedbackCipher {
49
50
static int DEFAULT_TAG_LEN = AES_BLOCK_SIZE;
51
static int DEFAULT_IV_LEN = 12; // in bytes
52
53
// In NIST SP 800-38D, GCM input size is limited to be no longer
54
// than (2^36 - 32) bytes. Otherwise, the counter will wrap
55
// around and lead to a leak of plaintext.
56
// However, given the current GCM spec requirement that recovered
57
// text can only be returned after successful tag verification,
58
// we are bound by limiting the data size to the size limit of
59
// java byte array, e.g. Integer.MAX_VALUE, since all data
60
// can only be returned by the doFinal(...) call.
61
private static final int MAX_BUF_SIZE = Integer.MAX_VALUE;
62
63
// data size when buffer is divided up to aid in intrinsics
64
private static final int TRIGGERLEN = 65536; // 64k
65
66
// buffer for AAD data; if null, meaning update has been called
67
private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream();
68
private int sizeOfAAD = 0;
69
70
// buffer for storing input in decryption, not used for encryption
71
private ByteArrayOutputStream ibuffer = null;
72
73
// in bytes; need to convert to bits (default value 128) when needed
74
private int tagLenBytes = DEFAULT_TAG_LEN;
75
76
// these following 2 fields can only be initialized after init() is
77
// called, e.g. after cipher key k is set, and STAY UNCHANGED
78
private byte[] subkeyH = null;
79
private byte[] preCounterBlock = null;
80
81
private GCTR gctrPAndC = null;
82
private GHASH ghashAllToS = null;
83
84
// length of total data, i.e. len(C)
85
private int processed = 0;
86
87
// additional variables for save/restore calls
88
private byte[] aadBufferSave = null;
89
private int sizeOfAADSave = 0;
90
private byte[] ibufferSave = null;
91
private int processedSave = 0;
92
93
// value must be 16-byte long; used by GCTR and GHASH as well
94
static void increment32(byte[] value) {
95
if (value.length != AES_BLOCK_SIZE) {
96
// should never happen
97
throw new ProviderException("Illegal counter block length");
98
}
99
// start from last byte and only go over 4 bytes, i.e. total 32 bits
100
int n = value.length - 1;
101
while ((n >= value.length - 4) && (++value[n] == 0)) {
102
n--;
103
}
104
}
105
106
private static byte[] getLengthBlock(int ivLenInBytes) {
107
long ivLen = ((long)ivLenInBytes) << 3;
108
byte[] out = new byte[AES_BLOCK_SIZE];
109
out[8] = (byte)(ivLen >>> 56);
110
out[9] = (byte)(ivLen >>> 48);
111
out[10] = (byte)(ivLen >>> 40);
112
out[11] = (byte)(ivLen >>> 32);
113
out[12] = (byte)(ivLen >>> 24);
114
out[13] = (byte)(ivLen >>> 16);
115
out[14] = (byte)(ivLen >>> 8);
116
out[15] = (byte)ivLen;
117
return out;
118
}
119
120
private static byte[] getLengthBlock(int aLenInBytes, int cLenInBytes) {
121
long aLen = ((long)aLenInBytes) << 3;
122
long cLen = ((long)cLenInBytes) << 3;
123
byte[] out = new byte[AES_BLOCK_SIZE];
124
out[0] = (byte)(aLen >>> 56);
125
out[1] = (byte)(aLen >>> 48);
126
out[2] = (byte)(aLen >>> 40);
127
out[3] = (byte)(aLen >>> 32);
128
out[4] = (byte)(aLen >>> 24);
129
out[5] = (byte)(aLen >>> 16);
130
out[6] = (byte)(aLen >>> 8);
131
out[7] = (byte)aLen;
132
out[8] = (byte)(cLen >>> 56);
133
out[9] = (byte)(cLen >>> 48);
134
out[10] = (byte)(cLen >>> 40);
135
out[11] = (byte)(cLen >>> 32);
136
out[12] = (byte)(cLen >>> 24);
137
out[13] = (byte)(cLen >>> 16);
138
out[14] = (byte)(cLen >>> 8);
139
out[15] = (byte)cLen;
140
return out;
141
}
142
143
private static byte[] expandToOneBlock(byte[] in, int inOfs, int len) {
144
if (len > AES_BLOCK_SIZE) {
145
throw new ProviderException("input " + len + " too long");
146
}
147
if (len == AES_BLOCK_SIZE && inOfs == 0) {
148
return in;
149
} else {
150
byte[] paddedIn = new byte[AES_BLOCK_SIZE];
151
System.arraycopy(in, inOfs, paddedIn, 0, len);
152
return paddedIn;
153
}
154
}
155
156
private static byte[] getJ0(byte[] iv, byte[] subkeyH) {
157
byte[] j0;
158
if (iv.length == 12) { // 96 bits
159
j0 = expandToOneBlock(iv, 0, iv.length);
160
j0[AES_BLOCK_SIZE - 1] = 1;
161
} else {
162
GHASH g = new GHASH(subkeyH);
163
int lastLen = iv.length % AES_BLOCK_SIZE;
164
if (lastLen != 0) {
165
g.update(iv, 0, iv.length - lastLen);
166
byte[] padded =
167
expandToOneBlock(iv, iv.length - lastLen, lastLen);
168
g.update(padded);
169
} else {
170
g.update(iv);
171
}
172
byte[] lengthBlock = getLengthBlock(iv.length);
173
g.update(lengthBlock);
174
j0 = g.digest();
175
}
176
return j0;
177
}
178
179
private static void checkDataLength(int processed, int len) {
180
if (processed > MAX_BUF_SIZE - len) {
181
throw new ProviderException("SunJCE provider only supports " +
182
"input size up to " + MAX_BUF_SIZE + " bytes");
183
}
184
}
185
186
GaloisCounterMode(SymmetricCipher embeddedCipher) {
187
super(embeddedCipher);
188
aadBuffer = new ByteArrayOutputStream();
189
}
190
191
/**
192
* Gets the name of the feedback mechanism
193
*
194
* @return the name of the feedback mechanism
195
*/
196
String getFeedback() {
197
return "GCM";
198
}
199
200
/**
201
* Resets the cipher object to its original state.
202
* This is used when doFinal is called in the Cipher class, so that the
203
* cipher can be reused (with its original key and iv).
204
*/
205
void reset() {
206
if (aadBuffer == null) {
207
aadBuffer = new ByteArrayOutputStream();
208
} else {
209
aadBuffer.reset();
210
}
211
if (gctrPAndC != null) gctrPAndC.reset();
212
if (ghashAllToS != null) ghashAllToS.reset();
213
processed = 0;
214
sizeOfAAD = 0;
215
if (ibuffer != null) {
216
ibuffer.reset();
217
}
218
}
219
220
/**
221
* Save the current content of this cipher.
222
*/
223
void save() {
224
processedSave = processed;
225
sizeOfAADSave = sizeOfAAD;
226
aadBufferSave =
227
((aadBuffer == null || aadBuffer.size() == 0)?
228
null : aadBuffer.toByteArray());
229
if (gctrPAndC != null) gctrPAndC.save();
230
if (ghashAllToS != null) ghashAllToS.save();
231
if (ibuffer != null) {
232
ibufferSave = ibuffer.toByteArray();
233
}
234
}
235
236
/**
237
* Restores the content of this cipher to the previous saved one.
238
*/
239
void restore() {
240
processed = processedSave;
241
sizeOfAAD = sizeOfAADSave;
242
if (aadBuffer != null) {
243
aadBuffer.reset();
244
if (aadBufferSave != null) {
245
aadBuffer.write(aadBufferSave, 0, aadBufferSave.length);
246
}
247
}
248
if (gctrPAndC != null) gctrPAndC.restore();
249
if (ghashAllToS != null) ghashAllToS.restore();
250
if (ibuffer != null) {
251
ibuffer.reset();
252
ibuffer.write(ibufferSave, 0, ibufferSave.length);
253
}
254
}
255
256
/**
257
* Initializes the cipher in the specified mode with the given key
258
* and iv.
259
*
260
* @param decrypting flag indicating encryption or decryption
261
* @param algorithm the algorithm name
262
* @param key the key
263
* @param iv the iv
264
* @param tagLenBytes the length of tag in bytes
265
*
266
* @exception InvalidKeyException if the given key is inappropriate for
267
* initializing this cipher
268
*/
269
@Override
270
void init(boolean decrypting, String algorithm, byte[] key, byte[] iv)
271
throws InvalidKeyException, InvalidAlgorithmParameterException {
272
init(decrypting, algorithm, key, iv, DEFAULT_TAG_LEN);
273
}
274
275
/**
276
* Initializes the cipher in the specified mode with the given key
277
* and iv.
278
*
279
* @param decrypting flag indicating encryption or decryption
280
* @param algorithm the algorithm name
281
* @param key the key
282
* @param iv the iv
283
* @param tagLenBytes the length of tag in bytes
284
*
285
* @exception InvalidKeyException if the given key is inappropriate for
286
* initializing this cipher
287
*/
288
void init(boolean decrypting, String algorithm, byte[] keyValue,
289
byte[] ivValue, int tagLenBytes)
290
throws InvalidKeyException, InvalidAlgorithmParameterException {
291
if (keyValue == null) {
292
throw new InvalidKeyException("Internal error");
293
}
294
if (ivValue == null) {
295
throw new InvalidAlgorithmParameterException("Internal error");
296
}
297
if (ivValue.length == 0) {
298
throw new InvalidAlgorithmParameterException("IV is empty");
299
}
300
301
// always encrypt mode for embedded cipher
302
this.embeddedCipher.init(false, algorithm, keyValue);
303
this.subkeyH = new byte[AES_BLOCK_SIZE];
304
this.embeddedCipher.encryptBlock(new byte[AES_BLOCK_SIZE], 0,
305
this.subkeyH, 0);
306
307
this.iv = ivValue.clone();
308
preCounterBlock = getJ0(iv, subkeyH);
309
byte[] j0Plus1 = preCounterBlock.clone();
310
increment32(j0Plus1);
311
gctrPAndC = new GCTR(embeddedCipher, j0Plus1);
312
ghashAllToS = new GHASH(subkeyH);
313
314
this.tagLenBytes = tagLenBytes;
315
if (aadBuffer == null) {
316
aadBuffer = new ByteArrayOutputStream();
317
} else {
318
aadBuffer.reset();
319
}
320
processed = 0;
321
sizeOfAAD = 0;
322
if (decrypting) {
323
ibuffer = new ByteArrayOutputStream();
324
}
325
}
326
327
/**
328
* Continues a multi-part update of the Additional Authentication
329
* Data (AAD), using a subset of the provided buffer. If this
330
* cipher is operating in either GCM or CCM mode, all AAD must be
331
* supplied before beginning operations on the ciphertext (via the
332
* {@code update} and {@code doFinal} methods).
333
* <p>
334
* NOTE: Given most modes do not accept AAD, default impl for this
335
* method throws IllegalStateException.
336
*
337
* @param src the buffer containing the AAD
338
* @param offset the offset in {@code src} where the AAD input starts
339
* @param len the number of AAD bytes
340
*
341
* @throws IllegalStateException if this cipher is in a wrong state
342
* (e.g., has not been initialized), does not accept AAD, or if
343
* operating in either GCM or CCM mode and one of the {@code update}
344
* methods has already been called for the active
345
* encryption/decryption operation
346
* @throws UnsupportedOperationException if this method
347
* has not been overridden by an implementation
348
*
349
* @since 1.8
350
*/
351
void updateAAD(byte[] src, int offset, int len) {
352
if (aadBuffer != null) {
353
aadBuffer.write(src, offset, len);
354
} else {
355
// update has already been called
356
throw new IllegalStateException
357
("Update has been called; no more AAD data");
358
}
359
}
360
361
// Feed the AAD data to GHASH, pad if necessary
362
void processAAD() {
363
if (aadBuffer != null) {
364
if (aadBuffer.size() > 0) {
365
byte[] aad = aadBuffer.toByteArray();
366
sizeOfAAD = aad.length;
367
368
int lastLen = aad.length % AES_BLOCK_SIZE;
369
if (lastLen != 0) {
370
ghashAllToS.update(aad, 0, aad.length - lastLen);
371
byte[] padded = expandToOneBlock(aad, aad.length - lastLen,
372
lastLen);
373
ghashAllToS.update(padded);
374
} else {
375
ghashAllToS.update(aad);
376
}
377
}
378
aadBuffer = null;
379
}
380
}
381
382
// Utility to process the last block; used by encryptFinal and decryptFinal
383
void doLastBlock(byte[] in, int inOfs, int len, byte[] out, int outOfs,
384
boolean isEncrypt) throws IllegalBlockSizeException {
385
byte[] ct;
386
int ctOfs;
387
int ilen = len; // internal length
388
389
if (isEncrypt) {
390
ct = out;
391
ctOfs = outOfs;
392
} else {
393
ct = in;
394
ctOfs = inOfs;
395
}
396
397
// Divide up larger data sizes to trigger CTR & GHASH intrinsic quicker
398
if (len > TRIGGERLEN) {
399
int i = 0;
400
int tlen; // incremental lengths
401
final int plen = AES_BLOCK_SIZE * 6;
402
// arbitrary formula to aid intrinsic without reaching buffer end
403
final int count = len / 1024;
404
405
while (count > i) {
406
tlen = gctrPAndC.update(in, inOfs, plen, out, outOfs);
407
ghashAllToS.update(ct, ctOfs, tlen);
408
inOfs += tlen;
409
outOfs += tlen;
410
ctOfs += tlen;
411
i++;
412
}
413
ilen -= count * plen;
414
processed += count * plen;
415
}
416
417
gctrPAndC.doFinal(in, inOfs, ilen, out, outOfs);
418
processed += ilen;
419
420
int lastLen = ilen % AES_BLOCK_SIZE;
421
if (lastLen != 0) {
422
ghashAllToS.update(ct, ctOfs, ilen - lastLen);
423
ghashAllToS.update(
424
expandToOneBlock(ct, (ctOfs + ilen - lastLen), lastLen));
425
} else {
426
ghashAllToS.update(ct, ctOfs, ilen);
427
}
428
}
429
430
431
/**
432
* Performs encryption operation.
433
*
434
* <p>The input plain text <code>in</code>, starting at <code>inOfs</code>
435
* and ending at <code>(inOfs + len - 1)</code>, is encrypted. The result
436
* is stored in <code>out</code>, starting at <code>outOfs</code>.
437
*
438
* @param in the buffer with the input data to be encrypted
439
* @param inOfs the offset in <code>in</code>
440
* @param len the length of the input data
441
* @param out the buffer for the result
442
* @param outOfs the offset in <code>out</code>
443
* @exception ProviderException if <code>len</code> is not
444
* a multiple of the block size
445
* @return the number of bytes placed into the <code>out</code> buffer
446
*/
447
int encrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
448
checkDataLength(processed, len);
449
450
RangeUtil.blockSizeCheck(len, blockSize);
451
processAAD();
452
453
if (len > 0) {
454
RangeUtil.nullAndBoundsCheck(in, inOfs, len);
455
RangeUtil.nullAndBoundsCheck(out, outOfs, len);
456
457
gctrPAndC.update(in, inOfs, len, out, outOfs);
458
processed += len;
459
ghashAllToS.update(out, outOfs, len);
460
}
461
462
return len;
463
}
464
465
/**
466
* Performs encryption operation for the last time.
467
*
468
* @param in the input buffer with the data to be encrypted
469
* @param inOfs the offset in <code>in</code>
470
* @param len the length of the input data
471
* @param out the buffer for the encryption result
472
* @param outOfs the offset in <code>out</code>
473
* @return the number of bytes placed into the <code>out</code> buffer
474
*/
475
int encryptFinal(byte[] in, int inOfs, int len, byte[] out, int outOfs)
476
throws IllegalBlockSizeException, ShortBufferException {
477
if (len > MAX_BUF_SIZE - tagLenBytes) {
478
throw new ShortBufferException
479
("Can't fit both data and tag into one buffer");
480
}
481
try {
482
RangeUtil.nullAndBoundsCheck(out, outOfs,
483
(len + tagLenBytes));
484
} catch (ArrayIndexOutOfBoundsException aiobe) {
485
throw new ShortBufferException("Output buffer too small");
486
}
487
488
checkDataLength(processed, len);
489
490
processAAD();
491
if (len > 0) {
492
RangeUtil.nullAndBoundsCheck(in, inOfs, len);
493
494
doLastBlock(in, inOfs, len, out, outOfs, true);
495
}
496
497
byte[] lengthBlock =
498
getLengthBlock(sizeOfAAD, processed);
499
ghashAllToS.update(lengthBlock);
500
byte[] s = ghashAllToS.digest();
501
byte[] sOut = new byte[s.length];
502
GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock);
503
gctrForSToTag.doFinal(s, 0, s.length, sOut, 0);
504
505
System.arraycopy(sOut, 0, out, (outOfs + len), tagLenBytes);
506
return (len + tagLenBytes);
507
}
508
509
/**
510
* Performs decryption operation.
511
*
512
* <p>The input cipher text <code>in</code>, starting at
513
* <code>inOfs</code> and ending at <code>(inOfs + len - 1)</code>,
514
* is decrypted. The result is stored in <code>out</code>, starting at
515
* <code>outOfs</code>.
516
*
517
* @param in the buffer with the input data to be decrypted
518
* @param inOfs the offset in <code>in</code>
519
* @param len the length of the input data
520
* @param out the buffer for the result
521
* @param outOfs the offset in <code>out</code>
522
* @exception ProviderException if <code>len</code> is not
523
* a multiple of the block size
524
* @return the number of bytes placed into the <code>out</code> buffer
525
*/
526
int decrypt(byte[] in, int inOfs, int len, byte[] out, int outOfs) {
527
checkDataLength(ibuffer.size(), len);
528
529
RangeUtil.blockSizeCheck(len, blockSize);
530
processAAD();
531
532
if (len > 0) {
533
// store internally until decryptFinal is called because
534
// spec mentioned that only return recovered data after tag
535
// is successfully verified
536
RangeUtil.nullAndBoundsCheck(in, inOfs, len);
537
ibuffer.write(in, inOfs, len);
538
}
539
return 0;
540
}
541
542
/**
543
* Performs decryption operation for the last time.
544
*
545
* <p>NOTE: For cipher feedback modes which does not perform
546
* special handling for the last few blocks, this is essentially
547
* the same as <code>encrypt(...)</code>. Given most modes do
548
* not do special handling, the default impl for this method is
549
* to simply call <code>decrypt(...)</code>.
550
*
551
* @param in the input buffer with the data to be decrypted
552
* @param inOfs the offset in <code>cipher</code>
553
* @param len the length of the input data
554
* @param out the buffer for the decryption result
555
* @param outOfs the offset in <code>plain</code>
556
* @return the number of bytes placed into the <code>out</code> buffer
557
*/
558
int decryptFinal(byte[] in, int inOfs, int len,
559
byte[] out, int outOfs)
560
throws IllegalBlockSizeException, AEADBadTagException,
561
ShortBufferException {
562
if (len < tagLenBytes) {
563
throw new AEADBadTagException("Input too short - need tag");
564
}
565
566
// do this check here can also catch the potential integer overflow
567
// scenario for the subsequent output buffer capacity check.
568
checkDataLength(ibuffer.size(), (len - tagLenBytes));
569
570
try {
571
RangeUtil.nullAndBoundsCheck(out, outOfs,
572
(ibuffer.size() + len) - tagLenBytes);
573
} catch (ArrayIndexOutOfBoundsException aiobe) {
574
throw new ShortBufferException("Output buffer too small");
575
}
576
577
processAAD();
578
579
RangeUtil.nullAndBoundsCheck(in, inOfs, len);
580
581
// get the trailing tag bytes from 'in'
582
byte[] tag = new byte[tagLenBytes];
583
System.arraycopy(in, inOfs + len - tagLenBytes, tag, 0, tagLenBytes);
584
len -= tagLenBytes;
585
586
// If decryption is in-place or there is buffered "ibuffer" data, copy
587
// the "in" byte array into the ibuffer before proceeding.
588
if (in == out || ibuffer.size() > 0) {
589
if (len > 0) {
590
ibuffer.write(in, inOfs, len);
591
}
592
593
// refresh 'in' to all buffered-up bytes
594
in = ibuffer.toByteArray();
595
inOfs = 0;
596
len = in.length;
597
ibuffer.reset();
598
}
599
600
if (len > 0) {
601
doLastBlock(in, inOfs, len, out, outOfs, false);
602
}
603
604
byte[] lengthBlock =
605
getLengthBlock(sizeOfAAD, processed);
606
ghashAllToS.update(lengthBlock);
607
608
byte[] s = ghashAllToS.digest();
609
byte[] sOut = new byte[s.length];
610
GCTR gctrForSToTag = new GCTR(embeddedCipher, this.preCounterBlock);
611
gctrForSToTag.doFinal(s, 0, s.length, sOut, 0);
612
613
// check entire authentication tag for time-consistency
614
int mismatch = 0;
615
for (int i = 0; i < tagLenBytes; i++) {
616
mismatch |= tag[i] ^ sOut[i];
617
}
618
619
if (mismatch != 0) {
620
throw new AEADBadTagException("Tag mismatch!");
621
}
622
623
return len;
624
}
625
626
// return tag length in bytes
627
int getTagLen() {
628
return this.tagLenBytes;
629
}
630
631
int getBufferedLength() {
632
if (ibuffer == null) {
633
return 0;
634
} else {
635
return ibuffer.size();
636
}
637
}
638
}
639
640