001: package org.bouncycastle.jce.provider;
002:
003: import org.bouncycastle.crypto.params.DESParameters;
004: import org.bouncycastle.util.Strings;
005:
006: import javax.crypto.KeyAgreementSpi;
007: import javax.crypto.SecretKey;
008: import javax.crypto.ShortBufferException;
009: import javax.crypto.interfaces.DHPrivateKey;
010: import javax.crypto.interfaces.DHPublicKey;
011: import javax.crypto.spec.DHParameterSpec;
012: import javax.crypto.spec.SecretKeySpec;
013: import java.math.BigInteger;
014: import java.security.InvalidAlgorithmParameterException;
015: import java.security.InvalidKeyException;
016: import java.security.Key;
017: import java.security.SecureRandom;
018: import java.security.spec.AlgorithmParameterSpec;
019: import java.util.Hashtable;
020:
021: /**
022: * Diffie-Hellman key agreement. There's actually a better way of doing this
023: * if you are using long term public keys, see the light-weight version for
024: * details.
025: */
026: public class JCEDHKeyAgreement extends KeyAgreementSpi {
027: private BigInteger x;
028: private BigInteger p;
029: private BigInteger g;
030: private BigInteger result;
031:
032: private SecureRandom random;
033:
034: private static final Hashtable algorithms = new Hashtable();
035:
036: static {
037: Integer i64 = new Integer(64);
038: Integer i192 = new Integer(192);
039: Integer i448 = new Integer(448);
040:
041: algorithms.put("DES", i64);
042: algorithms.put("DESEDE", i192);
043: algorithms.put("BLOWFISH", i448);
044: }
045:
046: private byte[] bigIntToBytes(BigInteger r) {
047: byte[] tmp = r.toByteArray();
048:
049: if (tmp[0] == 0) {
050: byte[] ntmp = new byte[tmp.length - 1];
051:
052: System.arraycopy(tmp, 1, ntmp, 0, ntmp.length);
053: return ntmp;
054: }
055:
056: return tmp;
057: }
058:
059: protected Key engineDoPhase(Key key, boolean lastPhase)
060: throws InvalidKeyException, IllegalStateException {
061: if (x == null) {
062: throw new IllegalStateException(
063: "Diffie-Hellman not initialised.");
064: }
065:
066: if (!(key instanceof DHPublicKey)) {
067: throw new InvalidKeyException(
068: "DHKeyAgreement doPhase requires DHPublicKey");
069: }
070: DHPublicKey pubKey = (DHPublicKey) key;
071:
072: if (!pubKey.getParams().getG().equals(g)
073: || !pubKey.getParams().getP().equals(p)) {
074: throw new InvalidKeyException(
075: "DHPublicKey not for this KeyAgreement!");
076: }
077:
078: if (lastPhase) {
079: result = ((DHPublicKey) key).getY().modPow(x, p);
080: return null;
081: } else {
082: result = ((DHPublicKey) key).getY().modPow(x, p);
083: }
084:
085: return new JCEDHPublicKey(result, pubKey.getParams());
086: }
087:
088: protected byte[] engineGenerateSecret()
089: throws IllegalStateException {
090: if (x == null) {
091: throw new IllegalStateException(
092: "Diffie-Hellman not initialised.");
093: }
094:
095: return bigIntToBytes(result);
096: }
097:
098: protected int engineGenerateSecret(byte[] sharedSecret, int offset)
099: throws IllegalStateException, ShortBufferException {
100: if (x == null) {
101: throw new IllegalStateException(
102: "Diffie-Hellman not initialised.");
103: }
104:
105: byte[] secret = bigIntToBytes(result);
106:
107: if (sharedSecret.length - offset < secret.length) {
108: throw new ShortBufferException(
109: "DHKeyAgreement - buffer too short");
110: }
111:
112: System
113: .arraycopy(secret, 0, sharedSecret, offset,
114: secret.length);
115:
116: return secret.length;
117: }
118:
119: protected SecretKey engineGenerateSecret(String algorithm) {
120: if (x == null) {
121: throw new IllegalStateException(
122: "Diffie-Hellman not initialised.");
123: }
124:
125: String algKey = Strings.toUpperCase(algorithm);
126: byte[] res = bigIntToBytes(result);
127:
128: if (algorithms.containsKey(algKey)) {
129: Integer length = (Integer) algorithms.get(algKey);
130:
131: byte[] key = new byte[length.intValue() / 8];
132: System.arraycopy(res, 0, key, 0, key.length);
133:
134: if (algKey.startsWith("DES")) {
135: DESParameters.setOddParity(key);
136: }
137:
138: return new SecretKeySpec(key, algorithm);
139: }
140:
141: return new SecretKeySpec(res, algorithm);
142: }
143:
144: protected void engineInit(Key key, AlgorithmParameterSpec params,
145: SecureRandom random) throws InvalidKeyException,
146: InvalidAlgorithmParameterException {
147: if (!(key instanceof DHPrivateKey)) {
148: throw new InvalidKeyException(
149: "DHKeyAgreement requires DHPrivateKey for initialisation");
150: }
151: DHPrivateKey privKey = (DHPrivateKey) key;
152:
153: this .random = random;
154:
155: if (params != null) {
156: if (!(params instanceof DHParameterSpec)) {
157: throw new InvalidAlgorithmParameterException(
158: "DHKeyAgreement only accepts DHParameterSpec");
159: }
160: DHParameterSpec p = (DHParameterSpec) params;
161:
162: this .p = p.getP();
163: this .g = p.getG();
164: } else {
165: this .p = privKey.getParams().getP();
166: this .g = privKey.getParams().getG();
167: }
168:
169: this .x = this .result = privKey.getX();
170: }
171:
172: protected void engineInit(Key key, SecureRandom random)
173: throws InvalidKeyException {
174: if (!(key instanceof DHPrivateKey)) {
175: throw new InvalidKeyException(
176: "DHKeyAgreement requires DHPrivateKey");
177: }
178:
179: DHPrivateKey privKey = (DHPrivateKey) key;
180:
181: this.random = random;
182: this.p = privKey.getParams().getP();
183: this.g = privKey.getParams().getG();
184: this.x = this.result = privKey.getX();
185: }
186: }
|