org.openid4java.association.DiffieHellmanSession Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2006-2008 Sxip Identity Corporation
*/
package org.openid4java.association;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHGenParameterSpec;
import javax.crypto.spec.DHPublicKeySpec;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.interfaces.DHPrivateKey;
import java.math.BigInteger;
import java.security.*;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author Marius Scurtescu, Johnny Bufu
*/
public class DiffieHellmanSession
{
private static Log _log = LogFactory.getLog(DiffieHellmanSession.class);
private static final boolean DEBUG = _log.isDebugEnabled();
public static final String DEFAULT_MODULUS_HEX =
"DCF93A0B883972EC0E19989AC5A2CE310E1D37717E8D9571BB7623731866E61E" +
"F75A2E27898B057F9891C2E27A639C3F29B60814581CD3B2CA3986D268370557" +
"7D45C2E7E52DC81C7A171876E5CEA74B1448BFDFAF18828EFD2519F14E45E382" +
"6634AF1949E5B535CC829A483B8A76223E5D490A257F05BDFF16F2FB22C583AB";
public static final String DEFAULT_MODULUS_BASE64 =
"ANz5OguIOXLsDhmYmsWizjEOHTdxfo2Vcbt2I3MYZuYe91ouJ4mLBX+YkcLiemOc" +
"Pym2CBRYHNOyyjmG0mg3BVd9RcLn5S3IHHoXGHblzqdLFEi/368Ygo79JRnxTkXj" +
"gmY0rxlJ5bU1zIKaSDuKdiI+XUkKJX8Fvf8W8vsixYOr";
public static final long DEFAULT_GENERATOR = 2;
public static final String DEFAULT_GENERATOR_BASE64 = "Ag==";
public static final String ALGORITHM = "DH";
public static final String H_ALGORITHM_SHA1 = "SHA-1";
public static final String H_ALGORITHM_SHA256 = "SHA-256";
private AssociationSessionType _type;
private DHParameterSpec _dhParameterSpec;
private KeyPair _keyPair;
private MessageDigest _hDigest;
private DiffieHellmanSession(AssociationSessionType type,
DHParameterSpec dhParameterSpec)
throws AssociationException
{
_type = type;
_dhParameterSpec = dhParameterSpec;
_keyPair = generateKeyPair(dhParameterSpec);
try
{
_hDigest = MessageDigest.getInstance(_type.getHAlgorithm());
}
catch (NoSuchAlgorithmException e)
{
throw new AssociationException("Unsupported H algorithm: " +
_type.getHAlgorithm(), e);
}
}
public String toString()
{
return _type + " base: " + _dhParameterSpec.getG()
+ " modulus: " + _dhParameterSpec.getP();
}
public static DiffieHellmanSession create(AssociationSessionType type,
String modulusBase64,
String generatorBase64)
throws AssociationException
{
byte[] modulus = Base64.decodeBase64(modulusBase64.getBytes());
byte[] generator = Base64.decodeBase64(generatorBase64.getBytes());
BigInteger p = new BigInteger(modulus);
BigInteger g = new BigInteger(generator);
DHParameterSpec dhParameterSpec = new DHParameterSpec(p, g);
return create(type, dhParameterSpec);
}
public static DiffieHellmanSession create(AssociationSessionType type,
DHParameterSpec dhParameterSpec)
throws AssociationException
{
DiffieHellmanSession dh = new DiffieHellmanSession(type, dhParameterSpec);
if (DEBUG) _log.debug("Created DH session: " + dh);
return dh;
}
public static DHParameterSpec getDefaultParameter()
{
BigInteger p = new BigInteger(DEFAULT_MODULUS_HEX, 16);
BigInteger g = BigInteger.valueOf(DEFAULT_GENERATOR);
return new DHParameterSpec(p, g);
}
public static DHParameterSpec generateRandomParameter(int primeSize, int keySize)
{
try
{
AlgorithmParameterGenerator paramGen =
AlgorithmParameterGenerator.getInstance(ALGORITHM);
DHGenParameterSpec genParameterSpec =
new DHGenParameterSpec(primeSize, keySize);
paramGen.init(genParameterSpec);
AlgorithmParameters params = paramGen.generateParameters();
DHParameterSpec result = (DHParameterSpec)
params.getParameterSpec(DHParameterSpec.class);
if (DEBUG) _log.debug("Generated random DHParameterSpec, base: "
+ result.getG() + ", modulus: " + result.getP());
return result;
}
catch (GeneralSecurityException e)
{
_log.error("Cannot generate DH params for primeSize: "
+ primeSize + " keySize: " + keySize, e);
return null;
}
}
protected static KeyPair generateKeyPair(DHParameterSpec dhSpec)
{
try
{
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
keyGen.initialize(dhSpec);
return keyGen.generateKeyPair();
}
catch (GeneralSecurityException e)
{
_log.error("Cannot generate key pair for DHParameterSpec, base: "
+ dhSpec.getG() + ", modulus: " + dhSpec.getP() );
return null;
}
}
public AssociationSessionType getType()
{
return _type;
}
/**
* Gets the modulus for the Diffie-Hellman key echange.
* This is the value passed in the openid.dh_modulus association
* request parameter.
*
* @return The base 64 encoded two's-complement representation of the
* modulus: base64(btwoc(p))
*/
public String getModulus()
{
BigInteger p = _dhParameterSpec.getP();
return new String(Base64.encodeBase64(p.toByteArray()));
}
/**
* Gets the generator for the Diffie-Hellman key echange.
* This is the value passed in the openid.dh_gen association
* request parameter.
*
* @return The base 64 encoded two's-complement representation of the
* generator: base64(btwoc(g))
*/
public String getGenerator()
{
BigInteger g = _dhParameterSpec.getG();
return new String(Base64.encodeBase64(g.toByteArray()));
}
/**
* Get the Diffie-Hellman public key.
* This is the value passed in the openid.dh_consumer_public
* association request parameter and the value passed in the
* openid.dh_server_public association response parameter.
*
* @return The base 64 encoded two's-complement representation of the
* public key: base64(btwoc(g ^ x mod p))
*/
public String getPublicKey()
{
DHPublicKey publicKey = (DHPublicKey) _keyPair.getPublic();
return publicKeyToString(publicKey);
}
protected DHPrivateKey getPrivateKey()
{
return (DHPrivateKey) _keyPair.getPrivate();
}
/**
* Encrypts the association MAC key. The encryption takes palce on the
* server side (aka OP). This is the value passed in the
* openid.enc_mac_key association response parameter.
*
* @param macKey The MAC key in binary format.
* @param consumerPublicKeyBase64 The base 64 encoding of the consumer
* Diffie-Hellman public key. This is the
* value passed in the
* openid.dh_consumer_public
* association request parameter.
* @return The base 64 encoded two's-complement
* representation of the encrypted mac key:
* base64(H(btwoc(g ^ (xa * xb) mod p)) XOR MAC)
* @throws AssociationException if the lengths of the mac key and digest
* of Diffie-Hellman shared secred do not
* match.
*/
public String encryptMacKey(byte[] macKey, String consumerPublicKeyBase64)
throws AssociationException
{
byte[] hzz = getDigestedZZ(consumerPublicKeyBase64);
if (hzz.length != macKey.length)
throw new AssociationException(
"MAC key legth different from shared secret digest length!");
byte[] encMacKey = new byte[hzz.length];
for (int i = 0; i < hzz.length; i++)
{
byte b1 = hzz[i];
byte b2 = macKey[i];
encMacKey[i] = (byte) (b1 ^ b2);
}
String encMacKeyBase64 = new String(Base64.encodeBase64(encMacKey));
if (DEBUG) _log.debug("Encrypted MAC key Base64: " + encMacKeyBase64);
return encMacKeyBase64;
}
/**
* Decrypts the association AMC key. The decryption takes palce on the
* consumer side (aka RP).
*
* @param encMacKeyBase64 The base 64 encoded two's-complement
* representation of the encrypted mac key:
* base64(H(btwoc(g ^ (xa * xb) mod p)) XOR MAC)
.
* This is the value passed in the
* openid.enc_mac_key association
* response parameter.
* @param serverPublicKeyBase64 The base 64 encoding of the server
* Diffie-Hellman public key. This is the
* value passed in the
* openid.dh_server_public
* association response parameter.
* @return The MAC key in binary format.
* @throws AssociationException if the lengths of the encrypted mac key
* and digest of Diffie-Hellman shared
* secret do not match.
*/
public byte[] decryptMacKey(String encMacKeyBase64, String serverPublicKeyBase64)
throws AssociationException
{
byte[] hzz = getDigestedZZ(serverPublicKeyBase64);
byte[] encMacKey = Base64.decodeBase64(encMacKeyBase64.getBytes());
if (hzz.length != encMacKey.length)
throw new AssociationException(
"Encrypted MAC key legth different from shared secret digest length!");
byte[] macKey = new byte[hzz.length];
for (int i = 0; i < hzz.length; i++)
{
byte b1 = hzz[i];
byte b2 = encMacKey[i];
macKey[i] = (byte) (b1 ^ b2);
}
if (DEBUG) _log.debug("Decrypted MAC key Base64: "
+ new String(Base64.encodeBase64(macKey)));
return macKey;
}
protected static String publicKeyToString(DHPublicKey publicKey)
{
return new String(Base64.encodeBase64(publicKey.getY().toByteArray()));
}
protected DHPublicKey stringToPublicKey(String publicKeyBase64)
{
try
{
byte[] yBinary = Base64.decodeBase64(publicKeyBase64.getBytes());
BigInteger y = new BigInteger(yBinary);
DHPublicKeySpec dhPublicKeySpec = new DHPublicKeySpec(
y, _dhParameterSpec.getP(), _dhParameterSpec.getG() );
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
return (DHPublicKey) keyFactory.generatePublic(dhPublicKeySpec);
}
catch (GeneralSecurityException e)
{
_log.error("Cannot create PublicKey object from: " + publicKeyBase64, e);
return null;
}
}
protected byte[] getDigestedZZ(String otherPublicKeyBase64)
{
DHPublicKey dhPublicKey = stringToPublicKey(otherPublicKeyBase64);
DHPrivateKey dhPrivateKey = getPrivateKey();
BigInteger xa = dhPrivateKey.getX();
BigInteger yb = dhPublicKey.getY();
BigInteger p = _dhParameterSpec.getP();
BigInteger zz = yb.modPow(xa, p);
return _hDigest.digest(zz.toByteArray());
}
private static boolean isDhSupported()
{
try
{
AlgorithmParameterGenerator.getInstance(ALGORITHM);
KeyPairGenerator.getInstance(ALGORITHM);
KeyFactory.getInstance(ALGORITHM);
return true;
}
catch (NoSuchAlgorithmException e)
{
return false;
}
}
public static boolean isDhSupported(AssociationSessionType type)
{
String hAlg = type.getHAlgorithm();
if (hAlg == null) // no encryption sessions
return true;
else
return isDhShaSupported(hAlg);
}
public static boolean isDhShaSupported(String shaAlgorithm)
{
if (!isDhSupported())
return false;
try
{
MessageDigest.getInstance(shaAlgorithm);
return true;
}
catch (NoSuchAlgorithmException e)
{
return false;
}
}
public static boolean isDhSha1Supported()
{
return isDhShaSupported(H_ALGORITHM_SHA1);
}
public static boolean isDhSha256Supported()
{
return isDhShaSupported(H_ALGORITHM_SHA256);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy