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