package com.dgrid.transport; import java.io.File; import java.security.Key; import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import com.dgrid.errors.TransportException; import com.dgrid.gen.Host; import com.dgrid.gen.InvalidApiKey; import com.dgrid.gen.InvalidHost; import com.dgrid.gen.InvalidJobId; import com.dgrid.gen.InvalidJobletId; import com.dgrid.gen.Job; import com.dgrid.gen.Joblet; import com.dgrid.gen.JobletResult; import com.dgrid.gen.NoHostAvailable; import com.dgrid.gen.NoWorkAvailable; import com.dgrid.service.DGridTransport; import com.dgrid.util.Base64Encoder; import com.dgrid.util.Encryption; import com.dgrid.util.io.InputStreamUtils; import com.dgrid.util.io.OutputStreamUtils; public class DGridEncryptedTransport implements DGridTransport { private DGridTransport delegate; private String desKeyPath; private String privateKeyPath; private String publicKeyPath; private KeyPair kp; private Key des; public void setDelegate(DGridTransport delegate) { this.delegate = delegate; } public void setApiKey(String apiKey) { delegate.setApiKey(apiKey); } public void setEndpoint(String endpoint) { delegate.setEndpoint(endpoint); } public void setPort(int port) { delegate.setPort(port); } public void setDesKeyPath(String path) { this.desKeyPath = path; } public void setPrivateKey(String path) { this.privateKeyPath = path; } public void setPublicKey(String path) { this.publicKeyPath = path; } public void init() throws Exception { Key priv = initRSAKey(privateKeyPath, true); Key pub = initRSAKey(publicKeyPath, false); this.kp = new KeyPair((PublicKey) pub, (PrivateKey) priv); this.des = initDESKey(); } public Host registerHost(String hostname) throws TransportException, InvalidApiKey, InvalidHost { return delegate.registerHost(hostname); } public void setHostFacts(int hostid, Map<String, String> facts) throws TransportException, InvalidApiKey, InvalidHost { delegate.setHostFacts(hostid, facts); } public Host getHost(int id) throws TransportException, InvalidApiKey, InvalidHost { return delegate.getHost(id); } public Host getHostByName(String hostname) throws TransportException, InvalidApiKey, InvalidHost { return delegate.getHostByName(hostname); } public String getHostSetting(int hostid, String name, String defaultValue) throws TransportException, InvalidApiKey, InvalidHost { return delegate.getHostSetting(hostid, name, defaultValue); } public String getSetting(String name, String defaultValue) throws TransportException, InvalidApiKey { return delegate.getSetting(name, defaultValue); } public void log(int jobletId, int jobletStatus, String message) throws TransportException, InvalidApiKey, InvalidJobletId { delegate.log(jobletId, jobletStatus, message); } public Job getJob(int jobId) throws TransportException, InvalidApiKey, InvalidJobId { return delegate.getJob(jobId); } public int getJobletQueueSize() throws TransportException, InvalidApiKey { return delegate.getJobletQueueSize(); } public List<Joblet> listActiveJoblets(String submitter, int offset, int limit) throws TransportException, InvalidApiKey { List<Joblet> joblets = delegate.listActiveJoblets(submitter, offset, limit); for (Joblet joblet : joblets) { decryptJoblet(joblet); } return joblets; } public JobletResult getJobletResult(int jobletId) throws TransportException, InvalidApiKey, InvalidJobletId { return delegate.getJobletResult(jobletId); } public List<JobletResult> getResults(int jobId) throws TransportException, InvalidApiKey, InvalidJobId { return delegate.getResults(jobId); } public Job submitJob(Job job) throws TransportException, InvalidApiKey { List<Joblet> joblets = job.getJoblets(); for (Joblet joblet : joblets) { signJoblet(joblet); encryptJoblet(joblet); } return delegate.submitJob(job); } public Joblet submitJoblet(Joblet joblet, int jobId, int callbackType, String callbackAddress, String callbackContent) throws TransportException, InvalidApiKey, InvalidJobId { signJoblet(joblet); encryptJoblet(joblet); return delegate.submitJoblet(joblet, jobId, callbackType, callbackAddress, callbackContent); } public Joblet getWork() throws TransportException, InvalidApiKey, InvalidHost, NoWorkAvailable { Joblet joblet = delegate.getWork(); decryptJoblet(joblet); if (!verify(joblet)) throw new RuntimeException(String.format( "Could not verify signature on joblet # %1$d", joblet .getId())); return joblet; } public void completeJoblet(int jobletId, JobletResult result, String logMessage) throws TransportException, InvalidApiKey, InvalidJobletId { delegate.completeJoblet(jobletId, result, logMessage); } public JobletResult gridExecute(Joblet joblet, int retries) throws InvalidApiKey, TransportException, NoHostAvailable { return delegate.gridExecute(joblet, retries); } public void releaseJoblet(int jobletId) throws InvalidApiKey, TransportException, InvalidJobletId { delegate.releaseJoblet(jobletId); } private void signJoblet(Joblet joblet) { if ((joblet.getContent() != null) && (joblet.getContent().length() > 0)) { String sig = Encryption.signString(joblet.getContent(), kp .getPrivate(), Encryption.SHA1withRSA); joblet.getParameters().put("signature", sig); } } private void encryptJoblet(Joblet joblet) throws RuntimeException { if ((joblet.getContent() != null) && (joblet.getContent().length() > 0)) { joblet.setContent(Encryption.encryptStringBase64(joblet .getContent(), Encryption.DES_PADDED, des)); } Set<Entry<String, String>> entries = joblet.getParameters().entrySet(); for (Entry<String, String> entry : entries) { String encryptedValue = Encryption.encryptStringBase64(entry .getValue(), Encryption.DES_PADDED, des); joblet.getParameters().put(entry.getKey(), encryptedValue); } } private void decryptJoblet(Joblet joblet) throws RuntimeException { if ((joblet.getContent() != null) && (joblet.getContent().length() > 0)) { joblet.setContent(Encryption.decryptStringBase64(joblet .getContent(), Encryption.DES_PADDED, des)); } Set<Entry<String, String>> entries = joblet.getParameters().entrySet(); for (Entry<String, String> entry : entries) { String decryptedValue = Encryption.decryptStringBase64(entry .getValue(), Encryption.DES_PADDED, des); joblet.getParameters().put(entry.getKey(), decryptedValue); } } private boolean verify(Joblet joblet) throws RuntimeException { if ((joblet.getContent() == null) || (joblet.getContent().length() == 0)) return true; String sig = joblet.getParameters().get("signature"); return Encryption.verifyBase64(joblet.getContent(), kp.getPublic(), Encryption.SHA1withRSA, sig); } private Key initRSAKey(String path, boolean isPrivateKey) throws Exception { File file = new File(path); Key key = null; if (file.exists()) { String b64Key = InputStreamUtils.getFileAsString(file); key = Encryption.getKey(Base64Encoder.base64Decode(b64Key) .getBytes(), Encryption.RSA, isPrivateKey); } else { KeyPair keyPair = Encryption.generateKeyPair(Encryption.RSA, 1024); OutputStreamUtils.writeStringToFile(new String(Base64Encoder .base64Encode(keyPair.getPrivate().getEncoded())), new File(privateKeyPath)); OutputStreamUtils.writeStringToFile(new String(Base64Encoder .base64Encode(keyPair.getPublic().getEncoded())), new File( publicKeyPath)); key = (isPrivateKey) ? keyPair.getPrivate() : keyPair.getPublic(); } return key; } private Key initDESKey() throws Exception { File file = new File(desKeyPath); Key key = null; if (file.exists()) { String b64Key = InputStreamUtils.getFileAsString(file); key = Encryption.getSecretKey(Encryption.DES, Base64Encoder .base64Decode(b64Key.getBytes())); } else { key = Encryption.generateSecretKey(Encryption.DES); OutputStreamUtils.writeStringToFile(new String(Base64Encoder .base64Encode(key.getEncoded())), file); } return key; } }