1/* 2 * Copyright (c) 1997, 2015, 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 7146728 27 * @summary DHKeyAgreement2 28 * @author Jan Luehe 29 */ 30 31import java.io.*; 32import java.math.BigInteger; 33import java.security.*; 34import java.security.spec.*; 35import java.security.interfaces.*; 36import javax.crypto.*; 37import javax.crypto.spec.*; 38import javax.crypto.interfaces.*; 39 40/** 41 * This test utility executes the Diffie-Hellman key agreement protocol 42 * between 2 parties: Alice and Bob. 43 * 44 * By default, preconfigured parameters (1024 bit prime modulus and base 45 * generator used by SKIP) are used. 46 * If this program is called with the "-gen" option, a new set of parameters 47 * are created. 48 */ 49 50public class DHKeyAgreement2 { 51 52 private static final String SUNJCE = "SunJCE"; 53 private DHKeyAgreement2() {} 54 55 public static void main(String argv[]) throws Exception { 56 String mode = "USE_SKIP_DH_PARAMS"; 57 58 DHKeyAgreement2 keyAgree = new DHKeyAgreement2(); 59 60 if (argv.length > 1) { 61 keyAgree.usage(); 62 throw new Exception("Wrong number of command options"); 63 } else if (argv.length == 1) { 64 if (!(argv[0].equals("-gen"))) { 65 keyAgree.usage(); 66 throw new Exception("Unrecognized flag: " + argv[0]); 67 } 68 mode = "GENERATE_DH_PARAMS"; 69 } 70 71 keyAgree.run(mode); 72 System.out.println("Test Passed"); 73 } 74 75 private void run(String mode) throws Exception { 76 77 DHParameterSpec dhSkipParamSpec; 78 79 if (mode.equals("GENERATE_DH_PARAMS")) { 80 // Some central authority creates new DH parameters 81 System.err.println("Creating Diffie-Hellman parameters ..."); 82 AlgorithmParameterGenerator paramGen 83 = AlgorithmParameterGenerator.getInstance("DH", SUNJCE); 84 paramGen.init(512); 85 AlgorithmParameters params = paramGen.generateParameters(); 86 dhSkipParamSpec = (DHParameterSpec)params.getParameterSpec 87 (DHParameterSpec.class); 88 } else { 89 // use some pre-generated, default DH parameters 90 System.err.println("Using SKIP Diffie-Hellman parameters"); 91 dhSkipParamSpec = new DHParameterSpec(skip1024Modulus, 92 skip1024Base); 93 } 94 95 /* 96 * Alice creates her own DH key pair, using the DH parameters from 97 * above 98 */ 99 System.err.println("ALICE: Generate DH keypair ..."); 100 KeyPairGenerator aliceKpairGen = KeyPairGenerator.getInstance("DH", SUNJCE); 101 aliceKpairGen.initialize(dhSkipParamSpec); 102 KeyPair aliceKpair = aliceKpairGen.generateKeyPair(); 103 System.out.println("Alice DH public key:\n" + 104 aliceKpair.getPublic().toString()); 105 System.out.println("Alice DH private key:\n" + 106 aliceKpair.getPrivate().toString()); 107 DHParameterSpec dhParamSpec = 108 ((DHPublicKey)aliceKpair.getPublic()).getParams(); 109 AlgorithmParameters algParams = AlgorithmParameters.getInstance("DH", SUNJCE); 110 algParams.init(dhParamSpec); 111 System.out.println("Alice DH parameters:\n" 112 + algParams.toString()); 113 114 // Alice executes Phase1 of her version of the DH protocol 115 System.err.println("ALICE: Execute PHASE1 ..."); 116 KeyAgreement aliceKeyAgree = KeyAgreement.getInstance("DH", SUNJCE); 117 aliceKeyAgree.init(aliceKpair.getPrivate()); 118 119 // Alice encodes her public key, and sends it over to Bob. 120 byte[] alicePubKeyEnc = aliceKpair.getPublic().getEncoded(); 121 122 /* 123 * Let's turn over to Bob. Bob has received Alice's public key 124 * in encoded format. 125 * He instantiates a DH public key from the encoded key material. 126 */ 127 KeyFactory bobKeyFac = KeyFactory.getInstance("DH", SUNJCE); 128 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec 129 (alicePubKeyEnc); 130 PublicKey alicePubKey = bobKeyFac.generatePublic(x509KeySpec); 131 132 /* 133 * Bob gets the DH parameters associated with Alice's public key. 134 * He must use the same parameters when he generates his own key 135 * pair. 136 */ 137 dhParamSpec = ((DHPublicKey)alicePubKey).getParams(); 138 139 // Bob creates his own DH key pair 140 System.err.println("BOB: Generate DH keypair ..."); 141 KeyPairGenerator bobKpairGen = KeyPairGenerator.getInstance("DH", SUNJCE); 142 bobKpairGen.initialize(dhParamSpec); 143 KeyPair bobKpair = bobKpairGen.generateKeyPair(); 144 System.out.println("Bob DH public key:\n" + 145 bobKpair.getPublic().toString()); 146 System.out.println("Bob DH private key:\n" + 147 bobKpair.getPrivate().toString()); 148 149 // Bob executes Phase1 of his version of the DH protocol 150 System.err.println("BOB: Execute PHASE1 ..."); 151 KeyAgreement bobKeyAgree = KeyAgreement.getInstance("DH", SUNJCE); 152 bobKeyAgree.init(bobKpair.getPrivate()); 153 154 // Bob encodes his public key, and sends it over to Alice. 155 byte[] bobPubKeyEnc = bobKpair.getPublic().getEncoded(); 156 157 /* 158 * Alice uses Bob's public key for Phase2 of her version of the DH 159 * protocol. 160 * Before she can do so, she has to instanticate a DH public key 161 * from Bob's encoded key material. 162 */ 163 KeyFactory aliceKeyFac = KeyFactory.getInstance("DH", SUNJCE); 164 x509KeySpec = new X509EncodedKeySpec(bobPubKeyEnc); 165 PublicKey bobPubKey = aliceKeyFac.generatePublic(x509KeySpec); 166 System.err.println("ALICE: Execute PHASE2 ..."); 167 aliceKeyAgree.doPhase(bobPubKey, true); 168 169 /* 170 * Bob uses Alice's public key for Phase2 of his version of the DH 171 * protocol. 172 */ 173 System.err.println("BOB: Execute PHASE2 ..."); 174 bobKeyAgree.doPhase(alicePubKey, true); 175 176 /* 177 * At this stage, both Alice and Bob have completed the DH key 178 * agreement protocol. 179 * Each generates the (same) shared secret. 180 */ 181 byte[] aliceSharedSecret = aliceKeyAgree.generateSecret(); 182 int aliceLen = aliceSharedSecret.length; 183 184 // check if alice's key agreement has been reset afterwards 185 try { 186 aliceKeyAgree.generateSecret(); 187 throw new Exception("Error: alice's KeyAgreement not reset"); 188 } catch (IllegalStateException e) { 189 System.out.println("EXPECTED: " + e.getMessage()); 190 } 191 192 byte[] bobSharedSecret = new byte[aliceLen]; 193 int bobLen; 194 try { 195 // provide output buffer that is too short 196 bobLen = bobKeyAgree.generateSecret(bobSharedSecret, 1); 197 } catch (ShortBufferException e) { 198 System.out.println("EXPECTED: " + e.getMessage()); 199 } 200 // retry w/ output buffer of required size 201 bobLen = bobKeyAgree.generateSecret(bobSharedSecret, 0); 202 203 // check if bob's key agreement has been reset afterwards 204 try { 205 bobKeyAgree.generateSecret(bobSharedSecret, 0); 206 throw new Exception("Error: bob's KeyAgreement not reset"); 207 } catch (IllegalStateException e) { 208 System.out.println("EXPECTED: " + e.getMessage()); 209 } 210 211 System.out.println("Alice secret: " + toHexString(aliceSharedSecret)); 212 System.out.println("Bob secret: " + toHexString(bobSharedSecret)); 213 214 if (aliceLen != bobLen) { 215 throw new Exception("Shared secrets have different lengths"); 216 } 217 for (int i=0; i<aliceLen; i++) { 218 if (aliceSharedSecret[i] != bobSharedSecret[i]) { 219 throw new Exception("Shared secrets differ"); 220 } 221 } 222 System.err.println("Shared secrets are the same"); 223 224 // Now let's return the shared secret as a SecretKey object 225 // and use it for encryption 226 System.out.println("Return shared secret as SecretKey object ..."); 227 bobKeyAgree.doPhase(alicePubKey, true); 228 SecretKey desKey = bobKeyAgree.generateSecret("DES"); 229 230 Cipher desCipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); 231 desCipher.init(Cipher.ENCRYPT_MODE, desKey); 232 233 byte[] cleartext = "This is just an example".getBytes(); 234 byte[] ciphertext = desCipher.doFinal(cleartext); 235 236 desCipher.init(Cipher.DECRYPT_MODE, desKey); 237 byte[] cleartext1 = desCipher.doFinal(ciphertext); 238 239 int clearLen = cleartext.length; 240 int clear1Len = cleartext1.length; 241 if (clearLen != clear1Len) { 242 throw new Exception("DIFFERENT"); 243 } 244 for (int i=0; i < clear1Len; i++) { 245 if (cleartext[i] != cleartext1[i]) { 246 throw new Exception("DIFFERENT"); 247 } 248 } 249 System.err.println("SAME"); 250 } 251 252 /* 253 * Converts a byte to hex digit and writes to the supplied buffer 254 */ 255 private void byte2hex(byte b, StringBuffer buf) { 256 char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', 257 '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 258 int high = ((b & 0xf0) >> 4); 259 int low = (b & 0x0f); 260 buf.append(hexChars[high]); 261 buf.append(hexChars[low]); 262 } 263 264 /* 265 * Converts a byte array to hex string 266 */ 267 private String toHexString(byte[] block) { 268 StringBuffer buf = new StringBuffer(); 269 270 int len = block.length; 271 272 for (int i = 0; i < len; i++) { 273 byte2hex(block[i], buf); 274 if (i < len-1) { 275 buf.append(":"); 276 } 277 } 278 return buf.toString(); 279 } 280 281 /* 282 * Prints the usage of this test. 283 */ 284 private void usage() { 285 System.err.print("DHKeyAgreement usage: "); 286 System.err.println("[-gen]"); 287 } 288 289 // The 1024 bit Diffie-Hellman modulus values used by SKIP 290 private static final byte skip1024ModulusBytes[] = { 291 (byte)0xF4, (byte)0x88, (byte)0xFD, (byte)0x58, 292 (byte)0x4E, (byte)0x49, (byte)0xDB, (byte)0xCD, 293 (byte)0x20, (byte)0xB4, (byte)0x9D, (byte)0xE4, 294 (byte)0x91, (byte)0x07, (byte)0x36, (byte)0x6B, 295 (byte)0x33, (byte)0x6C, (byte)0x38, (byte)0x0D, 296 (byte)0x45, (byte)0x1D, (byte)0x0F, (byte)0x7C, 297 (byte)0x88, (byte)0xB3, (byte)0x1C, (byte)0x7C, 298 (byte)0x5B, (byte)0x2D, (byte)0x8E, (byte)0xF6, 299 (byte)0xF3, (byte)0xC9, (byte)0x23, (byte)0xC0, 300 (byte)0x43, (byte)0xF0, (byte)0xA5, (byte)0x5B, 301 (byte)0x18, (byte)0x8D, (byte)0x8E, (byte)0xBB, 302 (byte)0x55, (byte)0x8C, (byte)0xB8, (byte)0x5D, 303 (byte)0x38, (byte)0xD3, (byte)0x34, (byte)0xFD, 304 (byte)0x7C, (byte)0x17, (byte)0x57, (byte)0x43, 305 (byte)0xA3, (byte)0x1D, (byte)0x18, (byte)0x6C, 306 (byte)0xDE, (byte)0x33, (byte)0x21, (byte)0x2C, 307 (byte)0xB5, (byte)0x2A, (byte)0xFF, (byte)0x3C, 308 (byte)0xE1, (byte)0xB1, (byte)0x29, (byte)0x40, 309 (byte)0x18, (byte)0x11, (byte)0x8D, (byte)0x7C, 310 (byte)0x84, (byte)0xA7, (byte)0x0A, (byte)0x72, 311 (byte)0xD6, (byte)0x86, (byte)0xC4, (byte)0x03, 312 (byte)0x19, (byte)0xC8, (byte)0x07, (byte)0x29, 313 (byte)0x7A, (byte)0xCA, (byte)0x95, (byte)0x0C, 314 (byte)0xD9, (byte)0x96, (byte)0x9F, (byte)0xAB, 315 (byte)0xD0, (byte)0x0A, (byte)0x50, (byte)0x9B, 316 (byte)0x02, (byte)0x46, (byte)0xD3, (byte)0x08, 317 (byte)0x3D, (byte)0x66, (byte)0xA4, (byte)0x5D, 318 (byte)0x41, (byte)0x9F, (byte)0x9C, (byte)0x7C, 319 (byte)0xBD, (byte)0x89, (byte)0x4B, (byte)0x22, 320 (byte)0x19, (byte)0x26, (byte)0xBA, (byte)0xAB, 321 (byte)0xA2, (byte)0x5E, (byte)0xC3, (byte)0x55, 322 (byte)0xE9, (byte)0x2F, (byte)0x78, (byte)0xC7 323 }; 324 325 // The SKIP 1024 bit modulus 326 private static final BigInteger skip1024Modulus 327 = new BigInteger(1, skip1024ModulusBytes); 328 329 // The base used with the SKIP 1024 bit modulus 330 private static final BigInteger skip1024Base = BigInteger.valueOf(2); 331} 332