/** Copyright (C) 2012 Delcyon, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.delcyon.capo.crypto; import java.math.BigInteger; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map.Entry; import java.util.Set; import javax.crypto.Cipher; import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.interfaces.DHPublicKey; import javax.crypto.spec.DESKeySpec; import javax.crypto.spec.DHParameterSpec; import javax.xml.bind.DatatypeConverter; import org.w3c.dom.Element; import com.delcyon.capo.CapoApplication; import com.delcyon.capo.protocol.client.CapoConnection; import com.delcyon.capo.protocol.client.XMLRequest; import com.delcyon.capo.xml.XPath; /** * @author jeremiah * */ public class CertificateRequest extends XMLRequest { @SuppressWarnings("unchecked") private HashMap<Enum, String> parameterHashMap = new HashMap<Enum, String>(); public enum CertificateRequestType { DH } public enum Attributes { TYPE, SERVER_PUBLIC_KEY, CLIENT_PUBLIC_KEY, CLIENT_ID, SERVER_ID, DH_GENERATOR, DH_PRIME, DH_LENGTH, PHASE, PAYLOAD } private CertificateRequestType certificateRequestType = null; private CapoConnection capoConnection; private KeyAgreement keyAgreement1; private SecretKey secretKey1; private String payloadString; public CertificateRequest(CapoConnection capoConnection) throws Exception { super(); this.capoConnection = capoConnection; } @Override public void init() throws Exception { setInputStream(capoConnection.getInputStream()); setOutputStream(capoConnection.getOutputStream()); super.init(); } @SuppressWarnings("unchecked") @Override public Element getChildRootElement() throws Exception { Element updaterRequestElement = CapoApplication.getDefaultDocument("certificate_request.xml").getDocumentElement(); updaterRequestElement.setAttribute(Attributes.TYPE.toString(), certificateRequestType.toString()); Set<Entry<Enum, String>> parameterSet = parameterHashMap.entrySet(); for (Entry<Enum, String> entry : parameterSet) { updaterRequestElement.setAttribute(entry.getKey().toString(), entry.getValue()); } return updaterRequestElement; } public CertificateRequestType getCertificateRequestType() { return certificateRequestType; } public void setCertificateRequestType(CertificateRequestType certificateRequestType) { this.certificateRequestType = certificateRequestType; } @SuppressWarnings("unchecked") public void setParameter(Enum parameterName,String parameterValue) { parameterHashMap.put(parameterName, parameterValue); } @SuppressWarnings("unchecked") public String getParameter(Enum parameterName) { return parameterHashMap.get(parameterName); } public void clearParameters() { parameterHashMap.clear(); } public void loadDHPhase1() throws Exception { //create dh stuff //generate key pair KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH"); keyPairGenerator.initialize(1024); KeyPair keyPair = keyPairGenerator.generateKeyPair(); //get public key byte[] encodedPublicKey1 = keyPair.getPublic().getEncoded(); keyAgreement1 = KeyAgreement.getInstance("DH"); keyAgreement1.init(keyPair.getPrivate()); //get the key speces for remote DHParameterSpec dhParameterSpec = ((DHPublicKey) keyPair.getPublic()).getParams(); BigInteger dhParameterSpecGenerator = dhParameterSpec.getG(); BigInteger dhParameterSpecPrime = dhParameterSpec.getP(); int dhParameterSpecLength = dhParameterSpec.getL(); setParameter(Attributes.CLIENT_PUBLIC_KEY, DatatypeConverter.printBase64Binary(encodedPublicKey1)); setParameter(Attributes.DH_GENERATOR, dhParameterSpecGenerator.toString(16)); setParameter(Attributes.DH_PRIME, dhParameterSpecPrime.toString(16)); setParameter(Attributes.DH_LENGTH, dhParameterSpecLength+""); } public void parseResponse() throws Exception { Element responseElement = readResponse().getDocumentElement(); Element certificateRequestElement = (Element) XPath.selectSingleNode(responseElement, "//CertificateRequestResponse"); String publicKeyString = XPath.selectSingleNodeValue(certificateRequestElement, "//CertificateRequestResponse/@"+CertificateRequest.Attributes.SERVER_PUBLIC_KEY); payloadString = XPath.selectSingleNodeValue(certificateRequestElement, "//CertificateRequestResponse/@"+CertificateRequest.Attributes.PAYLOAD); String serverID = XPath.selectSingleNodeValue(certificateRequestElement, "//CertificateRequestResponse/@"+CertificateRequest.Attributes.SERVER_ID); setParameter(Attributes.SERVER_ID, serverID); String clientID = XPath.selectSingleNodeValue(certificateRequestElement, "//CertificateRequestResponse/@"+CertificateRequest.Attributes.CLIENT_ID); setParameter(Attributes.CLIENT_ID, clientID); KeyFactory keyFactory1 = KeyFactory.getInstance("DH"); X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(DatatypeConverter.parseBase64Binary(publicKeyString)); PublicKey publicKey2 = keyFactory1.generatePublic(x509Spec); //finish up key agreement with remote public key keyAgreement1.doPhase(publicKey2,true); //get local secret byte secret1[] = keyAgreement1.generateSecret(); //create secret key to encrypt things with SecretKeyFactory secretKeyFactory1 = SecretKeyFactory.getInstance("DES"); DESKeySpec desKeySpec1 = new DESKeySpec(secret1); secretKey1 = secretKeyFactory1.generateSecret(desKeySpec1); } public byte[] getDecryptedPayload() throws Exception { Cipher cipher1 = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher1.init(Cipher.DECRYPT_MODE, secretKey1); return cipher1.doFinal(DatatypeConverter.parseBase64Binary(payloadString)); } public void setPayload(String decryptedPayload) throws Exception { Cipher cipher1 = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher1.init(Cipher.ENCRYPT_MODE, secretKey1); byte[] encryptedPayload = cipher1.doFinal(decryptedPayload.getBytes()); setParameter(Attributes.PAYLOAD, DatatypeConverter.printBase64Binary(encryptedPayload)); } @SuppressWarnings("unchecked") public void resend() throws Exception { getImportedChildRootElement().setAttribute(Attributes.TYPE.toString(), certificateRequestType.toString()); Set<Entry<Enum, String>> parameterSet = parameterHashMap.entrySet(); for (Entry<Enum, String> entry : parameterSet) { getImportedChildRootElement().setAttribute(entry.getKey().toString(), entry.getValue()); } send(); } }