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/P11AEADCipher.java
41154 views
1
/*
2
* Copyright (c) 2019, 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.io.ByteArrayOutputStream;
28
import java.nio.ByteBuffer;
29
import java.util.Arrays;
30
import java.util.Locale;
31
32
import java.security.*;
33
import java.security.spec.*;
34
35
import javax.crypto.*;
36
import javax.crypto.spec.*;
37
38
import sun.nio.ch.DirectBuffer;
39
import sun.security.jca.JCAUtil;
40
import sun.security.pkcs11.wrapper.*;
41
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
42
import static sun.security.pkcs11.wrapper.PKCS11Exception.*;
43
44
/**
45
* P11 AEAD Cipher implementation class. This class currently supports
46
* AES cipher in GCM mode and CHACHA20-POLY1305 cipher.
47
*
48
* Note that AEAD modes do not use padding, so this class does not have
49
* its own padding impl. In addition, some vendors such as NSS may not support
50
* multi-part encryption/decryption for AEAD cipher algorithms, thus the
51
* current impl uses PKCS#11 C_Encrypt/C_Decrypt calls and buffers data until
52
* doFinal is called.
53
*
54
* @since 13
55
*/
56
final class P11AEADCipher extends CipherSpi {
57
58
// supported AEAD algorithms/transformations
59
private enum Transformation {
60
AES_GCM("AES", "GCM", "NOPADDING", 16, 16),
61
CHACHA20_POLY1305("CHACHA20", "NONE", "NOPADDING", 12, 16);
62
63
final String keyAlgo;
64
final String mode;
65
final String padding;
66
final int defIvLen; // in bytes
67
final int defTagLen; // in bytes
68
69
Transformation(String keyAlgo, String mode, String padding,
70
int defIvLen, int defTagLen) {
71
this.keyAlgo = keyAlgo;
72
this.mode = mode;
73
this.padding = padding;
74
this.defIvLen = defIvLen;
75
this.defTagLen = defTagLen;
76
}
77
}
78
79
// token instance
80
private final Token token;
81
82
// mechanism id
83
private final long mechanism;
84
85
// type of this AEAD cipher, one of Transformation enum above
86
private final Transformation type;
87
88
// acceptable key size in bytes, -1 if more than 1 key sizes are accepted
89
private final int fixedKeySize;
90
91
// associated session, if any
92
private Session session = null;
93
94
// key, if init() was called
95
private P11Key p11Key = null;
96
97
// flag indicating whether an operation is initialized
98
private boolean initialized = false;
99
100
// falg indicating encrypt or decrypt mode
101
private boolean encrypt = true;
102
103
// parameters
104
private byte[] iv = null;
105
private int tagLen = -1;
106
private SecureRandom random = JCAUtil.getSecureRandom();
107
108
// dataBuffer is cleared upon doFinal calls
109
private ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream();
110
// aadBuffer is cleared upon successful init calls
111
private ByteArrayOutputStream aadBuffer = new ByteArrayOutputStream();
112
private boolean updateCalled = false;
113
114
private boolean requireReinit = false;
115
private P11Key lastEncKey = null;
116
private byte[] lastEncIv = null;
117
118
P11AEADCipher(Token token, String algorithm, long mechanism)
119
throws PKCS11Exception, NoSuchAlgorithmException {
120
super();
121
this.token = token;
122
this.mechanism = mechanism;
123
124
String[] algoParts = algorithm.split("/");
125
if (algoParts[0].startsWith("AES")) {
126
// for AES_GCM, need 3 parts
127
if (algoParts.length != 3) {
128
throw new AssertionError("Invalid Transformation format: " +
129
algorithm);
130
}
131
int index = algoParts[0].indexOf('_');
132
if (index != -1) {
133
// should be well-formed since we specify what we support
134
fixedKeySize = Integer.parseInt(algoParts[0].substring(index+1)) >> 3;
135
} else {
136
fixedKeySize = -1;
137
}
138
this.type = Transformation.AES_GCM;
139
engineSetMode(algoParts[1]);
140
try {
141
engineSetPadding(algoParts[2]);
142
} catch (NoSuchPaddingException e) {
143
throw new NoSuchAlgorithmException();
144
}
145
} else if (algoParts[0].equals("ChaCha20-Poly1305")) {
146
fixedKeySize = 32;
147
this.type = Transformation.CHACHA20_POLY1305;
148
if (algoParts.length > 3) {
149
throw new AssertionError(
150
"Invalid Transformation format: " + algorithm);
151
} else {
152
if (algoParts.length > 1) {
153
engineSetMode(algoParts[1]);
154
}
155
try {
156
if (algoParts.length > 2) {
157
engineSetPadding(algoParts[2]);
158
}
159
} catch (NoSuchPaddingException e) {
160
throw new NoSuchAlgorithmException();
161
}
162
}
163
} else {
164
throw new AssertionError("Unsupported transformation " + algorithm);
165
}
166
}
167
168
@Override
169
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
170
if (!mode.toUpperCase(Locale.ENGLISH).equals(type.mode)) {
171
throw new NoSuchAlgorithmException("Unsupported mode " + mode);
172
}
173
}
174
175
// see JCE spec
176
@Override
177
protected void engineSetPadding(String padding)
178
throws NoSuchPaddingException {
179
if (!padding.toUpperCase(Locale.ENGLISH).equals(type.padding)) {
180
throw new NoSuchPaddingException("Unsupported padding " + padding);
181
}
182
}
183
184
// see JCE spec
185
@Override
186
protected int engineGetBlockSize() {
187
return switch (type) {
188
case AES_GCM -> 16;
189
case CHACHA20_POLY1305 -> 0;
190
default -> throw new AssertionError("Unsupported type " + type);
191
};
192
}
193
194
// see JCE spec
195
@Override
196
protected int engineGetOutputSize(int inputLen) {
197
return doFinalLength(inputLen);
198
}
199
200
// see JCE spec
201
@Override
202
protected byte[] engineGetIV() {
203
return (iv == null) ? null : iv.clone();
204
}
205
206
// see JCE spec
207
protected AlgorithmParameters engineGetParameters() {
208
String apAlgo;
209
AlgorithmParameterSpec spec = null;
210
switch (type) {
211
case AES_GCM:
212
apAlgo = "GCM";
213
if (encrypt && iv == null && tagLen == -1) {
214
iv = new byte[type.defIvLen];
215
tagLen = type.defTagLen;
216
random.nextBytes(iv);
217
}
218
if (iv != null) {
219
spec = new GCMParameterSpec(tagLen << 3, iv);
220
}
221
break;
222
case CHACHA20_POLY1305:
223
if (encrypt && iv == null) {
224
iv = new byte[type.defIvLen];
225
random.nextBytes(iv);
226
}
227
apAlgo = "ChaCha20-Poly1305";
228
if (iv != null) {
229
spec = new IvParameterSpec(iv);
230
}
231
break;
232
default:
233
throw new AssertionError("Unsupported type " + type);
234
}
235
if (spec != null) {
236
try {
237
AlgorithmParameters params =
238
AlgorithmParameters.getInstance(apAlgo);
239
params.init(spec);
240
return params;
241
} catch (GeneralSecurityException e) {
242
// NoSuchAlgorithmException, NoSuchProviderException
243
// InvalidParameterSpecException
244
throw new ProviderException("Could not encode parameters", e);
245
}
246
}
247
return null;
248
}
249
250
// see JCE spec
251
protected void engineInit(int opmode, Key key, SecureRandom sr)
252
throws InvalidKeyException {
253
if (opmode == Cipher.DECRYPT_MODE) {
254
throw new InvalidKeyException("Parameters required for decryption");
255
}
256
updateCalled = false;
257
try {
258
implInit(opmode, key, null, -1, sr);
259
} catch (InvalidAlgorithmParameterException e) {
260
throw new InvalidKeyException("init() failed", e);
261
}
262
}
263
264
// see JCE spec
265
protected void engineInit(int opmode, Key key,
266
AlgorithmParameterSpec params, SecureRandom sr)
267
throws InvalidKeyException, InvalidAlgorithmParameterException {
268
if (opmode == Cipher.DECRYPT_MODE && params == null) {
269
throw new InvalidAlgorithmParameterException
270
("Parameters required for decryption");
271
}
272
updateCalled = false;
273
byte[] ivValue = null;
274
int tagLen = -1;
275
switch (type) {
276
case AES_GCM:
277
if (params != null) {
278
if (!(params instanceof GCMParameterSpec)) {
279
throw new InvalidAlgorithmParameterException
280
("Only GCMParameterSpec is supported");
281
}
282
ivValue = ((GCMParameterSpec) params).getIV();
283
tagLen = ((GCMParameterSpec) params).getTLen() >> 3;
284
}
285
break;
286
case CHACHA20_POLY1305:
287
if (params != null) {
288
if (!(params instanceof IvParameterSpec)) {
289
throw new InvalidAlgorithmParameterException
290
("Only IvParameterSpec is supported");
291
}
292
ivValue = ((IvParameterSpec) params).getIV();
293
tagLen = type.defTagLen;
294
}
295
break;
296
default:
297
throw new AssertionError("Unsupported type " + type);
298
};
299
implInit(opmode, key, ivValue, tagLen, sr);
300
}
301
302
// see JCE spec
303
protected void engineInit(int opmode, Key key, AlgorithmParameters params,
304
SecureRandom sr)
305
throws InvalidKeyException, InvalidAlgorithmParameterException {
306
if (opmode == Cipher.DECRYPT_MODE && params == null) {
307
throw new InvalidAlgorithmParameterException
308
("Parameters required for decryption");
309
}
310
updateCalled = false;
311
try {
312
AlgorithmParameterSpec paramSpec = null;
313
if (params != null) {
314
switch (type) {
315
case AES_GCM:
316
paramSpec =
317
params.getParameterSpec(GCMParameterSpec.class);
318
break;
319
case CHACHA20_POLY1305:
320
paramSpec =
321
params.getParameterSpec(IvParameterSpec.class);
322
break;
323
default:
324
throw new AssertionError("Unsupported type " + type);
325
}
326
}
327
engineInit(opmode, key, paramSpec, sr);
328
} catch (InvalidParameterSpecException ex) {
329
throw new InvalidAlgorithmParameterException(ex);
330
}
331
}
332
333
// actual init() implementation
334
private void implInit(int opmode, Key key, byte[] iv, int tagLen,
335
SecureRandom sr)
336
throws InvalidKeyException, InvalidAlgorithmParameterException {
337
reset(true);
338
if (fixedKeySize != -1 &&
339
((key instanceof P11Key) ? ((P11Key) key).length() >> 3 :
340
key.getEncoded().length) != fixedKeySize) {
341
throw new InvalidKeyException("Key size is invalid");
342
}
343
P11Key newKey = P11SecretKeyFactory.convertKey(token, key,
344
type.keyAlgo);
345
switch (opmode) {
346
case Cipher.ENCRYPT_MODE:
347
encrypt = true;
348
requireReinit = Arrays.equals(iv, lastEncIv) &&
349
(newKey == lastEncKey);
350
if (requireReinit) {
351
throw new InvalidAlgorithmParameterException(
352
"Cannot reuse the same key and iv pair");
353
}
354
break;
355
case Cipher.DECRYPT_MODE:
356
encrypt = false;
357
requireReinit = false;
358
break;
359
default:
360
throw new InvalidAlgorithmParameterException
361
("Unsupported mode: " + opmode);
362
}
363
364
// decryption without parameters is checked in all engineInit() calls
365
if (sr != null) {
366
this.random = sr;
367
}
368
369
if (iv == null && tagLen == -1) {
370
// generate default values
371
switch (type) {
372
case AES_GCM:
373
iv = new byte[type.defIvLen];
374
this.random.nextBytes(iv);
375
tagLen = type.defTagLen;
376
break;
377
case CHACHA20_POLY1305:
378
iv = new byte[type.defIvLen];
379
this.random.nextBytes(iv);
380
tagLen = type.defTagLen;
381
break;
382
default:
383
throw new AssertionError("Unsupported type " + type);
384
}
385
}
386
this.iv = iv;
387
this.tagLen = tagLen;
388
this.p11Key = newKey;
389
try {
390
initialize();
391
} catch (PKCS11Exception e) {
392
if (e.getErrorCode() == CKR_MECHANISM_PARAM_INVALID) {
393
throw new InvalidAlgorithmParameterException("Bad params", e);
394
}
395
throw new InvalidKeyException("Could not initialize cipher", e);
396
}
397
}
398
399
private void cancelOperation() {
400
// cancel operation by finishing it; avoid killSession as some
401
// hardware vendors may require re-login
402
int bufLen = doFinalLength(0);
403
byte[] buffer = new byte[bufLen];
404
byte[] in = dataBuffer.toByteArray();
405
int inLen = in.length;
406
try {
407
if (encrypt) {
408
token.p11.C_Encrypt(session.id(), 0, in, 0, inLen,
409
0, buffer, 0, bufLen);
410
} else {
411
token.p11.C_Decrypt(session.id(), 0, in, 0, inLen,
412
0, buffer, 0, bufLen);
413
}
414
} catch (PKCS11Exception e) {
415
if (e.getErrorCode() == CKR_OPERATION_NOT_INITIALIZED) {
416
// Cancel Operation may be invoked after an error on a PKCS#11
417
// call. If the operation inside the token was already cancelled,
418
// do not fail here. This is part of a defensive mechanism for
419
// PKCS#11 libraries that do not strictly follow the standard.
420
return;
421
}
422
if (encrypt) {
423
throw new ProviderException("Cancel failed", e);
424
}
425
// ignore failure for decryption
426
}
427
}
428
429
private void ensureInitialized() throws PKCS11Exception {
430
if (initialized && aadBuffer.size() > 0) {
431
// need to cancel first to avoid CKR_OPERATION_ACTIVE
432
reset(true);
433
}
434
if (!initialized) {
435
initialize();
436
}
437
}
438
439
private void initialize() throws PKCS11Exception {
440
if (p11Key == null) {
441
throw new ProviderException(
442
"Operation cannot be performed without"
443
+ " calling engineInit first");
444
}
445
if (requireReinit) {
446
throw new IllegalStateException
447
("Must use either different key or iv");
448
}
449
450
token.ensureValid();
451
452
byte[] aad = (aadBuffer.size() > 0? aadBuffer.toByteArray() : null);
453
454
long p11KeyID = p11Key.getKeyID();
455
try {
456
CK_MECHANISM mechWithParams;
457
switch (type) {
458
case AES_GCM:
459
mechWithParams = new CK_MECHANISM(mechanism,
460
new CK_GCM_PARAMS(tagLen << 3, iv, aad));
461
break;
462
case CHACHA20_POLY1305:
463
mechWithParams = new CK_MECHANISM(mechanism,
464
new CK_SALSA20_CHACHA20_POLY1305_PARAMS(iv, aad));
465
break;
466
default:
467
throw new AssertionError("Unsupported type: " + type);
468
}
469
if (session == null) {
470
session = token.getOpSession();
471
}
472
if (encrypt) {
473
token.p11.C_EncryptInit(session.id(), mechWithParams,
474
p11KeyID);
475
} else {
476
token.p11.C_DecryptInit(session.id(), mechWithParams,
477
p11KeyID);
478
}
479
} catch (PKCS11Exception e) {
480
p11Key.releaseKeyID();
481
session = token.releaseSession(session);
482
throw e;
483
} finally {
484
dataBuffer.reset();
485
aadBuffer.reset();
486
}
487
initialized = true;
488
}
489
490
// if doFinal(inLen) is called, how big does the output buffer have to be?
491
private int doFinalLength(int inLen) {
492
if (inLen < 0) {
493
throw new ProviderException("Invalid negative input length");
494
}
495
496
int result = inLen + dataBuffer.size();
497
if (encrypt) {
498
result += tagLen;
499
} else {
500
// In earlier NSS versions, AES_GCM would report
501
// CKR_BUFFER_TOO_SMALL error if minus tagLen
502
if (type == Transformation.CHACHA20_POLY1305) {
503
result -= tagLen;
504
}
505
}
506
return (result > 0? result : 0);
507
}
508
509
// reset the states to the pre-initialized values
510
private void reset(boolean doCancel) {
511
if (!initialized) {
512
return;
513
}
514
initialized = false;
515
516
try {
517
if (session == null) {
518
return;
519
}
520
521
if (doCancel && token.explicitCancel) {
522
cancelOperation();
523
}
524
} finally {
525
p11Key.releaseKeyID();
526
session = token.releaseSession(session);
527
dataBuffer.reset();
528
}
529
}
530
531
// see JCE spec
532
protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
533
updateCalled = true;
534
int n = implUpdate(in, inOfs, inLen);
535
return new byte[0];
536
}
537
538
// see JCE spec
539
protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
540
int outOfs) throws ShortBufferException {
541
updateCalled = true;
542
implUpdate(in, inOfs, inLen);
543
return 0;
544
}
545
546
// see JCE spec
547
@Override
548
protected int engineUpdate(ByteBuffer inBuffer, ByteBuffer outBuffer)
549
throws ShortBufferException {
550
updateCalled = true;
551
implUpdate(inBuffer);
552
return 0;
553
}
554
555
// see JCE spec
556
@Override
557
protected synchronized void engineUpdateAAD(byte[] src, int srcOfs, int srcLen)
558
throws IllegalStateException {
559
if ((src == null) || (srcOfs < 0) || (srcOfs + srcLen > src.length)) {
560
throw new IllegalArgumentException("Invalid AAD");
561
}
562
if (requireReinit) {
563
throw new IllegalStateException
564
("Must use either different key or iv for encryption");
565
}
566
if (p11Key == null) {
567
throw new IllegalStateException("Need to initialize Cipher first");
568
}
569
if (updateCalled) {
570
throw new IllegalStateException
571
("Update has been called; no more AAD data");
572
}
573
aadBuffer.write(src, srcOfs, srcLen);
574
}
575
576
// see JCE spec
577
@Override
578
protected void engineUpdateAAD(ByteBuffer src)
579
throws IllegalStateException {
580
if (src == null) {
581
throw new IllegalArgumentException("Invalid AAD");
582
}
583
byte[] srcBytes = new byte[src.remaining()];
584
src.get(srcBytes);
585
engineUpdateAAD(srcBytes, 0, srcBytes.length);
586
}
587
588
// see JCE spec
589
protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
590
throws IllegalBlockSizeException, BadPaddingException {
591
int minOutLen = doFinalLength(inLen);
592
try {
593
byte[] out = new byte[minOutLen];
594
int n = engineDoFinal(in, inOfs, inLen, out, 0);
595
return P11Util.convert(out, 0, n);
596
} catch (ShortBufferException e) {
597
// convert since the output length is calculated by doFinalLength()
598
throw new ProviderException(e);
599
} finally {
600
updateCalled = false;
601
}
602
}
603
// see JCE spec
604
protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
605
int outOfs) throws ShortBufferException, IllegalBlockSizeException,
606
BadPaddingException {
607
try {
608
return implDoFinal(in, inOfs, inLen, out, outOfs, out.length - outOfs);
609
} finally {
610
updateCalled = false;
611
}
612
}
613
614
// see JCE spec
615
@Override
616
protected int engineDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
617
throws ShortBufferException, IllegalBlockSizeException,
618
BadPaddingException {
619
try {
620
return implDoFinal(inBuffer, outBuffer);
621
} finally {
622
updateCalled = false;
623
}
624
}
625
626
private int implUpdate(byte[] in, int inOfs, int inLen) {
627
if (inLen > 0) {
628
updateCalled = true;
629
try {
630
ensureInitialized();
631
} catch (PKCS11Exception e) {
632
//e.printStackTrace();
633
reset(false);
634
throw new ProviderException("update() failed", e);
635
}
636
dataBuffer.write(in, inOfs, inLen);
637
}
638
// always 0 as NSS only supports single-part encryption/decryption
639
return 0;
640
}
641
642
private int implUpdate(ByteBuffer inBuf) {
643
int inLen = inBuf.remaining();
644
if (inLen > 0) {
645
try {
646
ensureInitialized();
647
} catch (PKCS11Exception e) {
648
reset(false);
649
throw new ProviderException("update() failed", e);
650
}
651
byte[] data = new byte[inLen];
652
inBuf.get(data);
653
dataBuffer.write(data, 0, data.length);
654
}
655
// always 0 as NSS only supports single-part encryption/decryption
656
return 0;
657
}
658
659
private int implDoFinal(byte[] in, int inOfs, int inLen,
660
byte[] out, int outOfs, int outLen)
661
throws ShortBufferException, IllegalBlockSizeException,
662
BadPaddingException {
663
int requiredOutLen = doFinalLength(inLen);
664
if (outLen < requiredOutLen) {
665
throw new ShortBufferException();
666
}
667
668
boolean doCancel = true;
669
try {
670
ensureInitialized();
671
if (dataBuffer.size() > 0) {
672
if (in != null && inOfs > 0 && inLen > 0 &&
673
inOfs < (in.length - inLen)) {
674
dataBuffer.write(in, inOfs, inLen);
675
}
676
in = dataBuffer.toByteArray();
677
inOfs = 0;
678
inLen = in.length;
679
}
680
int k = 0;
681
if (encrypt) {
682
k = token.p11.C_Encrypt(session.id(), 0, in, inOfs, inLen,
683
0, out, outOfs, outLen);
684
doCancel = false;
685
} else {
686
// Special handling to match SunJCE provider behavior
687
if (inLen == 0) {
688
return 0;
689
}
690
k = token.p11.C_Decrypt(session.id(), 0, in, inOfs, inLen,
691
0, out, outOfs, outLen);
692
doCancel = false;
693
}
694
return k;
695
} catch (PKCS11Exception e) {
696
// As per the PKCS#11 standard, C_Encrypt and C_Decrypt may only
697
// keep the operation active on CKR_BUFFER_TOO_SMALL errors or
698
// successful calls to determine the output length. However,
699
// these cases are not expected here because the output length
700
// is checked in the OpenJDK side before making the PKCS#11 call.
701
// Thus, doCancel can safely be 'false'.
702
doCancel = false;
703
handleException(e);
704
throw new ProviderException("doFinal() failed", e);
705
} finally {
706
if (encrypt) {
707
lastEncKey = this.p11Key;
708
lastEncIv = this.iv;
709
requireReinit = true;
710
}
711
reset(doCancel);
712
}
713
}
714
715
private int implDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer)
716
throws ShortBufferException, IllegalBlockSizeException,
717
BadPaddingException {
718
int outLen = outBuffer.remaining();
719
int inLen = inBuffer.remaining();
720
721
int requiredOutLen = doFinalLength(inLen);
722
if (outLen < requiredOutLen) {
723
throw new ShortBufferException();
724
}
725
726
boolean doCancel = true;
727
try {
728
ensureInitialized();
729
730
long inAddr = 0;
731
byte[] in = null;
732
int inOfs = 0;
733
if (dataBuffer.size() > 0) {
734
if (inLen > 0) {
735
byte[] temp = new byte[inLen];
736
inBuffer.get(temp);
737
dataBuffer.write(temp, 0, temp.length);
738
}
739
in = dataBuffer.toByteArray();
740
inOfs = 0;
741
inLen = in.length;
742
} else {
743
if (inBuffer instanceof DirectBuffer) {
744
inAddr = ((DirectBuffer) inBuffer).address();
745
inOfs = inBuffer.position();
746
} else {
747
if (inBuffer.hasArray()) {
748
in = inBuffer.array();
749
inOfs = inBuffer.position() + inBuffer.arrayOffset();
750
} else {
751
in = new byte[inLen];
752
inBuffer.get(in);
753
}
754
}
755
}
756
long outAddr = 0;
757
byte[] outArray = null;
758
int outOfs = 0;
759
if (outBuffer instanceof DirectBuffer) {
760
outAddr = ((DirectBuffer) outBuffer).address();
761
outOfs = outBuffer.position();
762
} else {
763
if (outBuffer.hasArray()) {
764
outArray = outBuffer.array();
765
outOfs = outBuffer.position() + outBuffer.arrayOffset();
766
} else {
767
outArray = new byte[outLen];
768
}
769
}
770
771
int k = 0;
772
if (encrypt) {
773
k = token.p11.C_Encrypt(session.id(), inAddr, in, inOfs, inLen,
774
outAddr, outArray, outOfs, outLen);
775
doCancel = false;
776
} else {
777
// Special handling to match SunJCE provider behavior
778
if (inLen == 0) {
779
return 0;
780
}
781
k = token.p11.C_Decrypt(session.id(), inAddr, in, inOfs, inLen,
782
outAddr, outArray, outOfs, outLen);
783
doCancel = false;
784
}
785
inBuffer.position(inBuffer.limit());
786
outBuffer.position(outBuffer.position() + k);
787
return k;
788
} catch (PKCS11Exception e) {
789
// As per the PKCS#11 standard, C_Encrypt and C_Decrypt may only
790
// keep the operation active on CKR_BUFFER_TOO_SMALL errors or
791
// successful calls to determine the output length. However,
792
// these cases are not expected here because the output length
793
// is checked in the OpenJDK side before making the PKCS#11 call.
794
// Thus, doCancel can safely be 'false'.
795
doCancel = false;
796
handleException(e);
797
throw new ProviderException("doFinal() failed", e);
798
} finally {
799
if (encrypt) {
800
lastEncKey = this.p11Key;
801
lastEncIv = this.iv;
802
requireReinit = true;
803
}
804
reset(doCancel);
805
}
806
}
807
808
private void handleException(PKCS11Exception e)
809
throws ShortBufferException, IllegalBlockSizeException,
810
BadPaddingException {
811
long errorCode = e.getErrorCode();
812
if (errorCode == CKR_BUFFER_TOO_SMALL) {
813
throw (ShortBufferException)
814
(new ShortBufferException().initCause(e));
815
} else if (errorCode == CKR_DATA_LEN_RANGE ||
816
errorCode == CKR_ENCRYPTED_DATA_LEN_RANGE) {
817
throw (IllegalBlockSizeException)
818
(new IllegalBlockSizeException(e.toString()).initCause(e));
819
} else if (errorCode == CKR_ENCRYPTED_DATA_INVALID ||
820
// Solaris-specific
821
errorCode == CKR_GENERAL_ERROR) {
822
throw (AEADBadTagException)
823
(new AEADBadTagException(e.toString()).initCause(e));
824
}
825
}
826
827
// see JCE spec
828
protected byte[] engineWrap(Key key) throws IllegalBlockSizeException,
829
InvalidKeyException {
830
// XXX key wrapping
831
throw new UnsupportedOperationException("engineWrap()");
832
}
833
834
// see JCE spec
835
protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
836
int wrappedKeyType)
837
throws InvalidKeyException, NoSuchAlgorithmException {
838
// XXX key unwrapping
839
throw new UnsupportedOperationException("engineUnwrap()");
840
}
841
842
// see JCE spec
843
@Override
844
protected int engineGetKeySize(Key key) throws InvalidKeyException {
845
int n = P11SecretKeyFactory.convertKey
846
(token, key, type.keyAlgo).length();
847
return n;
848
}
849
}
850
851
852