1 /* 2 * Copyright (c) 2018, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8184359 27 * @summary KeyPairGenerator Test with multiple threads. 28 * Arguments order <KeyExchangeAlgorithm> <Provider> <KeyGenAlgorithm> <Curve*> 29 * @run main MultiThreadTest DiffieHellman SunJCE DiffieHellman 30 * @run main MultiThreadTest ECDH SunEC EC 31 * @run main MultiThreadTest XDH SunEC XDH X25519 32 * @run main MultiThreadTest XDH SunEC XDH X448 33 */ 34 import java.security.KeyPair; 35 import java.security.KeyPairGenerator; 36 import java.util.Arrays; 37 import java.util.concurrent.CountDownLatch; 38 import java.util.concurrent.ExecutorService; 39 import java.util.concurrent.Executors; 40 import java.util.concurrent.ThreadFactory; 41 import javax.crypto.KeyAgreement; 42 43 /** 44 * This test targets KeyPairGenerator API related issue in a multi threaded 45 * context. 46 */ 47 public class MultiThreadTest { 48 49 // Tested a shared KeyPairGenerator with 100 number of threads. 50 private static final int THREAD_COUNT = 100; 51 main(String[] args)52 public static void main(String[] args) throws Exception { 53 54 String kaAlgo = args[0]; 55 String provider = args[1]; 56 String kpgAlgo = args[2]; 57 KeyPairGenerator kpg = genKeyGenerator(provider, kpgAlgo, 58 (args.length > 3) ? args[3] : kpgAlgo); 59 new MultiThreadTest().runTest(provider, kaAlgo, kpg); 60 } 61 62 /** 63 * Initialize KeyPairGenerator based on different algorithm names. 64 */ genKeyGenerator(String provider, String kpgAlgo, String kpgInit)65 private static KeyPairGenerator genKeyGenerator(String provider, 66 String kpgAlgo, String kpgInit) throws Exception { 67 68 KeyPairGenerator kpg = KeyPairGenerator.getInstance(kpgAlgo, provider); 69 switch (kpgInit) { 70 case "DiffieHellman": 71 kpg.initialize(512); 72 break; 73 case "EC": 74 kpg.initialize(256); 75 break; 76 case "X25519": 77 kpg.initialize(255); 78 break; 79 case "X448": 80 kpg.initialize(448); 81 break; 82 default: 83 throw new RuntimeException("Invalid Algo name " + kpgInit); 84 } 85 return kpg; 86 } 87 runTest(String provider, String kaAlgo, KeyPairGenerator kpg)88 private void runTest(String provider, String kaAlgo, KeyPairGenerator kpg) 89 throws Exception { 90 91 ExecutorService executor = null; 92 try { 93 executor = Executors.newCachedThreadPool(new ThreadFactory() { 94 @Override 95 public Thread newThread(Runnable r) { 96 Thread t = Executors.defaultThreadFactory().newThread(r); 97 t.setDaemon(true); 98 return t; 99 } 100 }); 101 CountDownLatch latch = new CountDownLatch(THREAD_COUNT); 102 103 for (int i = 0; i < THREAD_COUNT; i++) { 104 executor.execute(new Runnable() { 105 @Override 106 public void run() { 107 try { 108 testKeyAgreement(provider, kaAlgo, kpg); 109 } catch (Exception e) { 110 throw new RuntimeException(e); 111 } finally { 112 // Indicate a task completed. 113 latch.countDown(); 114 } 115 } 116 }); 117 } 118 // Wait till all tasks get complete. 119 latch.await(); 120 } finally { 121 if (executor != null) { 122 executor.shutdown(); 123 } 124 } 125 } 126 127 /** 128 * Perform KeyAgreement operation with a shared KeyPairGenerator instance. 129 */ testKeyAgreement(String provider, String kaAlgo, KeyPairGenerator kpg)130 private static void testKeyAgreement(String provider, String kaAlgo, 131 KeyPairGenerator kpg) throws Exception { 132 133 KeyPair kp1 = kpg.generateKeyPair(); 134 KeyPair kp2 = kpg.generateKeyPair(); 135 136 KeyAgreement ka1 = KeyAgreement.getInstance(kaAlgo, provider); 137 ka1.init(kp1.getPrivate()); 138 ka1.doPhase(kp2.getPublic(), true); 139 byte[] secret1 = ka1.generateSecret(); 140 KeyAgreement ka2 = KeyAgreement.getInstance(kaAlgo, provider); 141 ka2.init(kp2.getPrivate()); 142 ka2.doPhase(kp1.getPublic(), true); 143 byte[] secret2 = ka2.generateSecret(); 144 145 // With related keypairs, generated KeyAgreement secret should be same. 146 if (!Arrays.equals(secret1, secret2)) { 147 throw new Exception("KeyAgreement secret mismatch."); 148 } 149 } 150 } 151