Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java
67773 views
1
/*
2
* Copyright (c) 2013, 2020, 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
/*
27
* (C) Copyright IBM Corp. 2013
28
*/
29
30
package com.sun.crypto.provider;
31
32
import java.nio.ByteBuffer;
33
import java.nio.ByteOrder;
34
import java.util.Arrays;
35
36
/**
37
* This class represents the GCTR function defined in NIST 800-38D
38
* under section 6.5. With a given cipher object and initial counter
39
* block, a counter mode operation is performed. Blocksize is limited
40
* to 16 bytes.
41
*
42
* If any invariant is broken, failures can occur because the
43
* AESCrypt.encryptBlock method can be intrinsified on the HotSpot VM
44
* (see JDK-8067648 for details).
45
*
46
* The counter mode operations can be intrinsified and parallelized
47
* by using CounterMode.implCrypt() if HotSpot VM supports it on the
48
* architecture.
49
*
50
* <p>This function is used in the implementation of GCM mode.
51
*
52
* @since 1.8
53
*/
54
final class GCTR extends CounterMode implements GCM {
55
56
// Maximum buffer size rotating ByteBuffer->byte[] intrinsic copy
57
private static final int MAX_LEN = 1024;
58
private byte[] block;
59
60
GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) {
61
super(cipher);
62
if (initialCounterBlk.length != blockSize) {
63
throw new RuntimeException("length of initial counter block (" +
64
initialCounterBlk.length + ") not equal to blockSize (" +
65
blockSize + ")");
66
}
67
68
iv = initialCounterBlk;
69
reset();
70
}
71
72
@Override
73
String getFeedback() {
74
return "GCTR";
75
}
76
77
// return the number of blocks until the lower 32 bits roll over
78
private long blocksUntilRollover() {
79
ByteBuffer buf = ByteBuffer.wrap(counter, counter.length - 4, 4);
80
buf.order(ByteOrder.BIG_ENDIAN);
81
long ctr32 = 0xFFFFFFFFL & buf.getInt();
82
long blocksLeft = (1L << 32) - ctr32;
83
return blocksLeft;
84
}
85
86
private void checkBlock() {
87
if (block == null) {
88
block = new byte[blockSize];
89
} else {
90
Arrays.fill(block, (byte)0);
91
}
92
}
93
94
/**
95
* Using the given inLen, this operates only on blockSize data, leaving
96
* the remainder in 'in'.
97
* The return value will be (inLen - (inLen % blockSize))
98
*/
99
public int update(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) {
100
if (inLen == 0) {
101
return 0;
102
}
103
104
if (inLen - inOfs > in.length) {
105
throw new RuntimeException("input length out of bound");
106
}
107
if (inLen < 0) {
108
throw new RuntimeException("input length unsupported");
109
}
110
if (out.length - outOfs < (inLen - (inLen % blockSize))) {
111
throw new RuntimeException("output buffer too small");
112
}
113
114
inLen -= inLen % blockSize;
115
long blocksLeft = blocksUntilRollover();
116
int numOfCompleteBlocks = inLen / blockSize;
117
if (numOfCompleteBlocks >= blocksLeft) {
118
// Counter Mode encryption cannot be used because counter will
119
// roll over incorrectly. Use GCM-specific code instead.
120
checkBlock();
121
for (int i = 0; i < numOfCompleteBlocks; i++) {
122
embeddedCipher.encryptBlock(counter, 0, block, 0);
123
for (int n = 0; n < blockSize; n++) {
124
int index = (i * blockSize + n);
125
out[outOfs + index] =
126
(byte) ((in[inOfs + index] ^ block[n]));
127
}
128
GaloisCounterMode.increment32(counter);
129
}
130
return inLen;
131
} else {
132
return encrypt(in, inOfs, inLen, out, outOfs);
133
}
134
}
135
136
/**
137
* Operate on only blocksize data leaving the remainder in 'in' .
138
*/
139
public int update(byte[] in, int inOfs, int inLen, ByteBuffer dst) {
140
// If the bytebuffer is backed by arrays, use that instead of
141
// allocating and copying for direct bytebuffers
142
if (!dst.isDirect()) {
143
int len = update(in, inOfs, inLen, dst.array(),
144
dst.arrayOffset() + dst.position());
145
dst.position(dst.position() + len);
146
return len;
147
}
148
149
// Direct ByteBuffer operation
150
if (inLen - inOfs > in.length) {
151
throw new RuntimeException("input length out of bound");
152
}
153
if (inLen < 0) {
154
throw new RuntimeException("input length unsupported");
155
}
156
// See GaloisCounterMode. decryptFinal(bytebuffer, bytebuffer) for
157
// details on the check for 'dst' having enough space for the result.
158
159
long blocksLeft = blocksUntilRollover();
160
int numOfCompleteBlocks = inLen / blockSize;
161
if (numOfCompleteBlocks >= blocksLeft) {
162
// Counter Mode encryption cannot be used because counter will
163
// roll over incorrectly. Use GCM-specific code instead.
164
checkBlock();
165
for (int i = 0; i < numOfCompleteBlocks; i++) {
166
embeddedCipher.encryptBlock(counter, 0, block, 0);
167
for (int n = 0; n < blockSize; n++) {
168
int index = (i * blockSize + n);
169
dst.put((byte) ((in[inOfs + index] ^ block[n])));
170
}
171
GaloisCounterMode.increment32(counter);
172
}
173
return inLen;
174
} else {
175
int len = inLen - inLen % blockSize;
176
int processed = len;
177
byte[] out = new byte[Math.min(MAX_LEN, len)];
178
int offset = inOfs;
179
while (processed > MAX_LEN) {
180
encrypt(in, offset, MAX_LEN, out, 0);
181
dst.put(out, 0, MAX_LEN);
182
processed -= MAX_LEN;
183
offset += MAX_LEN;
184
}
185
encrypt(in, offset, processed, out, 0);
186
// If dst is less than blocksize, insert only what it can. Extra
187
// bytes would cause buffers with enough size to fail with a
188
// short buffer
189
dst.put(out, 0, Math.min(dst.remaining(), processed));
190
return len;
191
}
192
}
193
194
/**
195
* Operate on only blocksize data leaving the remainder in the src buffer.
196
*/
197
public int update(ByteBuffer src, ByteBuffer dst) {
198
int len;
199
200
// If the bytebuffer is backed by arrays, use that instead of
201
// allocating and copying for direct bytebuffers
202
if (src.hasArray() && dst.hasArray()) {
203
len = update(src.array(), src.arrayOffset() + src.position(),
204
src.remaining() - (src.remaining() % blockSize),
205
dst.array(), dst.arrayOffset() + dst.position());
206
src.position(src.position() + len);
207
dst.position(dst.position() + len);
208
return len;
209
}
210
211
// Direct bytebuffer operation
212
long blocksLeft = blocksUntilRollover();
213
int numOfCompleteBlocks = src.remaining() / blockSize;
214
if (numOfCompleteBlocks >= blocksLeft) {
215
// Counter Mode encryption cannot be used because counter will
216
// roll over incorrectly. Use GCM-specific code instead.
217
checkBlock();
218
for (int i = 0; i < numOfCompleteBlocks; i++) {
219
embeddedCipher.encryptBlock(counter, 0, block, 0);
220
for (int n = 0; n < blockSize; n++) {
221
dst.put((byte) (src.get() ^ block[n]));
222
}
223
GaloisCounterMode.increment32(counter);
224
}
225
return numOfCompleteBlocks * blockSize;
226
}
227
228
len = src.remaining() - (src.remaining() % blockSize);
229
int processed = len;
230
byte[] in = new byte[Math.min(MAX_LEN, len)];
231
while (processed > MAX_LEN) {
232
src.get(in, 0, MAX_LEN);
233
encrypt(in, 0, MAX_LEN, in, 0);
234
dst.put(in, 0, MAX_LEN);
235
processed -= MAX_LEN;
236
}
237
src.get(in, 0, processed);
238
encrypt(in, 0, processed, in, 0);
239
dst.put(in, 0, processed);
240
return len;
241
}
242
243
/**
244
* doFinal operation by using update() for any full block operations needed,
245
* then operating on the final bytes in the input buffer.
246
*
247
* This method will not write any block padding to the output buffer
248
*/
249
public int doFinal(byte[] in, int inOfs, int inLen, byte[] out,
250
int outOfs) {
251
if (inLen == 0) {
252
return 0;
253
}
254
int lastBlockSize = inLen % blockSize;
255
int completeBlkLen = inLen - lastBlockSize;
256
// process the complete blocks first
257
update(in, inOfs, completeBlkLen, out, outOfs);
258
if (lastBlockSize != 0) {
259
// do the last partial block
260
checkBlock();
261
embeddedCipher.encryptBlock(counter, 0, block, 0);
262
for (int n = 0; n < lastBlockSize; n++) {
263
out[outOfs + completeBlkLen + n] =
264
(byte) ((in[inOfs + completeBlkLen + n] ^ block[n]));
265
}
266
}
267
return inLen;
268
}
269
270
/**
271
* doFinal operation by using update() for any full block operations needed,
272
* then operating on the final bytes in the input buffer.
273
*
274
* If src and dst are array-backed bytebuffers, call doFinal(byte[]...) for
275
* less memory usage.
276
*/
277
public int doFinal(ByteBuffer src, ByteBuffer dst) {
278
// If the bytebuffer is backed by arrays, use that instead of
279
// allocating and copying for direct bytebuffers
280
if (src.hasArray() && dst.hasArray()) {
281
int len = doFinal(src.array(), src.arrayOffset() + src.position(),
282
src.remaining(), dst.array(),
283
dst.arrayOffset() + dst.position());
284
src.position(src.position() + len);
285
dst.position(dst.position() + len);
286
return len;
287
}
288
289
int len = src.remaining();
290
int lastBlockSize = len % blockSize;
291
update(src, dst);
292
if (lastBlockSize != 0) {
293
checkBlock();
294
// do the last partial block
295
embeddedCipher.encryptBlock(counter, 0, block, 0);
296
for (int n = 0; n < lastBlockSize; n++) {
297
dst.put((byte) (src.get() ^ block[n]));
298
}
299
}
300
return len;
301
}
302
}
303
304