Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Cipher.java
41154 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
// falg 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
default:
374
throw new InvalidAlgorithmParameterException
375
("Unsupported mode: " + opmode);
376
}
377
if (blockMode == MODE_ECB) { // ECB or stream cipher
378
if (iv != null) {
379
if (blockSize == 0) {
380
throw new InvalidAlgorithmParameterException
381
("IV not used with stream ciphers");
382
} else {
383
throw new InvalidAlgorithmParameterException
384
("IV not used in ECB mode");
385
}
386
}
387
} else { // MODE_CBC or MODE_CTR
388
if (iv == null) {
389
if (encrypt == false) {
390
String exMsg =
391
(blockMode == MODE_CBC ?
392
"IV must be specified for decryption in CBC mode" :
393
"IV must be specified for decryption in CTR mode");
394
throw new InvalidAlgorithmParameterException(exMsg);
395
}
396
// generate random IV
397
if (random == null) {
398
random = JCAUtil.getSecureRandom();
399
}
400
iv = new byte[blockSize];
401
random.nextBytes(iv);
402
} else {
403
if (iv.length != blockSize) {
404
throw new InvalidAlgorithmParameterException
405
("IV length must match block size");
406
}
407
}
408
}
409
this.iv = iv;
410
p11Key = P11SecretKeyFactory.convertKey(token, key, keyAlgorithm);
411
try {
412
initialize();
413
} catch (PKCS11Exception e) {
414
throw new InvalidKeyException("Could not initialize cipher", e);
415
}
416
}
417
418
// reset the states to the pre-initialized values
419
// need to be called after doFinal or prior to re-init
420
private void reset(boolean doCancel) {
421
if (!initialized) {
422
return;
423
}
424
initialized = false;
425
426
try {
427
if (session == null) {
428
return;
429
}
430
431
if (doCancel && token.explicitCancel) {
432
cancelOperation();
433
}
434
} finally {
435
p11Key.releaseKeyID();
436
session = token.releaseSession(session);
437
bytesBuffered = 0;
438
padBufferLen = 0;
439
}
440
}
441
442
private void cancelOperation() {
443
token.ensureValid();
444
// cancel operation by finishing it; avoid killSession as some
445
// hardware vendors may require re-login
446
try {
447
int bufLen = doFinalLength(0);
448
byte[] buffer = new byte[bufLen];
449
if (encrypt) {
450
token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);
451
} else {
452
token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
453
}
454
} catch (PKCS11Exception e) {
455
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
456
// Cancel Operation may be invoked after an error on a PKCS#11
457
// call. If the operation inside the token was already cancelled,
458
// do not fail here. This is part of a defensive mechanism for
459
// PKCS#11 libraries that do not strictly follow the standard.
460
return;
461
}
462
if (encrypt) {
463
throw new ProviderException("Cancel failed", e);
464
}
465
// ignore failure for decryption
466
}
467
}
468
469
private void ensureInitialized() throws PKCS11Exception {
470
if (!initialized) {
471
initialize();
472
}
473
}
474
475
private void initialize() throws PKCS11Exception {
476
if (p11Key == null) {
477
throw new ProviderException(
478
"Operation cannot be performed without"
479
+ " calling engineInit first");
480
}
481
token.ensureValid();
482
long p11KeyID = p11Key.getKeyID();
483
try {
484
if (session == null) {
485
session = token.getOpSession();
486
}
487
CK_MECHANISM mechParams = (blockMode == MODE_CTR?
488
new CK_MECHANISM(mechanism, new CK_AES_CTR_PARAMS(iv)) :
489
new CK_MECHANISM(mechanism, iv));
490
if (encrypt) {
491
token.p11.C_EncryptInit(session.id(), mechParams, p11KeyID);
492
} else {
493
token.p11.C_DecryptInit(session.id(), mechParams, p11KeyID);
494
}
495
} catch (PKCS11Exception e) {
496
p11Key.releaseKeyID();
497
session = token.releaseSession(session);
498
throw e;
499
}
500
initialized = true;
501
bytesBuffered = 0;
502
padBufferLen = 0;
503
}
504
505
// if update(inLen) is called, how big does the output buffer have to be?
506
private int updateLength(int inLen) {
507
if (inLen <= 0) {
508
return 0;
509
}
510
511
int result = inLen + bytesBuffered;
512
if (blockSize != 0 && blockMode != MODE_CTR) {
513
// minus the number of bytes in the last incomplete block.
514
result -= (result & (blockSize - 1));
515
}
516
return result;
517
}
518
519
// if doFinal(inLen) is called, how big does the output buffer have to be?
520
private int doFinalLength(int inLen) {
521
if (inLen < 0) {
522
return 0;
523
}
524
525
int result = inLen + bytesBuffered;
526
if (blockSize != 0 && encrypt && paddingType != PAD_NONE) {
527
// add the number of bytes to make the last block complete.
528
result += (blockSize - (result & (blockSize - 1)));
529
}
530
return result;
531
}
532
533
// see JCE spec
534
protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
535
try {
536
byte[] out = new byte[updateLength(inLen)];
537
int n = engineUpdate(in, inOfs, inLen, out, 0);
538
return P11Util.convert(out, 0, n);
539
} catch (ShortBufferException e) {
540
// convert since the output length is calculated by updateLength()
541
throw new ProviderException(e);
542
}
543
}
544
545
// see JCE spec
546
protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
547
int outOfs) throws ShortBufferException {
548
int outLen = out.length - outOfs;
549
return implUpdate(in, inOfs, inLen, out, outOfs, outLen);
550
}
551
552
// see JCE spec
553
@Override
554
protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
555
throws ShortBufferException {
556
return implUpdate(inBuffer, outBuffer);
557
}
558
559
// see JCE spec
560
protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
561
throws IllegalBlockSizeException, BadPaddingException {
562
try {
563
byte[] out = new byte[doFinalLength(inLen)];
564
int n = engineDoFinal(in, inOfs, inLen, out, 0);
565
return P11Util.convert(out, 0, n);
566
} catch (ShortBufferException e) {
567
// convert since the output length is calculated by doFinalLength()
568
throw new ProviderException(e);
569
}
570
}
571
572
// see JCE spec
573
protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
574
int outOfs) throws ShortBufferException, IllegalBlockSizeException,
575
BadPaddingException {
576
int n = 0;
577
if ((inLen != 0) && (in != null)) {
578
n = engineUpdate(in, inOfs, inLen, out, outOfs);
579
outOfs += n;
580
}
581
n += implDoFinal(out, outOfs, out.length - outOfs);
582
return n;
583
}
584
585
// see JCE spec
586
@Override
587
protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
588
throws ShortBufferException, IllegalBlockSizeException,
589
BadPaddingException {
590
int n = engineUpdate(inBuffer, outBuffer);
591
n += implDoFinal(outBuffer);
592
return n;
593
}
594
595
private int implUpdate(byte[] in, int inOfs, int inLen,
596
byte[] out, int outOfs, int outLen) throws ShortBufferException {
597
if (outLen < updateLength(inLen)) {
598
throw new ShortBufferException();
599
}
600
try {
601
ensureInitialized();
602
int k = 0;
603
int newPadBufferLen = 0;
604
if (paddingObj != null && (!encrypt || reqBlockUpdates)) {
605
if (padBufferLen != 0) {
606
if (padBufferLen != padBuffer.length) {
607
int bufCapacity = padBuffer.length - padBufferLen;
608
if (inLen > bufCapacity) {
609
bufferInputBytes(in, inOfs, bufCapacity);
610
inOfs += bufCapacity;
611
inLen -= bufCapacity;
612
} else {
613
bufferInputBytes(in, inOfs, inLen);
614
return 0;
615
}
616
}
617
if (encrypt) {
618
k = token.p11.C_EncryptUpdate(session.id(),
619
0, padBuffer, 0, padBufferLen,
620
0, out, outOfs, outLen);
621
} else {
622
k = token.p11.C_DecryptUpdate(session.id(),
623
0, padBuffer, 0, padBufferLen,
624
0, out, outOfs, outLen);
625
}
626
padBufferLen = 0;
627
}
628
newPadBufferLen = inLen & (blockSize - 1);
629
if (!encrypt && newPadBufferLen == 0) {
630
// While decrypting with implUpdate, the last encrypted block
631
// is always held in a buffer. If it's the final one (unknown
632
// at this point), it may contain padding bytes and need further
633
// processing. In implDoFinal (where we know it's the final one)
634
// the buffer is decrypted, unpadded and returned.
635
newPadBufferLen = padBuffer.length;
636
}
637
inLen -= newPadBufferLen;
638
}
639
if (inLen > 0) {
640
if (encrypt) {
641
k += token.p11.C_EncryptUpdate(session.id(), 0, in, inOfs,
642
inLen, 0, out, (outOfs + k), (outLen - k));
643
} else {
644
k += token.p11.C_DecryptUpdate(session.id(), 0, in, inOfs,
645
inLen, 0, out, (outOfs + k), (outLen - k));
646
}
647
}
648
// update 'padBuffer' if using our own padding impl.
649
if (paddingObj != null && newPadBufferLen > 0) {
650
bufferInputBytes(in, inOfs + inLen, newPadBufferLen);
651
}
652
bytesBuffered += (inLen - k);
653
return k;
654
} catch (PKCS11Exception e) {
655
if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
656
throw (ShortBufferException)
657
(new ShortBufferException().initCause(e));
658
}
659
// Some implementations such as the NSS Software Token do not
660
// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate
661
// failure (as required by the PKCS#11 standard). See JDK-8258833
662
// for further information.
663
reset(true);
664
throw new ProviderException("update() failed", e);
665
}
666
}
667
668
private int implUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
669
throws ShortBufferException {
670
int inLen = inBuffer.remaining();
671
if (inLen <= 0) {
672
return 0;
673
}
674
675
int outLen = outBuffer.remaining();
676
if (outLen < updateLength(inLen)) {
677
throw new ShortBufferException();
678
}
679
int origPos = inBuffer.position();
680
try {
681
ensureInitialized();
682
683
long inAddr = 0;
684
int inOfs = 0;
685
byte[] inArray = null;
686
687
if (inBuffer instanceof DirectBuffer) {
688
inAddr = ((DirectBuffer) inBuffer).address();
689
inOfs = origPos;
690
} else if (inBuffer.hasArray()) {
691
inArray = inBuffer.array();
692
inOfs = (origPos + inBuffer.arrayOffset());
693
}
694
695
long outAddr = 0;
696
int outOfs = 0;
697
byte[] outArray = null;
698
if (outBuffer instanceof DirectBuffer) {
699
outAddr = ((DirectBuffer) outBuffer).address();
700
outOfs = outBuffer.position();
701
} else {
702
if (outBuffer.hasArray()) {
703
outArray = outBuffer.array();
704
outOfs = (outBuffer.position() + outBuffer.arrayOffset());
705
} else {
706
outArray = new byte[outLen];
707
}
708
}
709
710
int k = 0;
711
int newPadBufferLen = 0;
712
if (paddingObj != null && (!encrypt || reqBlockUpdates)) {
713
if (padBufferLen != 0) {
714
if (padBufferLen != padBuffer.length) {
715
int bufCapacity = padBuffer.length - padBufferLen;
716
if (inLen > bufCapacity) {
717
bufferInputBytes(inBuffer, bufCapacity);
718
inOfs += bufCapacity;
719
inLen -= bufCapacity;
720
} else {
721
bufferInputBytes(inBuffer, inLen);
722
return 0;
723
}
724
}
725
if (encrypt) {
726
k = token.p11.C_EncryptUpdate(session.id(), 0,
727
padBuffer, 0, padBufferLen, outAddr, outArray,
728
outOfs, outLen);
729
} else {
730
k = token.p11.C_DecryptUpdate(session.id(), 0,
731
padBuffer, 0, padBufferLen, outAddr, outArray,
732
outOfs, outLen);
733
}
734
padBufferLen = 0;
735
}
736
newPadBufferLen = inLen & (blockSize - 1);
737
if (!encrypt && newPadBufferLen == 0) {
738
// While decrypting with implUpdate, the last encrypted block
739
// is always held in a buffer. If it's the final one (unknown
740
// at this point), it may contain padding bytes and need further
741
// processing. In implDoFinal (where we know it's the final one)
742
// the buffer is decrypted, unpadded and returned.
743
newPadBufferLen = padBuffer.length;
744
}
745
inLen -= newPadBufferLen;
746
}
747
if (inLen > 0) {
748
if (inAddr == 0 && inArray == null) {
749
inArray = new byte[inLen];
750
inBuffer.get(inArray);
751
} else {
752
inBuffer.position(inBuffer.position() + inLen);
753
}
754
if (encrypt) {
755
k += token.p11.C_EncryptUpdate(session.id(), inAddr,
756
inArray, inOfs, inLen, outAddr, outArray,
757
(outOfs + k), (outLen - k));
758
} else {
759
k += token.p11.C_DecryptUpdate(session.id(), inAddr,
760
inArray, inOfs, inLen, outAddr, outArray,
761
(outOfs + k), (outLen - k));
762
}
763
}
764
// update 'padBuffer' if using our own padding impl.
765
if (paddingObj != null && newPadBufferLen > 0) {
766
bufferInputBytes(inBuffer, newPadBufferLen);
767
}
768
bytesBuffered += (inLen - k);
769
if (!(outBuffer instanceof DirectBuffer) &&
770
!outBuffer.hasArray()) {
771
outBuffer.put(outArray, outOfs, k);
772
} else {
773
outBuffer.position(outBuffer.position() + k);
774
}
775
return k;
776
} catch (PKCS11Exception e) {
777
// Reset input buffer to its original position for
778
inBuffer.position(origPos);
779
if (e.getErrorCode() == CKR_BUFFER_TOO_SMALL) {
780
throw (ShortBufferException)
781
(new ShortBufferException().initCause(e));
782
}
783
// Some implementations such as the NSS Software Token do not
784
// cancel the operation upon a C_EncryptUpdate/C_DecryptUpdate
785
// failure (as required by the PKCS#11 standard). See JDK-8258833
786
// for further information.
787
reset(true);
788
throw new ProviderException("update() failed", e);
789
}
790
}
791
792
private int implDoFinal(byte[] out, int outOfs, int outLen)
793
throws ShortBufferException, IllegalBlockSizeException,
794
BadPaddingException {
795
int requiredOutLen = doFinalLength(0);
796
if (outLen < requiredOutLen) {
797
throw new ShortBufferException();
798
}
799
boolean doCancel = true;
800
try {
801
ensureInitialized();
802
int k = 0;
803
if (encrypt) {
804
if (paddingObj != null) {
805
int startOff = 0;
806
if (reqBlockUpdates) {
807
startOff = padBufferLen;
808
}
809
int actualPadLen = paddingObj.setPaddingBytes(padBuffer,
810
startOff, requiredOutLen - bytesBuffered);
811
k = token.p11.C_EncryptUpdate(session.id(),
812
0, padBuffer, 0, startOff + actualPadLen,
813
0, out, outOfs, outLen);
814
}
815
// Some implementations such as the NSS Software Token do not
816
// cancel the operation upon a C_EncryptUpdate failure (as
817
// required by the PKCS#11 standard). Cancel is not needed
818
// only after this point. See JDK-8258833 for further
819
// information.
820
doCancel = false;
821
k += token.p11.C_EncryptFinal(session.id(),
822
0, out, (outOfs + k), (outLen - k));
823
} else {
824
// Special handling to match SunJCE provider behavior
825
if (bytesBuffered == 0 && padBufferLen == 0) {
826
return 0;
827
}
828
if (paddingObj != null) {
829
if (padBufferLen != 0) {
830
k = token.p11.C_DecryptUpdate(session.id(), 0,
831
padBuffer, 0, padBufferLen, 0, padBuffer, 0,
832
padBuffer.length);
833
}
834
// Some implementations such as the NSS Software Token do not
835
// cancel the operation upon a C_DecryptUpdate failure (as
836
// required by the PKCS#11 standard). Cancel is not needed
837
// only after this point. See JDK-8258833 for further
838
// information.
839
doCancel = false;
840
k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,
841
padBuffer.length - k);
842
843
int actualPadLen = paddingObj.unpad(padBuffer, k);
844
k -= actualPadLen;
845
System.arraycopy(padBuffer, 0, out, outOfs, k);
846
} else {
847
doCancel = false;
848
k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,
849
outLen);
850
}
851
}
852
return k;
853
} catch (PKCS11Exception e) {
854
handleException(e);
855
throw new ProviderException("doFinal() failed", e);
856
} finally {
857
reset(doCancel);
858
}
859
}
860
861
private int implDoFinal(ByteBuffer outBuffer)
862
throws ShortBufferException, IllegalBlockSizeException,
863
BadPaddingException {
864
int outLen = outBuffer.remaining();
865
int requiredOutLen = doFinalLength(0);
866
if (outLen < requiredOutLen) {
867
throw new ShortBufferException();
868
}
869
870
boolean doCancel = true;
871
try {
872
ensureInitialized();
873
874
long outAddr = 0;
875
byte[] outArray = null;
876
int outOfs = 0;
877
if (outBuffer instanceof DirectBuffer) {
878
outAddr = ((DirectBuffer) outBuffer).address();
879
outOfs = outBuffer.position();
880
} else {
881
if (outBuffer.hasArray()) {
882
outArray = outBuffer.array();
883
outOfs = outBuffer.position() + outBuffer.arrayOffset();
884
} else {
885
outArray = new byte[outLen];
886
}
887
}
888
889
int k = 0;
890
891
if (encrypt) {
892
if (paddingObj != null) {
893
int startOff = 0;
894
if (reqBlockUpdates) {
895
startOff = padBufferLen;
896
}
897
int actualPadLen = paddingObj.setPaddingBytes(padBuffer,
898
startOff, requiredOutLen - bytesBuffered);
899
k = token.p11.C_EncryptUpdate(session.id(),
900
0, padBuffer, 0, startOff + actualPadLen,
901
outAddr, outArray, outOfs, outLen);
902
}
903
// Some implementations such as the NSS Software Token do not
904
// cancel the operation upon a C_EncryptUpdate failure (as
905
// required by the PKCS#11 standard). Cancel is not needed
906
// only after this point. See JDK-8258833 for further
907
// information.
908
doCancel = false;
909
k += token.p11.C_EncryptFinal(session.id(),
910
outAddr, outArray, (outOfs + k), (outLen - k));
911
} else {
912
// Special handling to match SunJCE provider behavior
913
if (bytesBuffered == 0 && padBufferLen == 0) {
914
return 0;
915
}
916
917
if (paddingObj != null) {
918
if (padBufferLen != 0) {
919
k = token.p11.C_DecryptUpdate(session.id(),
920
0, padBuffer, 0, padBufferLen,
921
0, padBuffer, 0, padBuffer.length);
922
padBufferLen = 0;
923
}
924
// Some implementations such as the NSS Software Token do not
925
// cancel the operation upon a C_DecryptUpdate failure (as
926
// required by the PKCS#11 standard). Cancel is not needed
927
// only after this point. See JDK-8258833 for further
928
// information.
929
doCancel = false;
930
k += token.p11.C_DecryptFinal(session.id(),
931
0, padBuffer, k, padBuffer.length - k);
932
933
int actualPadLen = paddingObj.unpad(padBuffer, k);
934
k -= actualPadLen;
935
outArray = padBuffer;
936
outOfs = 0;
937
} else {
938
doCancel = false;
939
k = token.p11.C_DecryptFinal(session.id(),
940
outAddr, outArray, outOfs, outLen);
941
}
942
}
943
if ((!encrypt && paddingObj != null) ||
944
(!(outBuffer instanceof DirectBuffer) &&
945
!outBuffer.hasArray())) {
946
outBuffer.put(outArray, outOfs, k);
947
} else {
948
outBuffer.position(outBuffer.position() + k);
949
}
950
return k;
951
} catch (PKCS11Exception e) {
952
handleException(e);
953
throw new ProviderException("doFinal() failed", e);
954
} finally {
955
reset(doCancel);
956
}
957
}
958
959
private void handleException(PKCS11Exception e)
960
throws ShortBufferException, IllegalBlockSizeException {
961
long errorCode = e.getErrorCode();
962
if (errorCode == CKR_BUFFER_TOO_SMALL) {
963
throw (ShortBufferException)
964
(new ShortBufferException().initCause(e));
965
} else if (errorCode == CKR_DATA_LEN_RANGE ||
966
errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) {
967
throw (IllegalBlockSizeException)
968
(new IllegalBlockSizeException(e.toString()).initCause(e));
969
}
970
}
971
972
// see JCE spec
973
protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,
974
InvalidKeyException {
975
// XXX key wrapping
976
throw new UnsupportedOperationException("engineWrap()");
977
}
978
979
// see JCE spec
980
protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
981
int wrappedKeyType)
982
throws InvalidKeyException, NoSuchAlgorithmException {
983
// XXX key unwrapping
984
throw new UnsupportedOperationException("engineUnwrap()");
985
}
986
987
// see JCE spec
988
@Override
989
protected int engineGetKeySize(Key key) throws InvalidKeyException {
990
int n = P11SecretKeyFactory.convertKey
991
(token, key, keyAlgorithm).length();
992
return n;
993
}
994
995
private final void bufferInputBytes(byte[] in, int inOfs, int len) {
996
System.arraycopy(in, inOfs, padBuffer, padBufferLen, len);
997
padBufferLen += len;
998
bytesBuffered += len;
999
}
1000
1001
private final void bufferInputBytes(ByteBuffer inBuffer, int len) {
1002
inBuffer.get(padBuffer, padBufferLen, len);
1003
padBufferLen += len;
1004
bytesBuffered += len;
1005
}
1006
}
1007
1008