1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.java.security; 18 19 import java.security.InvalidAlgorithmParameterException; 20 import java.security.InvalidParameterException; 21 import java.security.NoSuchAlgorithmException; 22 import java.security.Provider; 23 import java.security.SecureRandom; 24 import java.security.SecureRandomSpi; 25 import java.security.Security; 26 import java.security.cert.CRL; 27 import java.security.cert.CRLSelector; 28 import java.security.cert.CertSelector; 29 import java.security.cert.CertStoreException; 30 import java.security.cert.CertStoreParameters; 31 import java.security.cert.CertStoreSpi; 32 import java.security.cert.Certificate; 33 import java.security.interfaces.RSAPrivateKey; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.Collection; 37 import java.util.Collections; 38 import java.util.HashMap; 39 import java.util.HashSet; 40 import java.util.List; 41 import java.util.Locale; 42 import java.util.Map; 43 import java.util.Map.Entry; 44 import java.util.Set; 45 import java.util.TreeMap; 46 import java.util.regex.Matcher; 47 import java.util.regex.Pattern; 48 import javax.crypto.Cipher; 49 import javax.crypto.EncryptedPrivateKeyInfo; 50 import javax.crypto.NoSuchPaddingException; 51 import junit.framework.TestCase; 52 import libcore.javax.crypto.MockKey; 53 54 public class ProviderTest extends TestCase { 55 private static final boolean LOG_DEBUG = false; 56 57 /** 58 * Makes sure all all expected implementations (but not aliases) 59 * and that there are no extras, according to what we expect from 60 * StandardNames 61 */ 62 public void test_Provider_getServices() throws Exception { 63 // build set of expected algorithms 64 Map<String,Set<String>> remainingExpected 65 = new HashMap<String,Set<String>>(StandardNames.PROVIDER_ALGORITHMS); 66 for (Entry<String,Set<String>> entry : remainingExpected.entrySet()) { 67 entry.setValue(new HashSet<String>(entry.getValue())); 68 } 69 70 List<String> extra = new ArrayList<String>(); 71 List<String> missing = new ArrayList<String>(); 72 73 Provider[] providers = Security.getProviders(); 74 for (Provider provider : providers) { 75 String providerName = provider.getName(); 76 // ignore BouncyCastle provider if it is installed on the RI 77 if (StandardNames.IS_RI && providerName.equals("BC")) { 78 continue; 79 } 80 Set<Provider.Service> services = provider.getServices(); 81 assertNotNull(services); 82 assertFalse(services.isEmpty()); 83 84 for (Provider.Service service : services) { 85 String type = service.getType(); 86 String algorithm = service.getAlgorithm().toUpperCase(); 87 String className = service.getClassName(); 88 if (LOG_DEBUG) { 89 System.out.println(providerName 90 + " " + type 91 + " " + algorithm 92 + " " + className); 93 } 94 95 // remove from remaining, assert unknown if missing 96 Set<String> remainingAlgorithms = remainingExpected.get(type); 97 if (remainingAlgorithms == null || !remainingAlgorithms.remove(algorithm)) { 98 // seems to be missing, but sometimes the same 99 // algorithm is available from multiple providers 100 // (e.g. KeyFactory RSA is available from 101 // SunRsaSign and SunJSSE), so double check in 102 // original source before giving error 103 if (!(StandardNames.PROVIDER_ALGORITHMS.containsKey(type) 104 && StandardNames.PROVIDER_ALGORITHMS.get(type).contains(algorithm))) { 105 extra.add("Unknown " + type + " " + algorithm + " " + providerName + "\n"); 106 } 107 } else if ("Cipher".equals(type) && !algorithm.contains("/")) { 108 /* 109 * Cipher selection follows special rules where you can 110 * specify the mode and padding during the getInstance call. 111 * Try to see if the service supports this. 112 */ 113 Set<String> toRemove = new HashSet<String>(); 114 for (String remainingAlgo : remainingAlgorithms) { 115 String[] parts = remainingAlgo.split("/"); 116 if (parts.length == 3 && algorithm.equals(parts[0])) { 117 try { 118 Cipher.getInstance(remainingAlgo, provider); 119 toRemove.add(remainingAlgo); 120 } catch (NoSuchAlgorithmException ignored) { 121 } catch (NoSuchPaddingException ignored) { 122 } 123 } 124 } 125 remainingAlgorithms.removeAll(toRemove); 126 } 127 if (remainingAlgorithms != null && remainingAlgorithms.isEmpty()) { 128 remainingExpected.remove(type); 129 } 130 131 // make sure class exists and can be initialized 132 try { 133 assertNotNull(Class.forName(className, 134 true, 135 provider.getClass().getClassLoader())); 136 } catch (ClassNotFoundException e) { 137 // Sun forgot their own class 138 if (!className.equals("sun.security.pkcs11.P11MAC")) { 139 missing.add(className); 140 } 141 } 142 } 143 } 144 145 // assert that we don't have any extra in the implementation 146 Collections.sort(extra); // sort so that its grouped by type 147 assertEquals("Extra algorithms", Collections.EMPTY_LIST, extra); 148 149 // assert that we don't have any missing in the implementation 150 assertEquals("Missing algorithms", Collections.EMPTY_MAP, remainingExpected); 151 152 // assert that we don't have any missing classes 153 Collections.sort(missing); // sort it for readability 154 assertEquals("Missing classes", Collections.EMPTY_LIST, missing); 155 } 156 157 private static final Pattern alias = Pattern.compile("Alg\\.Alias\\.([^.]*)\\.(.*)"); 158 159 /** 160 * Makes sure all provider properties either point to a class 161 * implementation that exists or are aliases to known algorithms. 162 */ 163 public void test_Provider_Properties() throws Exception { 164 /* 165 * A useful reference on Provider properties 166 * <a href="http://java.sun.com/javase/6/docs/technotes/guides/security/crypto/HowToImplAProvider.html"> 167 * How to Implement a Provider in the Java ™ Cryptography Architecture 168 * </a> 169 */ 170 171 Provider[] providers = Security.getProviders(); 172 for (Provider provider : providers) { 173 // check Provider.id proprieties 174 assertEquals(provider.getName(), 175 provider.get("Provider.id name")); 176 assertEquals(String.valueOf(provider.getVersion()), 177 provider.get("Provider.id version")); 178 assertEquals(provider.getInfo(), 179 provider.get("Provider.id info")); 180 assertEquals(provider.getClass().getName(), 181 provider.get("Provider.id className")); 182 183 // build map of all known aliases and implementations 184 Map<String,String> aliases = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 185 Map<String,String> implementations = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); 186 for (Entry<Object,Object> entry : provider.entrySet()) { 187 Object k = entry.getKey(); 188 Object v = entry.getValue(); 189 assertEquals(String.class, k.getClass()); 190 assertEquals(String.class, v.getClass()); 191 String key = (String)k; 192 String value = (String)v; 193 194 // skip Provider.id keys, we check well known ones values above 195 if (key.startsWith("Provider.id ")) { 196 continue; 197 } 198 199 // skip property settings such as: "Signature.SHA1withDSA ImplementedIn" "Software" 200 if (key.indexOf(' ') != -1) { 201 continue; 202 } 203 204 Matcher m = alias.matcher(key); 205 if (m.find()) { 206 String type = m.group(1); 207 aliases.put(key, type + "." + value); 208 } else { 209 implementations.put(key, value); 210 } 211 } 212 213 // verify implementation classes are available 214 for (Entry<String,String> entry : implementations.entrySet()) { 215 String typeAndAlgorithm = entry.getKey(); 216 String className = entry.getValue(); 217 try { 218 assertNotNull(Class.forName(className, 219 true, 220 provider.getClass().getClassLoader())); 221 } catch (ClassNotFoundException e) { 222 // Sun forgot their own class 223 if (!className.equals("sun.security.pkcs11.P11MAC")) { 224 fail("Could not find class " + className + " for " + typeAndAlgorithm 225 + " [provider=" + provider.getName() + "]"); 226 } 227 } 228 } 229 230 // make sure all aliases point to some known implementation 231 for (Entry<String,String> entry : aliases.entrySet()) { 232 String alias = entry.getKey(); 233 String actual = entry.getValue(); 234 assertTrue("Could not find implementation " + actual + " for alias " + alias + 235 " [provider=" + provider.getName() + "]", 236 implementations.containsKey(actual)); 237 } 238 } 239 } 240 241 private static final String[] TYPES_SERVICES_CHECKED = new String[] { 242 "KeyFactory", "CertPathBuilder", "Cipher", "SecureRandom", 243 "AlgorithmParameterGenerator", "Signature", "KeyPairGenerator", "CertificateFactory", 244 "MessageDigest", "KeyAgreement", "CertStore", "SSLContext", "AlgorithmParameters", 245 "TrustManagerFactory", "KeyGenerator", "Mac", "CertPathValidator", "SecretKeyFactory", 246 "KeyManagerFactory", "KeyStore", 247 }; 248 249 private static final HashSet<String> TYPES_SUPPORTS_PARAMETER = new HashSet<String>( 250 Arrays.asList(new String[] { 251 "Mac", "KeyAgreement", "Cipher", "Signature", 252 })); 253 254 private static final HashSet<String> TYPES_NOT_SUPPORTS_PARAMETER = new HashSet<String>( 255 Arrays.asList(TYPES_SERVICES_CHECKED)); 256 static { 257 TYPES_NOT_SUPPORTS_PARAMETER.removeAll(TYPES_SUPPORTS_PARAMETER); 258 } 259 260 public void test_Provider_getServices_supportsParameter() throws Exception { 261 HashSet<String> remainingTypes = new HashSet<String>(Arrays.asList(TYPES_SERVICES_CHECKED)); 262 263 HashSet<String> supportsParameterTypes = new HashSet<String>(); 264 HashSet<String> noSupportsParameterTypes = new HashSet<String>(); 265 266 Provider[] providers = Security.getProviders(); 267 for (Provider provider : providers) { 268 Set<Provider.Service> services = provider.getServices(); 269 assertNotNull(services); 270 assertFalse(services.isEmpty()); 271 272 for (Provider.Service service : services) { 273 final String type = service.getType(); 274 remainingTypes.remove(type); 275 try { 276 service.supportsParameter(new MockKey()); 277 supportsParameterTypes.add(type); 278 } catch (InvalidParameterException e) { 279 noSupportsParameterTypes.add(type); 280 try { 281 service.supportsParameter(new Object()); 282 fail("Should throw on non-Key parameter"); 283 } catch (InvalidParameterException expected) { 284 } 285 } 286 } 287 } 288 289 supportsParameterTypes.retainAll(TYPES_SUPPORTS_PARAMETER); 290 assertEquals("Types that should support parameters", TYPES_SUPPORTS_PARAMETER, 291 supportsParameterTypes); 292 293 noSupportsParameterTypes.retainAll(TYPES_NOT_SUPPORTS_PARAMETER); 294 assertEquals("Types that should not support parameters", TYPES_NOT_SUPPORTS_PARAMETER, 295 noSupportsParameterTypes); 296 297 assertEquals("Types that should be checked", Collections.EMPTY_SET, remainingTypes); 298 } 299 300 public static class MockSpi { 301 public Object parameter; 302 303 public MockSpi(MockKey parameter) { 304 this.parameter = parameter; 305 } 306 }; 307 308 @SuppressWarnings("serial") 309 public void testProviderService_supportsParameter_UnknownService_Success() throws Exception { 310 Provider provider = new MockProvider("MockProvider") { 311 public void setup() { 312 put("Fake.FOO", MockSpi.class.getName()); 313 } 314 }; 315 316 Security.addProvider(provider); 317 try { 318 Provider.Service service = provider.getService("Fake", "FOO"); 319 assertTrue(service.supportsParameter(new Object())); 320 } finally { 321 Security.removeProvider(provider.getName()); 322 } 323 } 324 325 @SuppressWarnings("serial") 326 public void testProviderService_supportsParameter_KnownService_NoClassInitialization_Success() 327 throws Exception { 328 Provider provider = new MockProvider("MockProvider") { 329 public void setup() { 330 put("Signature.FOO", MockSpi.class.getName()); 331 put("Signature.FOO SupportedKeyClasses", getClass().getName() 332 + ".UninitializedMockKey"); 333 } 334 }; 335 336 Security.addProvider(provider); 337 try { 338 Provider.Service service = provider.getService("Signature", "FOO"); 339 assertFalse(service.supportsParameter(new MockKey())); 340 } finally { 341 Security.removeProvider(provider.getName()); 342 } 343 } 344 345 @SuppressWarnings("serial") 346 public static class UninitializedMockKey extends MockKey { 347 static { 348 fail("This should not be initialized"); 349 } 350 } 351 352 @SuppressWarnings("serial") 353 public void testProviderService_supportsParameter_TypeDoesNotSupportParameter_Failure() 354 throws Exception { 355 Provider provider = new MockProvider("MockProvider") { 356 public void setup() { 357 put("KeyFactory.FOO", MockSpi.class.getName()); 358 } 359 }; 360 361 Security.addProvider(provider); 362 try { 363 Provider.Service service = provider.getService("KeyFactory", "FOO"); 364 try { 365 service.supportsParameter(new MockKey()); 366 fail("Should always throw exception"); 367 } catch (InvalidParameterException expected) { 368 } 369 } finally { 370 Security.removeProvider(provider.getName()); 371 } 372 } 373 374 @SuppressWarnings("serial") 375 public void testProviderService_supportsParameter_SupportedKeyClasses_NonKeyClass_Success() 376 throws Exception { 377 Provider provider = new MockProvider("MockProvider") { 378 public void setup() { 379 put("Signature.FOO", MockSpi.class.getName()); 380 put("Signature.FOO SupportedKeyClasses", MockSpi.class.getName()); 381 } 382 }; 383 384 Security.addProvider(provider); 385 try { 386 Provider.Service service = provider.getService("Signature", "FOO"); 387 assertFalse(service.supportsParameter(new MockKey())); 388 } finally { 389 Security.removeProvider(provider.getName()); 390 } 391 } 392 393 @SuppressWarnings("serial") 394 public void testProviderService_supportsParameter_KnownService_NonKey_Failure() 395 throws Exception { 396 Provider provider = new MockProvider("MockProvider") { 397 public void setup() { 398 put("Signature.FOO", MockSpi.class.getName()); 399 } 400 }; 401 402 Security.addProvider(provider); 403 try { 404 Provider.Service service = provider.getService("Signature", "FOO"); 405 try { 406 service.supportsParameter(new Object()); 407 fail("Should throw when non-Key passed in"); 408 } catch (InvalidParameterException expected) { 409 } 410 } finally { 411 Security.removeProvider(provider.getName()); 412 } 413 } 414 415 @SuppressWarnings("serial") 416 public void testProviderService_supportsParameter_KnownService_SupportedKeyClasses_NonKey_Failure() 417 throws Exception { 418 Provider provider = new MockProvider("MockProvider") { 419 public void setup() { 420 put("Signature.FOO", MockSpi.class.getName()); 421 put("Signature.FOO SupportedKeyClasses", RSAPrivateKey.class.getName()); 422 } 423 }; 424 425 Security.addProvider(provider); 426 try { 427 Provider.Service service = provider.getService("Signature", "FOO"); 428 try { 429 service.supportsParameter(new Object()); 430 fail("Should throw on non-Key instance passed in"); 431 } catch (InvalidParameterException expected) { 432 } 433 } finally { 434 Security.removeProvider(provider.getName()); 435 } 436 } 437 438 @SuppressWarnings("serial") 439 public void testProviderService_supportsParameter_KnownService_Null_Failure() throws Exception { 440 Provider provider = new MockProvider("MockProvider") { 441 public void setup() { 442 put("Signature.FOO", MockSpi.class.getName()); 443 put("Signature.FOO SupportedKeyClasses", RSAPrivateKey.class.getName()); 444 } 445 }; 446 447 Security.addProvider(provider); 448 try { 449 Provider.Service service = provider.getService("Signature", "FOO"); 450 assertFalse(service.supportsParameter(null)); 451 } finally { 452 Security.removeProvider(provider.getName()); 453 } 454 } 455 456 @SuppressWarnings("serial") 457 public void testProviderService_supportsParameter_SupportedKeyClasses_Success() 458 throws Exception { 459 Provider provider = new MockProvider("MockProvider") { 460 public void setup() { 461 put("Signature.FOO", MockSpi.class.getName()); 462 put("Signature.FOO SupportedKeyClasses", MockKey.class.getName()); 463 } 464 }; 465 466 Security.addProvider(provider); 467 try { 468 Provider.Service service = provider.getService("Signature", "FOO"); 469 assertTrue(service.supportsParameter(new MockKey())); 470 } finally { 471 Security.removeProvider(provider.getName()); 472 } 473 } 474 475 @SuppressWarnings("serial") 476 public void testProviderService_supportsParameter_SupportedKeyClasses_Failure() 477 throws Exception { 478 Provider provider = new MockProvider("MockProvider") { 479 public void setup() { 480 put("Signature.FOO", MockSpi.class.getName()); 481 put("Signature.FOO SupportedKeyClasses", RSAPrivateKey.class.getName()); 482 } 483 }; 484 485 Security.addProvider(provider); 486 try { 487 Provider.Service service = provider.getService("Signature", "FOO"); 488 assertFalse(service.supportsParameter(new MockKey())); 489 } finally { 490 Security.removeProvider(provider.getName()); 491 } 492 } 493 494 @SuppressWarnings("serial") 495 public void testProviderService_supportsParameter_SupportedKeyFormats_Success() 496 throws Exception { 497 Provider provider = new MockProvider("MockProvider") { 498 public void setup() { 499 put("Signature.FOO", MockSpi.class.getName()); 500 put("Signature.FOO SupportedKeyFormats", new MockKey().getFormat()); 501 } 502 }; 503 504 Security.addProvider(provider); 505 try { 506 Provider.Service service = provider.getService("Signature", "FOO"); 507 assertTrue(service.supportsParameter(new MockKey())); 508 } finally { 509 Security.removeProvider(provider.getName()); 510 } 511 } 512 513 @SuppressWarnings("serial") 514 public void testProviderService_supportsParameter_SupportedKeyFormats_Failure() 515 throws Exception { 516 Provider provider = new MockProvider("MockProvider") { 517 public void setup() { 518 put("Signature.FOO", MockSpi.class.getName()); 519 put("Signature.FOO SupportedKeyFormats", "Invalid"); 520 } 521 }; 522 523 Security.addProvider(provider); 524 try { 525 Provider.Service service = provider.getService("Signature", "FOO"); 526 assertFalse(service.supportsParameter(new MockKey())); 527 } finally { 528 Security.removeProvider(provider.getName()); 529 } 530 } 531 532 @SuppressWarnings("serial") 533 public void testProviderService_newInstance_DoesNotCallSupportsParameter_Success() 534 throws Exception { 535 MockProvider provider = new MockProvider("MockProvider"); 536 537 provider.putServiceForTest(new Provider.Service(provider, "CertStore", "FOO", 538 MyCertStoreSpi.class.getName(), null, null) { 539 @Override 540 public boolean supportsParameter(Object parameter) { 541 fail("This should not be called"); 542 return false; 543 } 544 }); 545 546 Security.addProvider(provider); 547 try { 548 Provider.Service service = provider.getService("CertStore", "FOO"); 549 assertNotNull(service.newInstance(new MyCertStoreParameters())); 550 } finally { 551 Security.removeProvider(provider.getName()); 552 } 553 } 554 555 @SuppressWarnings("serial") 556 public void testProviderService_AliasDoesNotEraseCanonical_Success() 557 throws Exception { 558 // Make sure we start with a "known good" alias for this OID. 559 { 560 EncryptedPrivateKeyInfo epki1 = new EncryptedPrivateKeyInfo("OID.1.2.840.113549.1.1.5", 561 new byte[1]); 562 assertEquals("SHA1WITHRSA", epki1.getAlgName().toUpperCase(Locale.US)); 563 } 564 565 Provider provider = new MockProvider("MockProvider") { 566 public void setup() { 567 put("Signature.FOO", MockSpi.class.getName()); 568 put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "FOO"); 569 } 570 }; 571 572 Security.addProvider(provider); 573 try { 574 // This triggers a re-indexing of the algorithm id data: 575 try { 576 new EncryptedPrivateKeyInfo("nonexistent", new byte[1]); 577 fail("Should not find 'nonexistent' algorithm"); 578 } catch (NoSuchAlgorithmException expected) { 579 } 580 581 EncryptedPrivateKeyInfo epki2 = new EncryptedPrivateKeyInfo("OID.1.2.840.113549.1.1.5", new byte[1]); 582 assertEquals("SHA1WITHRSA", epki2.getAlgName().toUpperCase(Locale.US)); 583 } finally { 584 Security.removeProvider(provider.getName()); 585 } 586 } 587 588 @SuppressWarnings("serial") 589 public void testProviderService_CanFindNewOID_Success() 590 throws Exception { 591 Provider provider = new MockProvider("MockProvider") { 592 public void setup() { 593 put("Signature.NEWALG", MockSpi.class.getName()); 594 put("Alg.Alias.Signature.OID.1.2.9999.9999.9999", "NEWALG"); 595 } 596 }; 597 598 Security.addProvider(provider); 599 try { 600 EncryptedPrivateKeyInfo epki2 = new EncryptedPrivateKeyInfo("OID.1.2.9999.9999.9999", new byte[1]); 601 assertEquals("NEWALG", epki2.getAlgName().toUpperCase(Locale.US)); 602 } finally { 603 Security.removeProvider(provider.getName()); 604 } 605 } 606 607 public void testProvider_removeProvider_Success() throws Exception { 608 MockProvider provider = new MockProvider("MockProvider"); 609 assertNull(Security.getProvider(provider.getName())); 610 Security.addProvider(provider); 611 assertNotNull(Security.getProvider(provider.getName())); 612 Security.removeProvider(provider.getName()); 613 assertNull(Security.getProvider(provider.getName())); 614 } 615 616 public static class MyCertStoreSpi extends CertStoreSpi { 617 public MyCertStoreSpi(CertStoreParameters params) throws InvalidAlgorithmParameterException { 618 super(params); 619 } 620 621 @Override 622 public Collection<? extends Certificate> engineGetCertificates(CertSelector selector) 623 throws CertStoreException { 624 throw new UnsupportedOperationException(); 625 } 626 627 @Override 628 public Collection<? extends CRL> engineGetCRLs(CRLSelector selector) 629 throws CertStoreException { 630 throw new UnsupportedOperationException(); 631 } 632 } 633 634 public static class MyCertStoreParameters implements CertStoreParameters { 635 public Object clone() { 636 return new MyCertStoreParameters(); 637 } 638 } 639 640 /** 641 * http://code.google.com/p/android/issues/detail?id=21449 642 */ 643 public void testSecureRandomImplementationOrder() { 644 @SuppressWarnings("serial") 645 Provider srp = new MockProvider("SRProvider") { 646 public void setup() { 647 put("SecureRandom.SecureRandom1", SecureRandom1.class.getName()); 648 put("SecureRandom.SecureRandom2", SecureRandom2.class.getName()); 649 put("SecureRandom.SecureRandom3", SecureRandom3.class.getName()); 650 } 651 }; 652 try { 653 int position = Security.insertProviderAt(srp, 1); // first is one, not zero 654 assertEquals(1, position); 655 SecureRandom sr = new SecureRandom(); 656 if (!sr.getAlgorithm().equals("SecureRandom1")) { 657 throw new IllegalStateException("Expected SecureRandom1 was " + sr.getAlgorithm()); 658 } 659 } finally { 660 Security.removeProvider(srp.getName()); 661 } 662 } 663 664 @SuppressWarnings("serial") 665 private static class MockProvider extends Provider { 666 public MockProvider(String name) { 667 super(name, 1.0, "Mock provider used for testing"); 668 setup(); 669 } 670 671 public void setup() { 672 } 673 674 public void putServiceForTest(Provider.Service service) { 675 putService(service); 676 } 677 } 678 679 @SuppressWarnings("serial") 680 public static abstract class AbstractSecureRandom extends SecureRandomSpi { 681 protected void engineSetSeed(byte[] seed) { 682 throw new UnsupportedOperationException(); 683 } 684 protected void engineNextBytes(byte[] bytes) { 685 throw new UnsupportedOperationException(); 686 } 687 protected byte[] engineGenerateSeed(int numBytes) { 688 throw new UnsupportedOperationException(); 689 } 690 } 691 692 @SuppressWarnings("serial") 693 public static class SecureRandom1 extends AbstractSecureRandom {} 694 695 @SuppressWarnings("serial") 696 public static class SecureRandom2 extends AbstractSecureRandom {} 697 698 @SuppressWarnings("serial") 699 public static class SecureRandom3 extends AbstractSecureRandom {} 700 701 } 702