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/javax/crypto/Mac.java
38829 views
1
/*
2
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package javax.crypto;
27
28
import java.util.*;
29
30
import java.security.*;
31
import java.security.Provider.Service;
32
import java.security.spec.AlgorithmParameterSpec;
33
34
import java.nio.ByteBuffer;
35
36
import sun.security.util.Debug;
37
import sun.security.jca.*;
38
import sun.security.jca.GetInstance.Instance;
39
40
/**
41
* This class provides the functionality of a "Message Authentication Code"
42
* (MAC) algorithm.
43
*
44
* <p> A MAC provides a way to check
45
* the integrity of information transmitted over or stored in an unreliable
46
* medium, based on a secret key. Typically, message
47
* authentication codes are used between two parties that share a secret
48
* key in order to validate information transmitted between these
49
* parties.
50
*
51
* <p> A MAC mechanism that is based on cryptographic hash functions is
52
* referred to as HMAC. HMAC can be used with any cryptographic hash function,
53
* e.g., SHA256 or SHA384, in combination with a secret shared key. HMAC is
54
* specified in RFC 2104.
55
*
56
* <p> Every implementation of the Java platform is required to support
57
* the following standard {@code Mac} algorithms:
58
* <ul>
59
* <li>{@code HmacMD5}</li>
60
* <li>{@code HmacSHA1}</li>
61
* <li>{@code HmacSHA256}</li>
62
* </ul>
63
* These algorithms are described in the
64
* <a href="{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
65
* Mac section</a> of the
66
* Java Cryptography Architecture Standard Algorithm Name Documentation.
67
* Consult the release documentation for your implementation to see if any
68
* other algorithms are supported.
69
*
70
* @author Jan Luehe
71
*
72
* @since 1.4
73
*/
74
75
public class Mac implements Cloneable {
76
77
private static final Debug debug =
78
Debug.getInstance("jca", "Mac");
79
80
private static final Debug pdebug =
81
Debug.getInstance("provider", "Provider");
82
private static final boolean skipDebug =
83
Debug.isOn("engine=") && !Debug.isOn("mac");
84
85
// The provider
86
private Provider provider;
87
88
// The provider implementation (delegate)
89
private MacSpi spi;
90
91
// The name of the MAC algorithm.
92
private final String algorithm;
93
94
// Has this object been initialized?
95
private boolean initialized = false;
96
97
// next service to try in provider selection
98
// null once provider is selected
99
private Service firstService;
100
101
// remaining services to try in provider selection
102
// null once provider is selected
103
private Iterator<Service> serviceIterator;
104
105
private final Object lock;
106
107
/**
108
* Creates a MAC object.
109
*
110
* @param macSpi the delegate
111
* @param provider the provider
112
* @param algorithm the algorithm
113
*/
114
protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
115
this.spi = macSpi;
116
this.provider = provider;
117
this.algorithm = algorithm;
118
serviceIterator = null;
119
lock = null;
120
}
121
122
private Mac(Service s, Iterator<Service> t, String algorithm) {
123
firstService = s;
124
serviceIterator = t;
125
this.algorithm = algorithm;
126
lock = new Object();
127
}
128
129
/**
130
* Returns the algorithm name of this {@code Mac} object.
131
*
132
* <p>This is the same name that was specified in one of the
133
* {@code getInstance} calls that created this
134
* {@code Mac} object.
135
*
136
* @return the algorithm name of this {@code Mac} object.
137
*/
138
public final String getAlgorithm() {
139
return this.algorithm;
140
}
141
142
/**
143
* Returns a {@code Mac} object that implements the
144
* specified MAC algorithm.
145
*
146
* <p> This method traverses the list of registered security Providers,
147
* starting with the most preferred Provider.
148
* A new Mac object encapsulating the
149
* MacSpi implementation from the first
150
* Provider that supports the specified algorithm is returned.
151
*
152
* <p> Note that the list of registered providers may be retrieved via
153
* the {@link Security#getProviders() Security.getProviders()} method.
154
*
155
* @param algorithm the standard name of the requested MAC algorithm.
156
* See the Mac section in the <a href=
157
* "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
158
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
159
* for information about standard algorithm names.
160
*
161
* @return the new {@code Mac} object.
162
*
163
* @exception NoSuchAlgorithmException if no Provider supports a
164
* MacSpi implementation for the
165
* specified algorithm.
166
*
167
* @see java.security.Provider
168
*/
169
public static final Mac getInstance(String algorithm)
170
throws NoSuchAlgorithmException {
171
List<Service> services = GetInstance.getServices("Mac", algorithm);
172
// make sure there is at least one service from a signed provider
173
Iterator<Service> t = services.iterator();
174
while (t.hasNext()) {
175
Service s = t.next();
176
if (JceSecurity.canUseProvider(s.getProvider()) == false) {
177
continue;
178
}
179
return new Mac(s, t, algorithm);
180
}
181
throw new NoSuchAlgorithmException
182
("Algorithm " + algorithm + " not available");
183
}
184
185
/**
186
* Returns a {@code Mac} object that implements the
187
* specified MAC algorithm.
188
*
189
* <p> A new Mac object encapsulating the
190
* MacSpi implementation from the specified provider
191
* is returned. The specified provider must be registered
192
* in the security provider list.
193
*
194
* <p> Note that the list of registered providers may be retrieved via
195
* the {@link Security#getProviders() Security.getProviders()} method.
196
*
197
* @param algorithm the standard name of the requested MAC algorithm.
198
* See the Mac section in the <a href=
199
* "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
200
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
201
* for information about standard algorithm names.
202
*
203
* @param provider the name of the provider.
204
*
205
* @return the new {@code Mac} object.
206
*
207
* @exception NoSuchAlgorithmException if a MacSpi
208
* implementation for the specified algorithm is not
209
* available from the specified provider.
210
*
211
* @exception NoSuchProviderException if the specified provider is not
212
* registered in the security provider list.
213
*
214
* @exception IllegalArgumentException if the {@code provider}
215
* is null or empty.
216
*
217
* @see java.security.Provider
218
*/
219
public static final Mac getInstance(String algorithm, String provider)
220
throws NoSuchAlgorithmException, NoSuchProviderException {
221
Instance instance = JceSecurity.getInstance
222
("Mac", MacSpi.class, algorithm, provider);
223
return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
224
}
225
226
/**
227
* Returns a {@code Mac} object that implements the
228
* specified MAC algorithm.
229
*
230
* <p> A new Mac object encapsulating the
231
* MacSpi implementation from the specified Provider
232
* object is returned. Note that the specified Provider object
233
* does not have to be registered in the provider list.
234
*
235
* @param algorithm the standard name of the requested MAC algorithm.
236
* See the Mac section in the <a href=
237
* "{@docRoot}/../technotes/guides/security/StandardNames.html#Mac">
238
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
239
* for information about standard algorithm names.
240
*
241
* @param provider the provider.
242
*
243
* @return the new {@code Mac} object.
244
*
245
* @exception NoSuchAlgorithmException if a MacSpi
246
* implementation for the specified algorithm is not available
247
* from the specified Provider object.
248
*
249
* @exception IllegalArgumentException if the {@code provider}
250
* is null.
251
*
252
* @see java.security.Provider
253
*/
254
public static final Mac getInstance(String algorithm, Provider provider)
255
throws NoSuchAlgorithmException {
256
Instance instance = JceSecurity.getInstance
257
("Mac", MacSpi.class, algorithm, provider);
258
return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
259
}
260
261
// max number of debug warnings to print from chooseFirstProvider()
262
private static int warnCount = 10;
263
264
/**
265
* Choose the Spi from the first provider available. Used if
266
* delayed provider selection is not possible because init()
267
* is not the first method called.
268
*/
269
void chooseFirstProvider() {
270
if ((spi != null) || (serviceIterator == null)) {
271
return;
272
}
273
synchronized (lock) {
274
if (spi != null) {
275
return;
276
}
277
if (debug != null) {
278
int w = --warnCount;
279
if (w >= 0) {
280
debug.println("Mac.init() not first method "
281
+ "called, disabling delayed provider selection");
282
if (w == 0) {
283
debug.println("Further warnings of this type will "
284
+ "be suppressed");
285
}
286
new Exception("Call trace").printStackTrace();
287
}
288
}
289
Exception lastException = null;
290
while ((firstService != null) || serviceIterator.hasNext()) {
291
Service s;
292
if (firstService != null) {
293
s = firstService;
294
firstService = null;
295
} else {
296
s = serviceIterator.next();
297
}
298
if (JceSecurity.canUseProvider(s.getProvider()) == false) {
299
continue;
300
}
301
try {
302
Object obj = s.newInstance(null);
303
if (obj instanceof MacSpi == false) {
304
continue;
305
}
306
spi = (MacSpi)obj;
307
provider = s.getProvider();
308
// not needed any more
309
firstService = null;
310
serviceIterator = null;
311
return;
312
} catch (NoSuchAlgorithmException e) {
313
lastException = e;
314
}
315
}
316
ProviderException e = new ProviderException
317
("Could not construct MacSpi instance");
318
if (lastException != null) {
319
e.initCause(lastException);
320
}
321
throw e;
322
}
323
}
324
325
private void chooseProvider(Key key, AlgorithmParameterSpec params)
326
throws InvalidKeyException, InvalidAlgorithmParameterException {
327
synchronized (lock) {
328
if (spi != null) {
329
spi.engineInit(key, params);
330
return;
331
}
332
Exception lastException = null;
333
while ((firstService != null) || serviceIterator.hasNext()) {
334
Service s;
335
if (firstService != null) {
336
s = firstService;
337
firstService = null;
338
} else {
339
s = serviceIterator.next();
340
}
341
// if provider says it does not support this key, ignore it
342
if (s.supportsParameter(key) == false) {
343
continue;
344
}
345
if (JceSecurity.canUseProvider(s.getProvider()) == false) {
346
continue;
347
}
348
try {
349
MacSpi spi = (MacSpi)s.newInstance(null);
350
spi.engineInit(key, params);
351
provider = s.getProvider();
352
this.spi = spi;
353
firstService = null;
354
serviceIterator = null;
355
return;
356
} catch (Exception e) {
357
// NoSuchAlgorithmException from newInstance()
358
// InvalidKeyException from init()
359
// RuntimeException (ProviderException) from init()
360
if (lastException == null) {
361
lastException = e;
362
}
363
}
364
}
365
// no working provider found, fail
366
if (lastException instanceof InvalidKeyException) {
367
throw (InvalidKeyException)lastException;
368
}
369
if (lastException instanceof InvalidAlgorithmParameterException) {
370
throw (InvalidAlgorithmParameterException)lastException;
371
}
372
if (lastException instanceof RuntimeException) {
373
throw (RuntimeException)lastException;
374
}
375
String kName = (key != null) ? key.getClass().getName() : "(null)";
376
throw new InvalidKeyException
377
("No installed provider supports this key: "
378
+ kName, lastException);
379
}
380
}
381
382
/**
383
* Returns the provider of this {@code Mac} object.
384
*
385
* @return the provider of this {@code Mac} object.
386
*/
387
public final Provider getProvider() {
388
chooseFirstProvider();
389
return this.provider;
390
}
391
392
/**
393
* Returns the length of the MAC in bytes.
394
*
395
* @return the MAC length in bytes.
396
*/
397
public final int getMacLength() {
398
chooseFirstProvider();
399
return spi.engineGetMacLength();
400
}
401
402
/**
403
* Initializes this {@code Mac} object with the given key.
404
*
405
* @param key the key.
406
*
407
* @exception InvalidKeyException if the given key is inappropriate for
408
* initializing this MAC.
409
*/
410
public final void init(Key key) throws InvalidKeyException {
411
try {
412
if (spi != null) {
413
spi.engineInit(key, null);
414
} else {
415
chooseProvider(key, null);
416
}
417
} catch (InvalidAlgorithmParameterException e) {
418
throw new InvalidKeyException("init() failed", e);
419
}
420
initialized = true;
421
422
if (!skipDebug && pdebug != null) {
423
pdebug.println("Mac." + algorithm + " algorithm from: " +
424
this.provider.getName());
425
}
426
}
427
428
/**
429
* Initializes this {@code Mac} object with the given key and
430
* algorithm parameters.
431
*
432
* @param key the key.
433
* @param params the algorithm parameters.
434
*
435
* @exception InvalidKeyException if the given key is inappropriate for
436
* initializing this MAC.
437
* @exception InvalidAlgorithmParameterException if the given algorithm
438
* parameters are inappropriate for this MAC.
439
*/
440
public final void init(Key key, AlgorithmParameterSpec params)
441
throws InvalidKeyException, InvalidAlgorithmParameterException {
442
if (spi != null) {
443
spi.engineInit(key, params);
444
} else {
445
chooseProvider(key, params);
446
}
447
initialized = true;
448
449
if (!skipDebug && pdebug != null) {
450
pdebug.println("Mac." + algorithm + " algorithm from: " +
451
this.provider.getName());
452
}
453
}
454
455
/**
456
* Processes the given byte.
457
*
458
* @param input the input byte to be processed.
459
*
460
* @exception IllegalStateException if this {@code Mac} has not been
461
* initialized.
462
*/
463
public final void update(byte input) throws IllegalStateException {
464
chooseFirstProvider();
465
if (initialized == false) {
466
throw new IllegalStateException("MAC not initialized");
467
}
468
spi.engineUpdate(input);
469
}
470
471
/**
472
* Processes the given array of bytes.
473
*
474
* @param input the array of bytes to be processed.
475
*
476
* @exception IllegalStateException if this {@code Mac} has not been
477
* initialized.
478
*/
479
public final void update(byte[] input) throws IllegalStateException {
480
chooseFirstProvider();
481
if (initialized == false) {
482
throw new IllegalStateException("MAC not initialized");
483
}
484
if (input != null) {
485
spi.engineUpdate(input, 0, input.length);
486
}
487
}
488
489
/**
490
* Processes the first {@code len} bytes in {@code input},
491
* starting at {@code offset} inclusive.
492
*
493
* @param input the input buffer.
494
* @param offset the offset in {@code input} where the input starts.
495
* @param len the number of bytes to process.
496
*
497
* @exception IllegalStateException if this {@code Mac} has not been
498
* initialized.
499
*/
500
public final void update(byte[] input, int offset, int len)
501
throws IllegalStateException {
502
chooseFirstProvider();
503
if (initialized == false) {
504
throw new IllegalStateException("MAC not initialized");
505
}
506
507
if (input != null) {
508
if ((offset < 0) || (len > (input.length - offset)) || (len < 0))
509
throw new IllegalArgumentException("Bad arguments");
510
spi.engineUpdate(input, offset, len);
511
}
512
}
513
514
/**
515
* Processes {@code input.remaining()} bytes in the ByteBuffer
516
* {@code input}, starting at {@code input.position()}.
517
* Upon return, the buffer's position will be equal to its limit;
518
* its limit will not have changed.
519
*
520
* @param input the ByteBuffer
521
*
522
* @exception IllegalStateException if this {@code Mac} has not been
523
* initialized.
524
* @since 1.5
525
*/
526
public final void update(ByteBuffer input) {
527
chooseFirstProvider();
528
if (initialized == false) {
529
throw new IllegalStateException("MAC not initialized");
530
}
531
if (input == null) {
532
throw new IllegalArgumentException("Buffer must not be null");
533
}
534
spi.engineUpdate(input);
535
}
536
537
/**
538
* Finishes the MAC operation.
539
*
540
* <p>A call to this method resets this {@code Mac} object to the
541
* state it was in when previously initialized via a call to
542
* {@code init(Key)} or
543
* {@code init(Key, AlgorithmParameterSpec)}.
544
* That is, the object is reset and available to generate another MAC from
545
* the same key, if desired, via new calls to {@code update} and
546
* {@code doFinal}.
547
* (In order to reuse this {@code Mac} object with a different key,
548
* it must be reinitialized via a call to {@code init(Key)} or
549
* {@code init(Key, AlgorithmParameterSpec)}.
550
*
551
* @return the MAC result.
552
*
553
* @exception IllegalStateException if this {@code Mac} has not been
554
* initialized.
555
*/
556
public final byte[] doFinal() throws IllegalStateException {
557
chooseFirstProvider();
558
if (initialized == false) {
559
throw new IllegalStateException("MAC not initialized");
560
}
561
byte[] mac = spi.engineDoFinal();
562
spi.engineReset();
563
return mac;
564
}
565
566
/**
567
* Finishes the MAC operation.
568
*
569
* <p>A call to this method resets this {@code Mac} object to the
570
* state it was in when previously initialized via a call to
571
* {@code init(Key)} or
572
* {@code init(Key, AlgorithmParameterSpec)}.
573
* That is, the object is reset and available to generate another MAC from
574
* the same key, if desired, via new calls to {@code update} and
575
* {@code doFinal}.
576
* (In order to reuse this {@code Mac} object with a different key,
577
* it must be reinitialized via a call to {@code init(Key)} or
578
* {@code init(Key, AlgorithmParameterSpec)}.
579
*
580
* <p>The MAC result is stored in {@code output}, starting at
581
* {@code outOffset} inclusive.
582
*
583
* @param output the buffer where the MAC result is stored
584
* @param outOffset the offset in {@code output} where the MAC is
585
* stored
586
*
587
* @exception ShortBufferException if the given output buffer is too small
588
* to hold the result
589
* @exception IllegalStateException if this {@code Mac} has not been
590
* initialized.
591
*/
592
public final void doFinal(byte[] output, int outOffset)
593
throws ShortBufferException, IllegalStateException
594
{
595
chooseFirstProvider();
596
if (initialized == false) {
597
throw new IllegalStateException("MAC not initialized");
598
}
599
int macLen = getMacLength();
600
if (output == null || output.length-outOffset < macLen) {
601
throw new ShortBufferException
602
("Cannot store MAC in output buffer");
603
}
604
byte[] mac = doFinal();
605
System.arraycopy(mac, 0, output, outOffset, macLen);
606
return;
607
}
608
609
/**
610
* Processes the given array of bytes and finishes the MAC operation.
611
*
612
* <p>A call to this method resets this {@code Mac} object to the
613
* state it was in when previously initialized via a call to
614
* {@code init(Key)} or
615
* {@code init(Key, AlgorithmParameterSpec)}.
616
* That is, the object is reset and available to generate another MAC from
617
* the same key, if desired, via new calls to {@code update} and
618
* {@code doFinal}.
619
* (In order to reuse this {@code Mac} object with a different key,
620
* it must be reinitialized via a call to {@code init(Key)} or
621
* {@code init(Key, AlgorithmParameterSpec)}.
622
*
623
* @param input data in bytes
624
* @return the MAC result.
625
*
626
* @exception IllegalStateException if this {@code Mac} has not been
627
* initialized.
628
*/
629
public final byte[] doFinal(byte[] input) throws IllegalStateException
630
{
631
chooseFirstProvider();
632
if (initialized == false) {
633
throw new IllegalStateException("MAC not initialized");
634
}
635
update(input);
636
return doFinal();
637
}
638
639
/**
640
* Resets this {@code Mac} object.
641
*
642
* <p>A call to this method resets this {@code Mac} object to the
643
* state it was in when previously initialized via a call to
644
* {@code init(Key)} or
645
* {@code init(Key, AlgorithmParameterSpec)}.
646
* That is, the object is reset and available to generate another MAC from
647
* the same key, if desired, via new calls to {@code update} and
648
* {@code doFinal}.
649
* (In order to reuse this {@code Mac} object with a different key,
650
* it must be reinitialized via a call to {@code init(Key)} or
651
* {@code init(Key, AlgorithmParameterSpec)}.
652
*/
653
public final void reset() {
654
chooseFirstProvider();
655
spi.engineReset();
656
}
657
658
/**
659
* Returns a clone if the provider implementation is cloneable.
660
*
661
* @return a clone if the provider implementation is cloneable.
662
*
663
* @exception CloneNotSupportedException if this is called on a
664
* delegate that does not support {@code Cloneable}.
665
*/
666
public final Object clone() throws CloneNotSupportedException {
667
chooseFirstProvider();
668
Mac that = (Mac)super.clone();
669
that.spi = (MacSpi)this.spi.clone();
670
return that;
671
}
672
}
673
674