Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/javax/crypto/Mac.java
41152 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 HmacSHA1}</li>
60
* <li>{@code HmacSHA256}</li>
61
* </ul>
62
* These algorithms are described in the
63
* <a href="{@docRoot}/../specs/security/standard-names.html#mac-algorithms">
64
* Mac section</a> of the
65
* Java Security Standard Algorithm Names Specification.
66
* Consult the release documentation for your implementation to see if any
67
* other algorithms are supported.
68
*
69
* @author Jan Luehe
70
*
71
* @since 1.4
72
*/
73
74
public class Mac implements Cloneable {
75
76
private static final Debug debug =
77
Debug.getInstance("jca", "Mac");
78
79
private static final Debug pdebug =
80
Debug.getInstance("provider", "Provider");
81
private static final boolean skipDebug =
82
Debug.isOn("engine=") && !Debug.isOn("mac");
83
84
// The provider
85
private Provider provider;
86
87
// The provider implementation (delegate)
88
private MacSpi spi;
89
90
// The name of the MAC algorithm.
91
private final String algorithm;
92
93
// Has this object been initialized?
94
private boolean initialized = false;
95
96
// next service to try in provider selection
97
// null once provider is selected
98
private Service firstService;
99
100
// remaining services to try in provider selection
101
// null once provider is selected
102
private Iterator<Service> serviceIterator;
103
104
private final Object lock;
105
106
/**
107
* Creates a MAC object.
108
*
109
* @param macSpi the delegate
110
* @param provider the provider
111
* @param algorithm the algorithm
112
*/
113
protected Mac(MacSpi macSpi, Provider provider, String algorithm) {
114
this.spi = macSpi;
115
this.provider = provider;
116
this.algorithm = algorithm;
117
serviceIterator = null;
118
lock = null;
119
}
120
121
private Mac(Service s, Iterator<Service> t, String algorithm) {
122
firstService = s;
123
serviceIterator = t;
124
this.algorithm = algorithm;
125
lock = new Object();
126
}
127
128
/**
129
* Returns the algorithm name of this {@code Mac} object.
130
*
131
* <p>This is the same name that was specified in one of the
132
* {@code getInstance} calls that created this
133
* {@code Mac} object.
134
*
135
* @return the algorithm name of this {@code Mac} object.
136
*/
137
public final String getAlgorithm() {
138
return this.algorithm;
139
}
140
141
/**
142
* Returns a {@code Mac} object that implements the
143
* specified MAC algorithm.
144
*
145
* <p> This method traverses the list of registered security Providers,
146
* starting with the most preferred Provider.
147
* A new Mac object encapsulating the
148
* MacSpi implementation from the first
149
* Provider that supports the specified algorithm is returned.
150
*
151
* <p> Note that the list of registered providers may be retrieved via
152
* the {@link Security#getProviders() Security.getProviders()} method.
153
*
154
* @implNote
155
* The JDK Reference Implementation additionally uses the
156
* {@code jdk.security.provider.preferred}
157
* {@link Security#getProperty(String) Security} property to determine
158
* the preferred provider order for the specified algorithm. This
159
* may be different than the order of providers returned by
160
* {@link Security#getProviders() Security.getProviders()}.
161
*
162
* @param algorithm the standard name of the requested MAC algorithm.
163
* See the Mac section in the <a href=
164
* "{@docRoot}/../specs/security/standard-names.html#mac-algorithms">
165
* Java Security Standard Algorithm Names Specification</a>
166
* for information about standard algorithm names.
167
*
168
* @return the new {@code Mac} object
169
*
170
* @throws NoSuchAlgorithmException if no {@code Provider} supports a
171
* {@code MacSpi} implementation for the specified algorithm
172
*
173
* @throws NullPointerException if {@code algorithm} is {@code null}
174
*
175
* @see java.security.Provider
176
*/
177
public static final Mac getInstance(String algorithm)
178
throws NoSuchAlgorithmException {
179
Objects.requireNonNull(algorithm, "null algorithm name");
180
List<Service> services = GetInstance.getServices("Mac", algorithm);
181
// make sure there is at least one service from a signed provider
182
Iterator<Service> t = services.iterator();
183
while (t.hasNext()) {
184
Service s = t.next();
185
if (JceSecurity.canUseProvider(s.getProvider()) == false) {
186
continue;
187
}
188
return new Mac(s, t, algorithm);
189
}
190
throw new NoSuchAlgorithmException
191
("Algorithm " + algorithm + " not available");
192
}
193
194
/**
195
* Returns a {@code Mac} object that implements the
196
* specified MAC algorithm.
197
*
198
* <p> A new Mac object encapsulating the
199
* MacSpi implementation from the specified provider
200
* is returned. The specified provider must be registered
201
* in the security provider list.
202
*
203
* <p> Note that the list of registered providers may be retrieved via
204
* the {@link Security#getProviders() Security.getProviders()} method.
205
*
206
* @param algorithm the standard name of the requested MAC algorithm.
207
* See the Mac section in the <a href=
208
* "{@docRoot}/../specs/security/standard-names.html#mac-algorithms">
209
* Java Security Standard Algorithm Names Specification</a>
210
* for information about standard algorithm names.
211
*
212
* @param provider the name of the provider.
213
*
214
* @return the new {@code Mac} object
215
*
216
* @throws IllegalArgumentException if the {@code provider}
217
* is {@code null} or empty
218
*
219
* @throws NoSuchAlgorithmException if a {@code MacSpi}
220
* implementation for the specified algorithm is not
221
* available from the specified provider
222
*
223
* @throws NoSuchProviderException if the specified provider is not
224
* registered in the security provider list
225
*
226
* @throws NullPointerException if {@code algorithm} is {@code null}
227
*
228
* @see java.security.Provider
229
*/
230
public static final Mac getInstance(String algorithm, String provider)
231
throws NoSuchAlgorithmException, NoSuchProviderException {
232
Objects.requireNonNull(algorithm, "null algorithm name");
233
Instance instance = JceSecurity.getInstance
234
("Mac", MacSpi.class, algorithm, provider);
235
return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
236
}
237
238
/**
239
* Returns a {@code Mac} object that implements the
240
* specified MAC algorithm.
241
*
242
* <p> A new Mac object encapsulating the
243
* MacSpi implementation from the specified Provider
244
* object is returned. Note that the specified Provider object
245
* does not have to be registered in the provider list.
246
*
247
* @param algorithm the standard name of the requested MAC algorithm.
248
* See the Mac section in the <a href=
249
* "{@docRoot}/../specs/security/standard-names.html#mac-algorithms">
250
* Java Security Standard Algorithm Names Specification</a>
251
* for information about standard algorithm names.
252
*
253
* @param provider the provider.
254
*
255
* @return the new {@code Mac} object
256
*
257
* @throws IllegalArgumentException if the {@code provider} is
258
* {@code null}
259
*
260
* @throws NoSuchAlgorithmException if a {@code MacSpi}
261
* implementation for the specified algorithm is not available
262
* from the specified {@code Provider} object
263
*
264
* @throws NullPointerException if {@code algorithm} is {@code null}
265
*
266
* @see java.security.Provider
267
*/
268
public static final Mac getInstance(String algorithm, Provider provider)
269
throws NoSuchAlgorithmException {
270
Objects.requireNonNull(algorithm, "null algorithm name");
271
Instance instance = JceSecurity.getInstance
272
("Mac", MacSpi.class, algorithm, provider);
273
return new Mac((MacSpi)instance.impl, instance.provider, algorithm);
274
}
275
276
// max number of debug warnings to print from chooseFirstProvider()
277
private static int warnCount = 10;
278
279
/**
280
* Choose the Spi from the first provider available. Used if
281
* delayed provider selection is not possible because init()
282
* is not the first method called.
283
*/
284
void chooseFirstProvider() {
285
if ((spi != null) || (serviceIterator == null)) {
286
return;
287
}
288
synchronized (lock) {
289
if (spi != null) {
290
return;
291
}
292
if (debug != null) {
293
int w = --warnCount;
294
if (w >= 0) {
295
debug.println("Mac.init() not first method "
296
+ "called, disabling delayed provider selection");
297
if (w == 0) {
298
debug.println("Further warnings of this type will "
299
+ "be suppressed");
300
}
301
new Exception("Call trace").printStackTrace();
302
}
303
}
304
Exception lastException = null;
305
while ((firstService != null) || serviceIterator.hasNext()) {
306
Service s;
307
if (firstService != null) {
308
s = firstService;
309
firstService = null;
310
} else {
311
s = serviceIterator.next();
312
}
313
if (JceSecurity.canUseProvider(s.getProvider()) == false) {
314
continue;
315
}
316
try {
317
Object obj = s.newInstance(null);
318
if (obj instanceof MacSpi == false) {
319
continue;
320
}
321
spi = (MacSpi)obj;
322
provider = s.getProvider();
323
// not needed any more
324
firstService = null;
325
serviceIterator = null;
326
return;
327
} catch (NoSuchAlgorithmException e) {
328
lastException = e;
329
}
330
}
331
ProviderException e = new ProviderException
332
("Could not construct MacSpi instance");
333
if (lastException != null) {
334
e.initCause(lastException);
335
}
336
throw e;
337
}
338
}
339
340
private void chooseProvider(Key key, AlgorithmParameterSpec params)
341
throws InvalidKeyException, InvalidAlgorithmParameterException {
342
synchronized (lock) {
343
if (spi != null) {
344
spi.engineInit(key, params);
345
return;
346
}
347
Exception lastException = null;
348
while ((firstService != null) || serviceIterator.hasNext()) {
349
Service s;
350
if (firstService != null) {
351
s = firstService;
352
firstService = null;
353
} else {
354
s = serviceIterator.next();
355
}
356
// if provider says it does not support this key, ignore it
357
if (s.supportsParameter(key) == false) {
358
continue;
359
}
360
if (JceSecurity.canUseProvider(s.getProvider()) == false) {
361
continue;
362
}
363
try {
364
MacSpi spi = (MacSpi)s.newInstance(null);
365
spi.engineInit(key, params);
366
provider = s.getProvider();
367
this.spi = spi;
368
firstService = null;
369
serviceIterator = null;
370
return;
371
} catch (Exception e) {
372
// NoSuchAlgorithmException from newInstance()
373
// InvalidKeyException from init()
374
// RuntimeException (ProviderException) from init()
375
if (lastException == null) {
376
lastException = e;
377
}
378
}
379
}
380
// no working provider found, fail
381
if (lastException instanceof InvalidKeyException) {
382
throw (InvalidKeyException)lastException;
383
}
384
if (lastException instanceof InvalidAlgorithmParameterException) {
385
throw (InvalidAlgorithmParameterException)lastException;
386
}
387
if (lastException instanceof RuntimeException) {
388
throw (RuntimeException)lastException;
389
}
390
String kName = (key != null) ? key.getClass().getName() : "(null)";
391
throw new InvalidKeyException
392
("No installed provider supports this key: "
393
+ kName, lastException);
394
}
395
}
396
397
/**
398
* Returns the provider of this {@code Mac} object.
399
*
400
* @return the provider of this {@code Mac} object.
401
*/
402
public final Provider getProvider() {
403
chooseFirstProvider();
404
return this.provider;
405
}
406
407
/**
408
* Returns the length of the MAC in bytes.
409
*
410
* @return the MAC length in bytes.
411
*/
412
public final int getMacLength() {
413
chooseFirstProvider();
414
return spi.engineGetMacLength();
415
}
416
417
private String getProviderName() {
418
return (provider == null) ? "(no provider)" : provider.getName();
419
}
420
421
/**
422
* Initializes this {@code Mac} object with the given key.
423
*
424
* @param key the key.
425
*
426
* @exception InvalidKeyException if the given key is inappropriate for
427
* initializing this MAC.
428
*/
429
public final void init(Key key) throws InvalidKeyException {
430
try {
431
if (spi != null) {
432
spi.engineInit(key, null);
433
} else {
434
chooseProvider(key, null);
435
}
436
} catch (InvalidAlgorithmParameterException e) {
437
throw new InvalidKeyException("init() failed", e);
438
}
439
initialized = true;
440
441
if (!skipDebug && pdebug != null) {
442
pdebug.println("Mac." + algorithm + " algorithm from: " +
443
getProviderName());
444
}
445
}
446
447
/**
448
* Initializes this {@code Mac} object with the given key and
449
* algorithm parameters.
450
*
451
* @param key the key.
452
* @param params the algorithm parameters.
453
*
454
* @exception InvalidKeyException if the given key is inappropriate for
455
* initializing this MAC.
456
* @exception InvalidAlgorithmParameterException if the given algorithm
457
* parameters are inappropriate for this MAC.
458
*/
459
public final void init(Key key, AlgorithmParameterSpec params)
460
throws InvalidKeyException, InvalidAlgorithmParameterException {
461
if (spi != null) {
462
spi.engineInit(key, params);
463
} else {
464
chooseProvider(key, params);
465
}
466
initialized = true;
467
468
if (!skipDebug && pdebug != null) {
469
pdebug.println("Mac." + algorithm + " algorithm from: " +
470
getProviderName());
471
}
472
}
473
474
/**
475
* Processes the given byte.
476
*
477
* @param input the input byte to be processed.
478
*
479
* @exception IllegalStateException if this {@code Mac} has not been
480
* initialized.
481
*/
482
public final void update(byte input) throws IllegalStateException {
483
chooseFirstProvider();
484
if (initialized == false) {
485
throw new IllegalStateException("MAC not initialized");
486
}
487
spi.engineUpdate(input);
488
}
489
490
/**
491
* Processes the given array of bytes.
492
*
493
* @param input the array of bytes to be processed.
494
*
495
* @exception IllegalStateException if this {@code Mac} has not been
496
* initialized.
497
*/
498
public final void update(byte[] input) throws IllegalStateException {
499
chooseFirstProvider();
500
if (initialized == false) {
501
throw new IllegalStateException("MAC not initialized");
502
}
503
if (input != null) {
504
spi.engineUpdate(input, 0, input.length);
505
}
506
}
507
508
/**
509
* Processes the first {@code len} bytes in {@code input},
510
* starting at {@code offset} inclusive.
511
*
512
* @param input the input buffer.
513
* @param offset the offset in {@code input} where the input starts.
514
* @param len the number of bytes to process.
515
*
516
* @exception IllegalStateException if this {@code Mac} has not been
517
* initialized.
518
*/
519
public final void update(byte[] input, int offset, int len)
520
throws IllegalStateException {
521
chooseFirstProvider();
522
if (initialized == false) {
523
throw new IllegalStateException("MAC not initialized");
524
}
525
526
if (input != null) {
527
if ((offset < 0) || (len > (input.length - offset)) || (len < 0))
528
throw new IllegalArgumentException("Bad arguments");
529
spi.engineUpdate(input, offset, len);
530
}
531
}
532
533
/**
534
* Processes {@code input.remaining()} bytes in the ByteBuffer
535
* {@code input}, starting at {@code input.position()}.
536
* Upon return, the buffer's position will be equal to its limit;
537
* its limit will not have changed.
538
*
539
* @param input the ByteBuffer
540
*
541
* @exception IllegalStateException if this {@code Mac} has not been
542
* initialized.
543
* @since 1.5
544
*/
545
public final void update(ByteBuffer input) {
546
chooseFirstProvider();
547
if (initialized == false) {
548
throw new IllegalStateException("MAC not initialized");
549
}
550
if (input == null) {
551
throw new IllegalArgumentException("Buffer must not be null");
552
}
553
spi.engineUpdate(input);
554
}
555
556
/**
557
* Finishes the MAC operation.
558
*
559
* <p>A call to this method resets this {@code Mac} object to the
560
* state it was in when previously initialized via a call to
561
* {@code init(Key)} or
562
* {@code init(Key, AlgorithmParameterSpec)}.
563
* That is, the object is reset and available to generate another MAC from
564
* the same key, if desired, via new calls to {@code update} and
565
* {@code doFinal}.
566
* (In order to reuse this {@code Mac} object with a different key,
567
* it must be reinitialized via a call to {@code init(Key)} or
568
* {@code init(Key, AlgorithmParameterSpec)}.
569
*
570
* @return the MAC result.
571
*
572
* @exception IllegalStateException if this {@code Mac} has not been
573
* initialized.
574
*/
575
public final byte[] doFinal() throws IllegalStateException {
576
chooseFirstProvider();
577
if (initialized == false) {
578
throw new IllegalStateException("MAC not initialized");
579
}
580
byte[] mac = spi.engineDoFinal();
581
spi.engineReset();
582
return mac;
583
}
584
585
/**
586
* Finishes the MAC operation.
587
*
588
* <p>A call to this method resets this {@code Mac} object to the
589
* state it was in when previously initialized via a call to
590
* {@code init(Key)} or
591
* {@code init(Key, AlgorithmParameterSpec)}.
592
* That is, the object is reset and available to generate another MAC from
593
* the same key, if desired, via new calls to {@code update} and
594
* {@code doFinal}.
595
* (In order to reuse this {@code Mac} object with a different key,
596
* it must be reinitialized via a call to {@code init(Key)} or
597
* {@code init(Key, AlgorithmParameterSpec)}.
598
*
599
* <p>The MAC result is stored in {@code output}, starting at
600
* {@code outOffset} inclusive.
601
*
602
* @param output the buffer where the MAC result is stored
603
* @param outOffset the offset in {@code output} where the MAC is
604
* stored
605
*
606
* @exception ShortBufferException if the given output buffer is too small
607
* to hold the result
608
* @exception IllegalStateException if this {@code Mac} has not been
609
* initialized.
610
*/
611
public final void doFinal(byte[] output, int outOffset)
612
throws ShortBufferException, IllegalStateException
613
{
614
chooseFirstProvider();
615
if (initialized == false) {
616
throw new IllegalStateException("MAC not initialized");
617
}
618
int macLen = getMacLength();
619
if (output == null || output.length-outOffset < macLen) {
620
throw new ShortBufferException
621
("Cannot store MAC in output buffer");
622
}
623
byte[] mac = doFinal();
624
System.arraycopy(mac, 0, output, outOffset, macLen);
625
return;
626
}
627
628
/**
629
* Processes the given array of bytes and finishes the MAC operation.
630
*
631
* <p>A call to this method resets this {@code Mac} object to the
632
* state it was in when previously initialized via a call to
633
* {@code init(Key)} or
634
* {@code init(Key, AlgorithmParameterSpec)}.
635
* That is, the object is reset and available to generate another MAC from
636
* the same key, if desired, via new calls to {@code update} and
637
* {@code doFinal}.
638
* (In order to reuse this {@code Mac} object with a different key,
639
* it must be reinitialized via a call to {@code init(Key)} or
640
* {@code init(Key, AlgorithmParameterSpec)}.
641
*
642
* @param input data in bytes
643
* @return the MAC result.
644
*
645
* @exception IllegalStateException if this {@code Mac} has not been
646
* initialized.
647
*/
648
public final byte[] doFinal(byte[] input) throws IllegalStateException
649
{
650
chooseFirstProvider();
651
if (initialized == false) {
652
throw new IllegalStateException("MAC not initialized");
653
}
654
update(input);
655
return doFinal();
656
}
657
658
/**
659
* Resets this {@code Mac} object.
660
*
661
* <p>A call to this method resets this {@code Mac} object to the
662
* state it was in when previously initialized via a call to
663
* {@code init(Key)} or
664
* {@code init(Key, AlgorithmParameterSpec)}.
665
* That is, the object is reset and available to generate another MAC from
666
* the same key, if desired, via new calls to {@code update} and
667
* {@code doFinal}.
668
* (In order to reuse this {@code Mac} object with a different key,
669
* it must be reinitialized via a call to {@code init(Key)} or
670
* {@code init(Key, AlgorithmParameterSpec)}.
671
*/
672
public final void reset() {
673
chooseFirstProvider();
674
spi.engineReset();
675
}
676
677
/**
678
* Returns a clone if the provider implementation is cloneable.
679
*
680
* @return a clone if the provider implementation is cloneable.
681
*
682
* @exception CloneNotSupportedException if this is called on a
683
* delegate that does not support {@code Cloneable}.
684
*/
685
public final Object clone() throws CloneNotSupportedException {
686
chooseFirstProvider();
687
Mac that = (Mac)super.clone();
688
that.spi = (MacSpi)this.spi.clone();
689
return that;
690
}
691
}
692
693