1 /* DiffieHellmanImpl.java -- implementation of the Diffie-Hellman key agreement. 2 Copyright (C) 2005, 2006 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package gnu.javax.crypto.jce; 40 41 import java.math.BigInteger; 42 import java.security.InvalidKeyException; 43 import java.security.Key; 44 import java.security.SecureRandom; 45 import java.security.spec.AlgorithmParameterSpec; 46 47 import javax.crypto.KeyAgreementSpi; 48 import javax.crypto.SecretKey; 49 import javax.crypto.ShortBufferException; 50 import javax.crypto.interfaces.DHPrivateKey; 51 import javax.crypto.interfaces.DHPublicKey; 52 import javax.crypto.spec.DHParameterSpec; 53 import javax.crypto.spec.SecretKeySpec; 54 55 /** 56 * The JCE implementation of a 2-party Diffie-Hellman key agreement. 57 * 58 * @author Casey Marshall (csm@gnu.org) 59 */ 60 public final class DiffieHellmanImpl 61 extends KeyAgreementSpi 62 { 63 /** The private key being used for this agreement. */ 64 private DHPrivateKey key; 65 66 /** The current result. */ 67 private byte[] result; 68 69 /** True if the caller told us we are done. */ 70 private boolean last_phase_done; 71 72 /** Trivial default constructor. */ DiffieHellmanImpl()73 public DiffieHellmanImpl() 74 { 75 super(); 76 77 key = null; 78 result = null; 79 last_phase_done = false; 80 } 81 engineDoPhase(Key incoming, boolean lastPhase)82 protected Key engineDoPhase(Key incoming, boolean lastPhase) 83 throws InvalidKeyException 84 { 85 if (key == null) 86 throw new IllegalStateException("Not initialized"); 87 88 if (last_phase_done) 89 throw new IllegalStateException("Last phase already done"); 90 91 if (! (incoming instanceof DHPublicKey)) 92 throw new InvalidKeyException("Key MUST be a DHPublicKey"); 93 94 DHPublicKey pub = (DHPublicKey) incoming; 95 DHParameterSpec s1 = key.getParams(); 96 DHParameterSpec s2 = pub.getParams(); 97 if (! s1.getG().equals(s2.getG()) || ! s1.getP().equals(s2.getP())) 98 throw new InvalidKeyException("Incompatible key"); 99 if (! lastPhase) 100 throw new IllegalArgumentException( 101 "This key-agreement MUST be concluded in one step only"); 102 BigInteger resultBI = pub.getY().modPow(key.getX(), s1.getP()); 103 result = resultBI.toByteArray(); 104 if (result[0] == 0x00) 105 { 106 byte[] buf = new byte[result.length - 1]; 107 System.arraycopy(result, 1, buf, 0, buf.length); 108 result = buf; 109 } 110 last_phase_done = true; 111 return null; 112 } 113 engineGenerateSecret()114 protected byte[] engineGenerateSecret() 115 { 116 checkState(); 117 byte[] res = (byte[]) result.clone(); 118 reset(); 119 return res; 120 } 121 engineGenerateSecret(byte[] secret, int offset)122 protected int engineGenerateSecret(byte[] secret, int offset) 123 throws ShortBufferException 124 { 125 checkState(); 126 if (result.length > secret.length - offset) 127 throw new ShortBufferException(); 128 System.arraycopy(result, 0, secret, offset, result.length); 129 int res = result.length; 130 reset(); 131 return res; 132 } 133 engineGenerateSecret(String algorithm)134 protected SecretKey engineGenerateSecret(String algorithm) 135 throws InvalidKeyException 136 { 137 checkState(); 138 byte[] s = (byte[]) result.clone(); 139 SecretKey res = new SecretKeySpec(s, algorithm); 140 reset(); 141 return res; 142 } 143 engineInit(Key key, SecureRandom random)144 protected void engineInit(Key key, SecureRandom random) 145 throws InvalidKeyException 146 { 147 if (! (key instanceof DHPrivateKey)) 148 throw new InvalidKeyException("Key MUST be a DHPrivateKey"); 149 this.key = (DHPrivateKey) key; 150 reset(); 151 } 152 engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random)153 protected void engineInit(Key key, AlgorithmParameterSpec params, 154 SecureRandom random) 155 throws InvalidKeyException 156 { 157 engineInit(key, random); 158 } 159 reset()160 private void reset() 161 { 162 result = null; 163 last_phase_done = false; 164 } 165 checkState()166 private void checkState() 167 { 168 if (result == null || ! last_phase_done) 169 throw new IllegalStateException("Not finished"); 170 } 171 } 172