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/sun/security/pkcs11/P11Cipher.java
38919 views
1
/*
2
* Copyright (c) 2003, 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
package sun.security.pkcs11;
26
27
import java.nio.ByteBuffer;
28
import java.util.Arrays;
29
import java.util.Locale;
30
31
import java.security.*;
32
import java.security.spec.*;
33
34
import javax.crypto.*;
35
import javax.crypto.spec.*;
36
37
import sun.nio.ch.DirectBuffer;
38
import sun.security.jca.JCAUtil;
39
import sun.security.pkcs11.wrapper.*;
40
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
41
42
/**
43
* Cipher implementation class. This class currently supports
44
* DES, DESede, AES, ARCFOUR, and Blowfish.
45
*
46
* This class is designed to support ECB, CBC, CTR with NoPadding
47
* and ECB, CBC with PKCS5Padding. It will use its own padding impl
48
* if the native mechanism does not support padding.
49
*
50
* Note that PKCS#11 currently only supports ECB, CBC, and CTR.
51
* There are no provisions for other modes such as CFB, OFB, and PCBC.
52
*
53
* @author Andreas Sterbenz
54
* @since 1.5
55
*/
56
final class P11Cipher extends CipherSpi {
57
58
// mode constant for ECB mode
59
private final static int MODE_ECB = 3;
60
// mode constant for CBC mode
61
private final static int MODE_CBC = 4;
62
// mode constant for CTR mode
63
private final static int MODE_CTR = 5;
64
65
// padding constant for NoPadding
66
private final static int PAD_NONE = 5;
67
// padding constant for PKCS5Padding
68
private final static int PAD_PKCS5 = 6;
69
70
private static interface Padding {
71
// ENC: format the specified buffer with padding bytes and return the
72
// actual padding length
73
int setPaddingBytes(byte[] paddingBuffer, int startOff, int padLen);
74
75
// DEC: return the length of trailing padding bytes given the specified
76
// padded data
77
int unpad(byte[] paddedData, int len)
78
throws BadPaddingException, IllegalBlockSizeException;
79
}
80
81
private static class PKCS5Padding implements Padding {
82
83
private final int blockSize;
84
85
PKCS5Padding(int blockSize)
86
throws NoSuchPaddingException {
87
if (blockSize == 0) {
88
throw new NoSuchPaddingException
89
("PKCS#5 padding not supported with stream ciphers");
90
}
91
this.blockSize = blockSize;
92
}
93
94
public int setPaddingBytes(byte[] paddingBuffer, int startOff, int padLen) {
95
Arrays.fill(paddingBuffer, startOff, startOff + padLen, (byte) (padLen & 0x007f));
96
return padLen;
97
}
98
99
public int unpad(byte[] paddedData, int len)
100
throws BadPaddingException, IllegalBlockSizeException {
101
if ((len < 1) || (len % blockSize != 0)) {
102
throw new IllegalBlockSizeException
103
("Input length must be multiples of " + blockSize);
104
}
105
byte padValue = paddedData[len - 1];
106
if (padValue < 1 || padValue > blockSize) {
107
throw new BadPaddingException("Invalid pad value!");
108
}
109
// sanity check padding bytes
110
int padStartIndex = len - padValue;
111
for (int i = padStartIndex; i < len; i++) {
112
if (paddedData[i] != padValue) {
113
throw new BadPaddingException("Invalid pad bytes!");
114
}
115
}
116
return padValue;
117
}
118
}
119
120
// token instance
121
private final Token token;
122
123
// algorithm name
124
private final String algorithm;
125
126
// name of the key algorithm, e.g. DES instead of algorithm DES/CBC/...
127
private final String keyAlgorithm;
128
129
// mechanism id
130
private final long mechanism;
131
132
// associated session, if any
133
private Session session;
134
135
// key, if init() was called
136
private P11Key p11Key;
137
138
// flag indicating whether an operation is initialized
139
private boolean initialized;
140
141
// falg indicating encrypt or decrypt mode
142
private boolean encrypt;
143
144
// mode, one of MODE_* above (MODE_ECB for stream ciphers)
145
private int blockMode;
146
147
// block size, 0 for stream ciphers
148
private final int blockSize;
149
150
// padding type, on of PAD_* above (PAD_NONE for stream ciphers)
151
private int paddingType;
152
153
// when the padding is requested but unsupported by the native mechanism,
154
// we use the following to do padding and necessary data buffering.
155
// padding object which generate padding and unpad the decrypted data
156
private Padding paddingObj;
157
// buffer for holding back the block which contains padding bytes
158
private byte[] padBuffer;
159
private int padBufferLen;
160
161
// original IV, if in MODE_CBC or MODE_CTR
162
private byte[] iv;
163
164
// number of bytes buffered internally by the native mechanism and padBuffer
165
// if we do the padding
166
private int bytesBuffered;
167
168
// length of key size in bytes; currently only used by AES given its oid
169
// specification mandates a fixed size of the key
170
private int fixedKeySize = -1;
171
172
// Indicates whether the underlying PKCS#11 library requires block-sized
173
// updates during multi-part operations. In such case, we buffer data in
174
// padBuffer up to a block-size. This may be needed only if padding is
175
// applied on the Java side. An example of the previous is when the
176
// CKM_AES_ECB mechanism is used and the PKCS#11 library is NSS. See more
177
// on JDK-8261355.
178
private boolean reqBlockUpdates = false;
179
180
P11Cipher(Token token, String algorithm, long mechanism)
181
throws PKCS11Exception, NoSuchAlgorithmException {
182
super();
183
this.token = token;
184
this.algorithm = algorithm;
185
this.mechanism = mechanism;
186
187
String algoParts[] = algorithm.split("/");
188
189
if (algoParts[0].startsWith("AES")) {
190
blockSize = 16;
191
int index = algoParts[0].indexOf('_');
192
if (index != -1) {
193
// should be well-formed since we specify what we support
194
fixedKeySize = Integer.parseInt(algoParts[0].substring(index+1))/8;
195
}
196
keyAlgorithm = "AES";
197
} else {
198
keyAlgorithm = algoParts[0];
199
if (keyAlgorithm.equals("RC4") ||
200
keyAlgorithm.equals("ARCFOUR")) {
201
blockSize = 0;
202
} else { // DES, DESede, Blowfish
203
blockSize = 8;
204
}
205
}
206
this.blockMode =
207
(algoParts.length > 1 ? parseMode(algoParts[1]) : MODE_ECB);
208
String defPadding = (blockSize == 0 ? "NoPadding" : "PKCS5Padding");
209
String paddingStr =
210
(algoParts.length > 2 ? algoParts[2] : defPadding);
211
try {
212
engineSetPadding(paddingStr);
213
} catch (NoSuchPaddingException nspe) {
214
// should not happen
215
throw new ProviderException(nspe);
216
}
217
}
218
219
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
220
// Disallow change of mode for now since currently it's explicitly
221
// defined in transformation strings
222
throw new NoSuchAlgorithmException("Unsupported mode " + mode);
223
}
224
225
private int parseMode(String mode) throws NoSuchAlgorithmException {
226
mode = mode.toUpperCase(Locale.ENGLISH);
227
int result;
228
if (mode.equals("ECB")) {
229
result = MODE_ECB;
230
} else if (mode.equals("CBC")) {
231
if (blockSize == 0) {
232
throw new NoSuchAlgorithmException
233
("CBC mode not supported with stream ciphers");
234
}
235
result = MODE_CBC;
236
} else if (mode.equals("CTR")) {
237
result = MODE_CTR;
238
} else {
239
throw new NoSuchAlgorithmException("Unsupported mode " + mode);
240
}
241
return result;
242
}
243
244
// see JCE spec
245
protected void engineSetPadding(String padding)
246
throws NoSuchPaddingException {
247
paddingObj = null;
248
padBuffer = null;
249
padding = padding.toUpperCase(Locale.ENGLISH);
250
if (padding.equals("NOPADDING")) {
251
paddingType = PAD_NONE;
252
} else if (padding.equals("PKCS5PADDING")) {
253
if (this.blockMode == MODE_CTR) {
254
throw new NoSuchPaddingException
255
("PKCS#5 padding not supported with CTR mode");
256
}
257
paddingType = PAD_PKCS5;
258
if (mechanism != CKM_DES_CBC_PAD && mechanism != CKM_DES3_CBC_PAD &&
259
mechanism != CKM_AES_CBC_PAD) {
260
// no native padding support; use our own padding impl
261
paddingObj = new PKCS5Padding(blockSize);
262
padBuffer = new byte[blockSize];
263
char[] tokenLabel = token.tokenInfo.label;
264
// NSS requires block-sized updates in multi-part operations.
265
reqBlockUpdates = ((tokenLabel[0] == 'N' && tokenLabel[1] == 'S'
266
&& tokenLabel[2] == 'S') ? true : false);
267
}
268
} else {
269
throw new NoSuchPaddingException("Unsupported padding " + padding);
270
}
271
}
272
273
// see JCE spec
274
protected int engineGetBlockSize() {
275
return blockSize;
276
}
277
278
// see JCE spec
279
protected int engineGetOutputSize(int inputLen) {
280
return doFinalLength(inputLen);
281
}
282
283
// see JCE spec
284
protected byte[] engineGetIV() {
285
return (iv == null) ? null : iv.clone();
286
}
287
288
// see JCE spec
289
protected AlgorithmParameters engineGetParameters() {
290
if (iv == null) {
291
return null;
292
}
293
IvParameterSpec ivSpec = new IvParameterSpec(iv);
294
try {
295
AlgorithmParameters params =
296
AlgorithmParameters.getInstance(keyAlgorithm,
297
P11Util.getSunJceProvider());
298
params.init(ivSpec);
299
return params;
300
} catch (GeneralSecurityException e) {
301
// NoSuchAlgorithmException, NoSuchProviderException
302
// InvalidParameterSpecException
303
throw new ProviderException("Could not encode parameters", e);
304
}
305
}
306
307
// see JCE spec
308
protected void engineInit(int opmode, Key key, SecureRandom random)
309
throws InvalidKeyException {
310
try {
311
implInit(opmode, key, null, random);
312
} catch (InvalidAlgorithmParameterException e) {
313
throw new InvalidKeyException("init() failed", e);
314
}
315
}
316
317
// see JCE spec
318
protected void engineInit(int opmode, Key key,
319
AlgorithmParameterSpec params, SecureRandom random)
320
throws InvalidKeyException, InvalidAlgorithmParameterException {
321
byte[] ivValue;
322
if (params != null) {
323
if (params instanceof IvParameterSpec == false) {
324
throw new InvalidAlgorithmParameterException
325
("Only IvParameterSpec supported");
326
}
327
IvParameterSpec ivSpec = (IvParameterSpec) params;
328
ivValue = ivSpec.getIV();
329
} else {
330
ivValue = null;
331
}
332
implInit(opmode, key, ivValue, random);
333
}
334
335
// see JCE spec
336
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
337
SecureRandom random)
338
throws InvalidKeyException, InvalidAlgorithmParameterException {
339
byte[] ivValue;
340
if (params != null) {
341
try {
342
IvParameterSpec ivSpec =
343
params.getParameterSpec(IvParameterSpec.class);
344
ivValue = ivSpec.getIV();
345
} catch (InvalidParameterSpecException e) {
346
throw new InvalidAlgorithmParameterException
347
("Could not decode IV", e);
348
}
349
} else {
350
ivValue = null;
351
}
352
implInit(opmode, key, ivValue, random);
353
}
354
355
// actual init() implementation
356
private void implInit(int opmode, Key key, byte[] iv,
357
SecureRandom random)
358
throws InvalidKeyException, InvalidAlgorithmParameterException {
359
reset(true);
360
if (fixedKeySize != -1 &&
361
((key instanceof P11Key) ? ((P11Key) key).length() >> 3 :
362
key.getEncoded().length) != fixedKeySize) {
363
throw new InvalidKeyException("Key size is invalid");
364
}
365
switch (opmode) {
366
case Cipher.ENCRYPT_MODE:
367
encrypt = true;
368
break;
369
case Cipher.DECRYPT_MODE:
370
encrypt = false;
371
break;
372
default:
373
throw new InvalidAlgorithmParameterException
374
("Unsupported mode: " + opmode);
375
}
376
if (blockMode == MODE_ECB) { // ECB or stream cipher
377
if (iv != null) {
378
if (blockSize == 0) {
379
throw new InvalidAlgorithmParameterException
380
("IV not used with stream ciphers");
381
} else {
382
throw new InvalidAlgorithmParameterException
383
("IV not used in ECB mode");
384
}
385
}
386
} else { // MODE_CBC or MODE_CTR
387
if (iv == null) {
388
if (encrypt == false) {
389
String exMsg =
390
(blockMode == MODE_CBC ?
391
"IV must be specified for decryption in CBC mode" :
392
"IV must be specified for decryption in CTR mode");
393
throw new InvalidAlgorithmParameterException(exMsg);
394
}
395
// generate random IV
396
if (random == null) {
397
random = JCAUtil.getSecureRandom();
398
}
399
iv = new byte[blockSize];
400
random.nextBytes(iv);
401
} else {
402
if (iv.length != blockSize) {
403
throw new InvalidAlgorithmParameterException
404
("IV length must match block size");
405
}
406
}
407
}
408
this.iv = iv;
409
p11Key = P11SecretKeyFactory.convertKey(token, key, keyAlgorithm);
410
try {
411
initialize();
412
} catch (PKCS11Exception e) {
413
throw new InvalidKeyException("Could not initialize cipher", e);
414
}
415
}
416
417
// reset the states to the pre-initialized values
418
// need to be called after doFinal or prior to re-init
419
private void reset(boolean doCancel) {
420
if (!initialized) {
421
return;
422
}
423
initialized = false;
424
425
try {
426
if (session == null) {
427
return;
428
}
429
430
if (doCancel && token.explicitCancel) {
431
cancelOperation();
432
}
433
} finally {
434
p11Key.releaseKeyID();
435
session = token.releaseSession(session);
436
bytesBuffered = 0;
437
padBufferLen = 0;
438
}
439
}
440
441
private void cancelOperation() {
442
token.ensureValid();
443
// cancel operation by finishing it; avoid killSession as some
444
// hardware vendors may require re-login
445
try {
446
int bufLen = doFinalLength(0);
447
byte[] buffer = new byte[bufLen];
448
if (encrypt) {
449
token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);
450
} else {
451
token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
452
}
453
} catch (PKCS11Exception e) {
454
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
455
// Cancel Operation may be invoked after an error on a PKCS#11
456
// call. If the operation inside the token was already cancelled,
457
// do not fail here. This is part of a defensive mechanism for
458
// PKCS#11 libraries that do not strictly follow the standard.
459
return;
460
}
461
if (encrypt) {
462
throw new ProviderException("Cancel failed", e);
463
}
464
// ignore failure for decryption
465
}
466
}
467
468
private void ensureInitialized() throws PKCS11Exception {
469
if (!initialized) {
470
initialize();
471
}
472
}
473
474
private void initialize() throws PKCS11Exception {
475
if (p11Key == null) {
476
throw new ProviderException(
477
"Operation cannot be performed without"
478
+ " calling engineInit first");
479
}
480
token.ensureValid();
481
long p11KeyID = p11Key.getKeyID();
482
try {
483
if (session == null) {
484
session = token.getOpSession();
485
}
486
CK_MECHANISM mechParams = (blockMode == MODE_CTR?
487
new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) :
488
new CK_MECHANISM(mechanism, iv));
489
if (encrypt) {
490
token.p11.C_EncryptInit(session.id(), mechParams, p11KeyID);
491
} else {
492
token.p11.C_DecryptInit(session.id(), mechParams, p11KeyID);
493
}
494
} catch (PKCS11Exception e) {
495
p11Key.releaseKeyID();
496
session = token.releaseSession(session);
497
throw e;
498
}
499
initialized = true;
500
bytesBuffered = 0;
501
padBufferLen = 0;
502
}
503
504
// if update(inLen) is called, how big does the output buffer have to be?
505
private int updateLength(int inLen) {
506
if (inLen <= 0) {
507
return 0;
508
}
509
510
int result = inLen + bytesBuffered;
511
if (blockSize != 0 && blockMode != MODE_CTR) {
512
// minus the number of bytes in the last incomplete block.
513
result -= (result & (blockSize - 1));
514
}
515
return result;
516
}
517
518
// if doFinal(inLen) is called, how big does the output buffer have to be?
519
private int doFinalLength(int inLen) {
520
if (inLen < 0) {
521
return 0;
522
}
523
524
int result = inLen + bytesBuffered;
525
if (blockSize != 0 && encrypt && paddingType != PAD_NONE) {
526
// add the number of bytes to make the last block complete.
527
result += (blockSize - (result & (blockSize - 1)));
528
}
529
return result;
530
}
531
532
// see JCE spec
533
protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
534
try {
535
byte[] out = new byte[updateLength(inLen)];
536
int n = engineUpdate(in, inOfs, inLen, out, 0);
537
return P11Util.convert(out, 0, n);
538
} catch (ShortBufferException e) {
539
// convert since the output length is calculated by updateLength()
540
throw new ProviderException(e);
541
}
542
}
543
544
// see JCE spec
545
protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
546
int outOfs) throws ShortBufferException {
547
int outLen = out.length - outOfs;
548
return implUpdate(in, inOfs, inLen, out, outOfs, outLen);
549
}
550
551
// see JCE spec
552
@Override
553
protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
554
throws ShortBufferException {
555
return implUpdate(inBuffer, outBuffer);
556
}
557
558
// see JCE spec
559
protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
560
throws IllegalBlockSizeException, BadPaddingException {
561
try {
562
byte[] out = new byte[doFinalLength(inLen)];
563
int n = engineDoFinal(in, inOfs, inLen, out, 0);
564
return P11Util.convert(out, 0, n);
565
} catch (ShortBufferException e) {
566
// convert since the output length is calculated by doFinalLength()
567
throw new ProviderException(e);
568
}
569
}
570
571
// see JCE spec
572
protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
573
int outOfs) throws ShortBufferException, IllegalBlockSizeException,
574
BadPaddingException {
575
int n = 0;
576
if ((inLen != 0) && (in != null)) {
577
n = engineUpdate(in, inOfs, inLen, out, outOfs);
578
outOfs += n;
579
}
580
n += implDoFinal(out, outOfs, out.length - outOfs);
581
return n;
582
}
583
584
// see JCE spec
585
@Override
586
protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
587
throws ShortBufferException, IllegalBlockSizeException,
588
BadPaddingException {
589
int n = engineUpdate(inBuffer, outBuffer);
590
n += implDoFinal(outBuffer);
591
return n;
592
}
593
594
private int implUpdate(byte[] in, int inOfs, int inLen,
595
byte[] out, int outOfs, int outLen) throws ShortBufferException {
596
if (outLen < updateLength(inLen)) {
597
throw new ShortBufferException();
598
}
599
try {
600
ensureInitialized();
601
int k = 0;
602
int newPadBufferLen = 0;
603
if (paddingObj != null && (!encrypt || reqBlockUpdates)) {
604
if (padBufferLen != 0) {
605
if (padBufferLen != padBuffer.length) {
606
int bufCapacity = padBuffer.length - padBufferLen;
607
if (inLen > bufCapacity) {
608
bufferInputBytes(in, inOfs, bufCapacity);
609
inOfs += bufCapacity;
610
inLen -= bufCapacity;
611
} else {
612
bufferInputBytes(in, inOfs, inLen);
613
return 0;
614
}
615
}
616
if (encrypt) {
617
k = token.p11.C_EncryptUpdate(session.id(),
618
0, padBuffer, 0, padBufferLen,
619
0, out, outOfs, outLen);
620
} else {
621
k = token.p11.C_DecryptUpdate(session.id(),
622
0, padBuffer, 0, padBufferLen,
623
0, out, outOfs, outLen);
624
}
625
padBufferLen = 0;
626
}
627
newPadBufferLen = inLen & (blockSize - 1);
628
if (!encrypt && newPadBufferLen == 0) {
629
// While decrypting with implUpdate, the last encrypted block
630
// is always held in a buffer. If it's the final one (unknown
631
// at this point), it may contain padding bytes and need further
632
// processing. In implDoFinal (where we know it's the final one)
633
// the buffer is decrypted, unpadded and returned.
634
newPadBufferLen = padBuffer.length;
635
}
636
inLen -= newPadBufferLen;
637
}
638
if (inLen > 0) {
639
if (encrypt) {
640
k += token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs,
641
inLen, 0, out, (outOfs + k), (outLen - k));
642
} else {
643
k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs,
644
inLen, 0, out, (outOfs + k), (outLen - k));
645
}
646
}
647
// update 'padBuffer' if using our own padding impl.
648
if (paddingObj != null && newPadBufferLen > 0) {
649
bufferInputBytes(in, inOfs + inLen, newPadBufferLen);
650
}
651
bytesBuffered += (inLen - k);
652
return k;
653
} catch (PKCS11Exception e) {
654
if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
655
throw (ShortBufferException)
656
(new ShortBufferException().initCause(e));
657
}
658
// Some implementations such as the NSS Software Token do not
659
// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate
660
// failure (as required by the PKCS#11 standard). See JDK-8258833
661
// for further information.
662
reset(true);
663
throw new ProviderException("update() failed", e);
664
}
665
}
666
667
private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
668
throws ShortBufferException {
669
int inLen = inBuffer.remaining();
670
if (inLen <= 0) {
671
return 0;
672
}
673
674
int outLen = outBuffer.remaining();
675
if (outLen < updateLength(inLen)) {
676
throw new ShortBufferException();
677
}
678
int origPos = inBuffer.position();
679
try {
680
ensureInitialized();
681
682
long inAddr = 0;
683
int inOfs = 0;
684
byte[] inArray = null;
685
686
if (inBuffer instanceof DirectBuffer) {
687
inAddr = ((DirectBuffer) inBuffer).address();
688
inOfs = origPos;
689
} else if (inBuffer.hasArray()) {
690
inArray = inBuffer.array();
691
inOfs = (origPos + inBuffer.arrayOffset());
692
}
693
694
long outAddr = 0;
695
int outOfs = 0;
696
byte[] outArray = null;
697
if (outBuffer instanceof DirectBuffer) {
698
outAddr = ((DirectBuffer) outBuffer).address();
699
outOfs = outBuffer.position();
700
} else {
701
if (outBuffer.hasArray()) {
702
outArray = outBuffer.array();
703
outOfs = (outBuffer.position() + outBuffer.arrayOffset());
704
} else {
705
outArray = new byte[outLen];
706
}
707
}
708
709
int k = 0;
710
int newPadBufferLen = 0;
711
if (paddingObj != null && (!encrypt || reqBlockUpdates)) {
712
if (padBufferLen != 0) {
713
if (padBufferLen != padBuffer.length) {
714
int bufCapacity = padBuffer.length - padBufferLen;
715
if (inLen > bufCapacity) {
716
bufferInputBytes(inBuffer, bufCapacity);
717
inOfs += bufCapacity;
718
inLen -= bufCapacity;
719
} else {
720
bufferInputBytes(inBuffer, inLen);
721
return 0;
722
}
723
}
724
if (encrypt) {
725
k = token.p11.C_EncryptUpdate(session.id(), 0,
726
padBuffer, 0, padBufferLen, outAddr, outArray,
727
outOfs, outLen);
728
} else {
729
k = token.p11.C_DecryptUpdate(session.id(), 0,
730
padBuffer, 0, padBufferLen, outAddr, outArray,
731
outOfs, outLen);
732
}
733
padBufferLen = 0;
734
}
735
newPadBufferLen = inLen & (blockSize - 1);
736
if (!encrypt && newPadBufferLen == 0) {
737
// While decrypting with implUpdate, the last encrypted block
738
// is always held in a buffer. If it's the final one (unknown
739
// at this point), it may contain padding bytes and need further
740
// processing. In implDoFinal (where we know it's the final one)
741
// the buffer is decrypted, unpadded and returned.
742
newPadBufferLen = padBuffer.length;
743
}
744
inLen -= newPadBufferLen;
745
}
746
if (inLen > 0) {
747
if (inAddr == 0 && inArray == null) {
748
inArray = new byte[inLen];
749
inBuffer.get(inArray);
750
} else {
751
inBuffer.position(inBuffer.position() + inLen);
752
}
753
if (encrypt) {
754
k += token.p11.C_EncryptUpdate(session.id(), inAddr,
755
inArray, inOfs, inLen, outAddr, outArray,
756
(outOfs + k), (outLen - k));
757
} else {
758
k += token.p11.C_DecryptUpdate(session.id(), inAddr,
759
inArray, inOfs, inLen, outAddr, outArray,
760
(outOfs + k), (outLen - k));
761
}
762
}
763
// update 'padBuffer' if using our own padding impl.
764
if (paddingObj != null && newPadBufferLen > 0) {
765
bufferInputBytes(inBuffer, newPadBufferLen);
766
}
767
bytesBuffered += (inLen - k);
768
if (!(outBuffer instanceof DirectBuffer) &&
769
!outBuffer.hasArray()) {
770
outBuffer.put(outArray, outOfs, k);
771
} else {
772
outBuffer.position(outBuffer.position() + k);
773
}
774
return k;
775
} catch (PKCS11Exception e) {
776
// Reset input buffer to its original position for
777
inBuffer.position(origPos);
778
if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
779
throw (ShortBufferException)
780
(new ShortBufferException().initCause(e));
781
}
782
// Some implementations such as the NSS Software Token do not
783
// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate
784
// failure (as required by the PKCS#11 standard). See JDK-8258833
785
// for further information.
786
reset(true);
787
throw new ProviderException("update() failed", e);
788
}
789
}
790
791
private int implDoFinal(byte[] out, int outOfs, int outLen)
792
throws ShortBufferException, IllegalBlockSizeException,
793
BadPaddingException {
794
int requiredOutLen = doFinalLength(0);
795
if (outLen < requiredOutLen) {
796
throw new ShortBufferException();
797
}
798
boolean doCancel = true;
799
try {
800
ensureInitialized();
801
int k = 0;
802
if (encrypt) {
803
if (paddingObj != null) {
804
int startOff = 0;
805
if (reqBlockUpdates) {
806
startOff = padBufferLen;
807
}
808
int actualPadLen = paddingObj.setPaddingBytes(padBuffer,
809
startOff, requiredOutLen - bytesBuffered);
810
k = token.p11.C_EncryptUpdate(session.id(),
811
0, padBuffer, 0, startOff + actualPadLen,
812
0, out, outOfs, outLen);
813
}
814
// Some implementations such as the NSS Software Token do not
815
// cancel the operation upon a C_EncryptUpdate failure (as
816
// required by the PKCS#11 standard). Cancel is not needed
817
// only after this point. See JDK-8258833 for further
818
// information.
819
doCancel = false;
820
k += token.p11.C_EncryptFinal(session.id(),
821
0, out, (outOfs + k), (outLen - k));
822
} else {
823
// Special handling to match SunJCE provider behavior
824
if (bytesBuffered == 0 && padBufferLen == 0) {
825
return 0;
826
}
827
if (paddingObj != null) {
828
if (padBufferLen != 0) {
829
k = token.p11.C_DecryptUpdate(session.id(), 0,
830
padBuffer, 0, padBufferLen, 0, padBuffer, 0,
831
padBuffer.length);
832
}
833
// Some implementations such as the NSS Software Token do not
834
// cancel the operation upon a C_DecryptUpdate failure (as
835
// required by the PKCS#11 standard). Cancel is not needed
836
// only after this point. See JDK-8258833 for further
837
// information.
838
doCancel = false;
839
k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,
840
padBuffer.length - k);
841
842
int actualPadLen = paddingObj.unpad(padBuffer, k);
843
k -= actualPadLen;
844
System.arraycopy(padBuffer, 0, out, outOfs, k);
845
} else {
846
doCancel = false;
847
k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,
848
outLen);
849
}
850
}
851
return k;
852
} catch (PKCS11Exception e) {
853
handleException(e);
854
throw new ProviderException("doFinal() failed", e);
855
} finally {
856
reset(doCancel);
857
}
858
}
859
860
private int implDoFinal(ByteBuffer outBuffer)
861
throws ShortBufferException, IllegalBlockSizeException,
862
BadPaddingException {
863
int outLen = outBuffer.remaining();
864
int requiredOutLen = doFinalLength(0);
865
if (outLen < requiredOutLen) {
866
throw new ShortBufferException();
867
}
868
869
boolean doCancel = true;
870
try {
871
ensureInitialized();
872
873
long outAddr = 0;
874
byte[] outArray = null;
875
int outOfs = 0;
876
if (outBuffer instanceof DirectBuffer) {
877
outAddr = ((DirectBuffer) outBuffer).address();
878
outOfs = outBuffer.position();
879
} else {
880
if (outBuffer.hasArray()) {
881
outArray = outBuffer.array();
882
outOfs = outBuffer.position() + outBuffer.arrayOffset();
883
} else {
884
outArray = new byte[outLen];
885
}
886
}
887
888
int k = 0;
889
890
if (encrypt) {
891
if (paddingObj != null) {
892
int startOff = 0;
893
if (reqBlockUpdates) {
894
startOff = padBufferLen;
895
}
896
int actualPadLen = paddingObj.setPaddingBytes(padBuffer,
897
startOff, requiredOutLen - bytesBuffered);
898
k = token.p11.C_EncryptUpdate(session.id(),
899
0, padBuffer, 0, startOff + actualPadLen,
900
outAddr, outArray, outOfs, outLen);
901
}
902
// Some implementations such as the NSS Software Token do not
903
// cancel the operation upon a C_EncryptUpdate failure (as
904
// required by the PKCS#11 standard). Cancel is not needed
905
// only after this point. See JDK-8258833 for further
906
// information.
907
doCancel = false;
908
k += token.p11.C_EncryptFinal(session.id(),
909
outAddr, outArray, (outOfs + k), (outLen - k));
910
} else {
911
// Special handling to match SunJCE provider behavior
912
if (bytesBuffered == 0 && padBufferLen == 0) {
913
return 0;
914
}
915
916
if (paddingObj != null) {
917
if (padBufferLen != 0) {
918
k = token.p11.C_DecryptUpdate(session.id(),
919
0, padBuffer, 0, padBufferLen,
920
0, padBuffer, 0, padBuffer.length);
921
padBufferLen = 0;
922
}
923
// Some implementations such as the NSS Software Token do not
924
// cancel the operation upon a C_DecryptUpdate failure (as
925
// required by the PKCS#11 standard). Cancel is not needed
926
// only after this point. See JDK-8258833 for further
927
// information.
928
doCancel = false;
929
k += token.p11.C_DecryptFinal(session.id(),
930
0, padBuffer, k, padBuffer.length - k);
931
932
int actualPadLen = paddingObj.unpad(padBuffer, k);
933
k -= actualPadLen;
934
outArray = padBuffer;
935
outOfs = 0;
936
} else {
937
doCancel = false;
938
k = token.p11.C_DecryptFinal(session.id(),
939
outAddr, outArray, outOfs, outLen);
940
}
941
}
942
if ((!encrypt && paddingObj != null) ||
943
(!(outBuffer instanceof DirectBuffer) &&
944
!outBuffer.hasArray())) {
945
outBuffer.put(outArray, outOfs, k);
946
} else {
947
outBuffer.position(outBuffer.position() + k);
948
}
949
return k;
950
} catch (PKCS11Exception e) {
951
handleException(e);
952
throw new ProviderException("doFinal() failed", e);
953
} finally {
954
reset(doCancel);
955
}
956
}
957
958
private void handleException(PKCS11Exception e)
959
throws ShortBufferException, IllegalBlockSizeException {
960
long errorCode = e.getErrorCode();
961
if (errorCode == CKR_BUFFER_TOO_SMALL) {
962
throw (ShortBufferException)
963
(new ShortBufferException().initCause(e));
964
} else if (errorCode == CKR_DATA_LEN_RANGE ||
965
errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) {
966
throw (IllegalBlockSizeException)
967
(new IllegalBlockSizeException(e.toString()).initCause(e));
968
}
969
}
970
971
// see JCE spec
972
protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,
973
InvalidKeyException {
974
// XXX key wrapping
975
throw new UnsupportedOperationException("engineWrap()");
976
}
977
978
// see JCE spec
979
protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
980
int wrappedKeyType)
981
throws InvalidKeyException, NoSuchAlgorithmException {
982
// XXX key unwrapping
983
throw new UnsupportedOperationException("engineUnwrap()");
984
}
985
986
// see JCE spec
987
@Override
988
protected int engineGetKeySize(Key key) throws InvalidKeyException {
989
int n = P11SecretKeyFactory.convertKey
990
(token, key, keyAlgorithm).length();
991
return n;
992
}
993
994
private final void bufferInputBytes(byte[] in, int inOfs, int len) {
995
System.arraycopy(in, inOfs, padBuffer, padBufferLen, len);
996
padBufferLen += len;
997
bytesBuffered += len;
998
}
999
1000
private final void bufferInputBytes(ByteBuffer inBuffer, int len) {
1001
inBuffer.get(padBuffer, padBufferLen, len);
1002
padBufferLen += len;
1003
bytesBuffered += len;
1004
}
1005
}
1006
1007