cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From chipchild...@apache.org
Subject git commit: updated refs/heads/4.1 to 73ed03b
Date Tue, 16 Apr 2013 00:45:41 GMT
Updated Branches:
  refs/heads/4.1 30c837cc6 -> 73ed03bae


CLOUDSTACK-2039: Improve console access security with 128-bit AES encryption and securely-randomized
key generation


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/73ed03ba
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/73ed03ba
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/73ed03ba

Branch: refs/heads/4.1
Commit: 73ed03baea3f6718f74703b752a61c4314246a69
Parents: 30c837c
Author: Kelven Yang <kelveny@gmail.com>
Authored: Mon Apr 15 16:51:50 2013 -0700
Committer: Chip Childers <chip.childers@gmail.com>
Committed: Tue Apr 16 01:42:29 2013 +0100

----------------------------------------------------------------------
 .../ConsoleProxyPasswordBasedEncryptor.java        |  253 +++++++++------
 server/src/com/cloud/configuration/Config.java     |    2 +
 .../consoleproxy/ConsoleProxyManagerImpl.java      |   47 ++-
 server/src/com/cloud/server/ManagementServer.java  |    3 +
 .../src/com/cloud/server/ManagementServerImpl.java |   61 ++++-
 .../ConsoleProxyPasswordBasedEncryptor.java        |   99 +++++--
 .../src/com/cloud/servlet/ConsoleProxyServlet.java |   16 +-
 7 files changed, 342 insertions(+), 139 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73ed03ba/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java
----------------------------------------------------------------------
diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java
b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java
index 29826f0..5a7241a 100644
--- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java
+++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java
@@ -16,13 +16,16 @@
 // under the License.
 package com.cloud.consoleproxy;
 
+import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 
 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
 import javax.crypto.IllegalBlockSizeException;
 import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
 import org.apache.commons.codec.binary.Base64;
@@ -33,110 +36,162 @@ import com.google.gson.GsonBuilder;
 
 /**
  * 
- * A simple password based encyrptor based on DES. It can serialize simple POJO object into
URL safe string
+ * @author Kelven Yang
+ * A simple password based encyrptor based on AES/CBC. It can serialize simple POJO object
into URL safe string
  * and deserialize it back.
  * 
  */
 public class ConsoleProxyPasswordBasedEncryptor {
-    private static final Logger s_logger = Logger.getLogger(ConsoleProxyPasswordBasedEncryptor.class);
-    
-    private String password;
-    private Gson gson;
-    
-    public ConsoleProxyPasswordBasedEncryptor(String password) {
-        this.password = password;
-        gson = new GsonBuilder().create();
-    }
-    
-    public String encryptText(String text) {
-        if(text == null || text.isEmpty())
-            return text;
-        
-        assert(password != null);
-        assert(!password.isEmpty());
-        
-        try {
-            Cipher cipher = Cipher.getInstance("DES");
-            int maxKeySize = 8;
-            SecretKeySpec keySpec = new SecretKeySpec(normalizeKey(password.getBytes(), maxKeySize),
"DES");
-            cipher.init(Cipher.ENCRYPT_MODE, keySpec);
-            byte[] encryptedBytes = cipher.doFinal(text.getBytes());
-            return Base64.encodeBase64URLSafeString(encryptedBytes);
-        } catch (NoSuchAlgorithmException e) {
-            s_logger.error("Unexpected exception ", e);
-            return null;
-        } catch (NoSuchPaddingException e) {
-            s_logger.error("Unexpected exception ", e);
-            return null;
-        } catch (IllegalBlockSizeException e) {
-            s_logger.error("Unexpected exception ", e);
-            return null;
-        } catch (BadPaddingException e) {
-            s_logger.error("Unexpected exception ", e);
-            return null;
-        } catch (InvalidKeyException e) {
-            s_logger.error("Unexpected exception ", e);
-            return null;
-        }
-    }
+	private static final Logger s_logger = Logger.getLogger(ConsoleProxyPasswordBasedEncryptor.class);
+	
+	private Gson gson;
+	
+	// key/IV will be set in 128 bit strength
+	private KeyIVPair keyIvPair;
+	
+	public ConsoleProxyPasswordBasedEncryptor(String password) {
+		gson = new GsonBuilder().create();
+		keyIvPair = gson.fromJson(password, KeyIVPair.class);
+	}
+	
+	public String encryptText(String text) {
+		if(text == null || text.isEmpty())
+			return text;
+		
+		try {
+			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+			SecretKeySpec keySpec = new SecretKeySpec(keyIvPair.getKeyBytes(), "AES");
 
-    public String decryptText(String encryptedText) {
-        if(encryptedText == null || encryptedText.isEmpty())
-            return encryptedText;
+			cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(keyIvPair.getIvBytes()));
+		
+			byte[] encryptedBytes = cipher.doFinal(text.getBytes());
+			return Base64.encodeBase64URLSafeString(encryptedBytes);
+		} catch (NoSuchAlgorithmException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		} catch (NoSuchPaddingException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		} catch (IllegalBlockSizeException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		} catch (BadPaddingException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		} catch (InvalidKeyException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		} catch (InvalidAlgorithmParameterException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		}
+	}
 
-        assert(password != null);
-        assert(!password.isEmpty());
+	public String decryptText(String encryptedText) {
+		if(encryptedText == null || encryptedText.isEmpty())
+			return encryptedText;
 
-        try {
-            Cipher cipher = Cipher.getInstance("DES");
-            int maxKeySize = 8;
-            SecretKeySpec keySpec = new SecretKeySpec(normalizeKey(password.getBytes(), maxKeySize),
"DES");
-            cipher.init(Cipher.DECRYPT_MODE, keySpec);
-            
-            byte[] encryptedBytes = Base64.decodeBase64(encryptedText);
-            return new String(cipher.doFinal(encryptedBytes));
-        } catch (NoSuchAlgorithmException e) {
-            s_logger.error("Unexpected exception ", e);
-            return null;
-        } catch (NoSuchPaddingException e) {
-            s_logger.error("Unexpected exception ", e);
-            return null;
-        } catch (IllegalBlockSizeException e) {
-            s_logger.error("Unexpected exception ", e);
-            return null;
-        } catch (BadPaddingException e) {
-            s_logger.error("Unexpected exception ", e);
-            return null;
-        } catch (InvalidKeyException e) {
-            s_logger.error("Unexpected exception ", e);
-            return null;
-        }
-    }
-    
-    public <T> String encryptObject(Class<?> clz, T obj) {
-        if(obj == null)
-            return null;
-        
-        String json = gson.toJson(obj);
-        return encryptText(json);
-    }
-    
-    @SuppressWarnings("unchecked")
-    public <T> T decryptObject(Class<?> clz, String encrypted) {
-        if(encrypted == null || encrypted.isEmpty())
-            return null;
-        
-        String json = decryptText(encrypted);
-        return (T)gson.fromJson(json, clz);
-    }
-    
-    private static byte[] normalizeKey(byte[] keyBytes, int keySize) {
-        assert(keySize > 0);
-        byte[] key = new byte[keySize];
-        
-        for(int i = 0; i < keyBytes.length; i++)
-            key[i%keySize] ^= keyBytes[i];
-        
-        return key;
-    }
+		try {
+			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+			SecretKeySpec keySpec = new SecretKeySpec(keyIvPair.getKeyBytes(), "AES");
+			cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(keyIvPair.getIvBytes()));
+			
+			byte[] encryptedBytes = Base64.decodeBase64(encryptedText);
+			return new String(cipher.doFinal(encryptedBytes));
+		} catch (NoSuchAlgorithmException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		} catch (NoSuchPaddingException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		} catch (IllegalBlockSizeException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		} catch (BadPaddingException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		} catch (InvalidKeyException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		} catch (InvalidAlgorithmParameterException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
+		}
+	}
+	
+	public <T> String encryptObject(Class<?> clz, T obj) {
+		if(obj == null)
+			return null;
+		
+		String json = gson.toJson(obj);
+		return encryptText(json);
+	}
+	
+	@SuppressWarnings("unchecked")
+	public <T> T decryptObject(Class<?> clz, String encrypted) {
+		if(encrypted == null || encrypted.isEmpty())
+			return null;
+		
+		String json = decryptText(encrypted);
+		return (T)gson.fromJson(json, clz);
+	}
+	
+	public static class KeyIVPair {
+		String base64EncodedKeyBytes;
+		String base64EncodedIvBytes;
+		
+		public KeyIVPair() {
+		}
+		
+		public KeyIVPair(String base64EncodedKeyBytes, String base64EncodedIvBytes) {
+			this.base64EncodedKeyBytes = base64EncodedKeyBytes;
+			this.base64EncodedIvBytes = base64EncodedIvBytes;
+		}
+
+		public byte[] getKeyBytes() {
+			return Base64.decodeBase64(base64EncodedKeyBytes);
+		}
+		
+		public void setKeyBytes(byte[] keyBytes) {
+			base64EncodedKeyBytes = Base64.encodeBase64URLSafeString(keyBytes);
+		}
+
+		public byte[] getIvBytes() {
+			return Base64.decodeBase64(base64EncodedIvBytes);
+		}
+		
+		public void setIvBytes(byte[] ivBytes) {
+			base64EncodedIvBytes = Base64.encodeBase64URLSafeString(ivBytes);
+		}
+	}
+	
+	public static void main(String[] args) {
+		SecureRandom random;
+		try {
+			random = SecureRandom.getInstance("SHA1PRNG");
+	        byte[] keyBytes = new byte[16];
+	        random.nextBytes(keyBytes);
+	        
+	        byte[] ivBytes = new byte[16];
+	        random.nextBytes(ivBytes);
+			
+			KeyIVPair keyIvPair = new KeyIVPair("8x/xUBgX0Up+3UEo39dSeG277JhVj31+ElHkN5+EC0Q=", "Y2SUiIN6JXTdKNK/ZMDyVtLB7gAM9MCCiyrP1xd3bSQ=");
+			//keyIvPair.setKeyBytes(keyBytes);	
+			//keyIvPair.setIvBytes(ivBytes);
+			
+			Gson gson = new GsonBuilder().create();
+			ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(gson.toJson(keyIvPair));
+			
+			String encrypted = encryptor.encryptText("Hello, world");
+			
+			System.out.println("Encrypted result: " + encrypted);
+			
+			String decrypted = encryptor.decryptText(encrypted);
+			
+			System.out.println("Decrypted result: " + decrypted);
+			
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		}
+ 	}
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73ed03ba/server/src/com/cloud/configuration/Config.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java
index 0815a77..74261ec 100755
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -289,6 +289,8 @@ public enum Config {
     SSOAuthTolerance("Advanced", ManagementServer.class, Long.class, "security.singlesignon.tolerance.millis",
"300000", "The allowable clock difference in milliseconds between when an SSO login request
is made and when it is received.", null),
 	//NetworkType("Hidden", ManagementServer.class, String.class, "network.type", "vlan", "The
type of network that this deployment will use.", "vlan,direct"),
 	HashKey("Hidden", ManagementServer.class, String.class, "security.hash.key", null, "for
generic key-ed hash", null),
+	EncryptionKey("Hidden", ManagementServer.class, String.class, "security.encryption.key",
null, "base64 encoded key data", null),
+	EncryptionIV("Hidden", ManagementServer.class, String.class, "security.encryption.iv", null,
"base64 encoded IV data", null),
 	RouterRamSize("Hidden", NetworkManager.class, Integer.class, "router.ram.size", "128", "Default
RAM for router VM (in MB).", null),
 
 	VmOpWaitInterval("Advanced", ManagementServer.class, Integer.class, "vm.op.wait.interval",
"120", "Time (in seconds) to wait before checking if a previous operation has succeeded",
null),

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73ed03ba/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java
index 168ac0e..831c812 100755
--- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java
+++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java
@@ -109,9 +109,11 @@ import com.cloud.resource.ResourceManager;
 import com.cloud.resource.ResourceStateAdapter;
 import com.cloud.resource.ServerResource;
 import com.cloud.resource.UnableDeleteHostException;
+import com.cloud.server.ManagementServer;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.servlet.ConsoleProxyServlet;
+import com.cloud.servlet.ConsoleProxyPasswordBasedEncryptor;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePoolStatus;
 import com.cloud.storage.StoragePoolVO;
@@ -129,7 +131,6 @@ import com.cloud.utils.DateUtil;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
 import com.cloud.utils.Ternary;
-import com.cloud.utils.component.Manager;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.utils.db.DB;
 import com.cloud.utils.db.GlobalLock;
@@ -234,6 +235,8 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy
     RulesManager _rulesMgr;
     @Inject
     IPAddressDao _ipAddressDao;
+    @Inject
+    ManagementServer _ms;
 
     private ConsoleProxyListener _listener;
 
@@ -268,7 +271,6 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy
     private Map<Long, ConsoleProxyLoadInfo> _zoneProxyCountMap; // map <zone id,
info about proxy VMs count in zone>
     private Map<Long, ConsoleProxyLoadInfo> _zoneVmCountMap; // map <zone id, info
about running VMs count in zone>
 
-    private String _hashKey;
     private String _staticPublicIp;
     private int _staticPort;
 
@@ -1731,6 +1733,33 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements
ConsoleProxy
         _consoleProxyDao.update(proxy.getId(), proxy);
     }
 
+    private String getEncryptorPassword() {
+    	
+    	String key;
+    	String iv;
+    	ConsoleProxyPasswordBasedEncryptor.KeyIVPair keyIvPair = null;
+    	
+    	// if we failed after reset, something is definitely wrong
+    	for(int i = 0; i < 2; i++) {
+	    	key = _ms.getEncryptionKey();
+	    	iv = _ms.getEncryptionIV();
+	    	
+	    	keyIvPair = new ConsoleProxyPasswordBasedEncryptor.KeyIVPair(key, iv);
+	    	
+	    	if(keyIvPair.getIvBytes() == null || keyIvPair.getIvBytes().length != 16 ||
+	    		keyIvPair.getKeyBytes() == null || keyIvPair.getKeyBytes().length != 16) {
+	    		
+	    		s_logger.warn("Console access AES KeyIV sanity check failed, reset and regenerate");
+	    		_ms.resetEncryptionKeyIV();
+	    	} else {
+	    		break;
+	    	}
+    	}
+    	
+		Gson gson = new GsonBuilder().create();
+		return gson.toJson(keyIvPair);
+    }
+    
     @Override
     public void startAgentHttpHandlerInVM(StartupProxyCommand startupCmd) {
         StartConsoleProxyAgentHttpHandlerCommand cmd = null;
@@ -1743,10 +1772,10 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements
ConsoleProxy
                 s_logger.error("Could not find and construct a valid SSL certificate");
             }
             cmd = new StartConsoleProxyAgentHttpHandlerCommand(ksBits, storePassword);
-            cmd.setEncryptorPassword(getHashKey());
+            cmd.setEncryptorPassword(getEncryptorPassword());
         } else {
             cmd = new StartConsoleProxyAgentHttpHandlerCommand();
-            cmd.setEncryptorPassword(getHashKey());
+            cmd.setEncryptorPassword(getEncryptorPassword());
         }
 
         try {
@@ -1998,15 +2027,6 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements
ConsoleProxy
         return sc.find();
     }
 
-    public String getHashKey() {
-        // although we may have race conditioning here, database transaction serialization
should
-        // give us the same key
-        if (_hashKey == null) {
-            _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(),
UUID.randomUUID().toString());
-        }
-        return _hashKey;
-    }
-
     @Override
     public boolean plugNic(Network network, NicTO nic, VirtualMachineTO vm,
             ReservationContext context, DeployDestination dest) throws ConcurrentOperationException,
ResourceUnavailableException,
@@ -2026,4 +2046,5 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements
ConsoleProxy
     @Override
     public void prepareStop(VirtualMachineProfile<ConsoleProxyVO> profile) {
     }
+    
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73ed03ba/server/src/com/cloud/server/ManagementServer.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServer.java b/server/src/com/cloud/server/ManagementServer.java
index 5c34dee..8d5e931 100755
--- a/server/src/com/cloud/server/ManagementServer.java
+++ b/server/src/com/cloud/server/ManagementServer.java
@@ -94,6 +94,9 @@ public interface ManagementServer extends ManagementService, PluggableService
 {
     Pair<List<StoragePoolVO>, Integer> searchForStoragePools(Criteria c);
 
     String getHashKey();
+    String getEncryptionKey();
+    String getEncryptionIV();
+    void resetEncryptionKeyIV();
     
     public void enableAdminUser(String password);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73ed03ba/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index 9cddb77..12c47a6 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -22,6 +22,8 @@ import java.net.InetAddress;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.UnknownHostException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Comparator;
@@ -405,6 +407,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
 
     @Inject ClusterManager _clusterMgr;
     private String _hashKey = null;
+    private String _encryptionKey = null;
+    private String _encryptionIV = null;
 
     public ManagementServerImpl() {
     	setRunLevel(ComponentLifecycle.RUN_LEVEL_APPLICATION_MAINLOOP);
@@ -2855,16 +2859,67 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
 
     @Override
     public String getHashKey() {
-        // although we may have race conditioning here, database transaction
-        // serialization should
+        // although we may have race conditioning here, database transaction serialization
should
         // give us the same key
         if (_hashKey == null) {
-            _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(),
UUID.randomUUID().toString());
+            _hashKey = _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(),

+            	getBase64EncodedRandomKey(128));
         }
         return _hashKey;
     }
 
     @Override
+    public String getEncryptionKey() {
+        if (_encryptionKey == null) {
+            _encryptionKey = _configDao.getValueAndInitIfNotExist(Config.EncryptionKey.key(),

+            	Config.EncryptionKey.getCategory(), 
+            	getBase64EncodedRandomKey(128));
+        }
+        return _encryptionKey;
+    }
+    
+    @Override
+    public String getEncryptionIV() {
+        if (_encryptionIV == null) {
+            _encryptionIV = _configDao.getValueAndInitIfNotExist(Config.EncryptionIV.key(),

+            	Config.EncryptionIV.getCategory(), 
+            	getBase64EncodedRandomKey(128));
+        }
+        return _encryptionIV;
+    }
+    
+    @Override
+    @DB
+    public void resetEncryptionKeyIV() {
+    	
+    	SearchBuilder<ConfigurationVO> sb = _configDao.createSearchBuilder();
+    	sb.and("name1", sb.entity().getName(), SearchCriteria.Op.EQ);
+    	sb.or("name2", sb.entity().getName(), SearchCriteria.Op.EQ);
+    	sb.done();
+    	
+    	SearchCriteria<ConfigurationVO> sc = sb.create();
+    	sc.setParameters("name1", Config.EncryptionKey.key());
+    	sc.setParameters("name2", Config.EncryptionIV.key());
+    	
+    	_configDao.expunge(sc);
+    	_encryptionKey = null;
+    	_encryptionIV = null;
+    }
+    
+    private static String getBase64EncodedRandomKey(int nBits) {
+		SecureRandom random;
+		try {
+			random = SecureRandom.getInstance("SHA1PRNG");
+	        byte[] keyBytes = new byte[nBits/8];
+	        random.nextBytes(keyBytes);
+	        return Base64.encodeBase64URLSafeString(keyBytes);
+		} catch (NoSuchAlgorithmException e) {
+			s_logger.error("Unhandled exception: ", e);
+		}
+		return null;
+    }
+
+    @Override
     public SSHKeyPair createSSHKeyPair(CreateSSHKeyPairCmd cmd) {
         Account caller = UserContext.current().getCaller();
         String accountName = cmd.getAccountName();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73ed03ba/server/src/com/cloud/servlet/ConsoleProxyPasswordBasedEncryptor.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/servlet/ConsoleProxyPasswordBasedEncryptor.java b/server/src/com/cloud/servlet/ConsoleProxyPasswordBasedEncryptor.java
index 2638c8b..7463ec0 100644
--- a/server/src/com/cloud/servlet/ConsoleProxyPasswordBasedEncryptor.java
+++ b/server/src/com/cloud/servlet/ConsoleProxyPasswordBasedEncryptor.java
@@ -16,13 +16,16 @@
 // under the License.
 package com.cloud.servlet;
 
+import java.security.InvalidAlgorithmParameterException;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 
 import javax.crypto.BadPaddingException;
 import javax.crypto.Cipher;
 import javax.crypto.IllegalBlockSizeException;
 import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
 
 import org.apache.commons.codec.binary.Base64;
@@ -35,26 +38,26 @@ import com.google.gson.GsonBuilder;
 public class ConsoleProxyPasswordBasedEncryptor {
 	private static final Logger s_logger = Logger.getLogger(ConsoleProxyPasswordBasedEncryptor.class);
 	
-	private String password;
 	private Gson gson;
 	
+	// key/IV will be set in 128 bit strength
+	private KeyIVPair keyIvPair;
+	
 	public ConsoleProxyPasswordBasedEncryptor(String password) {
-		this.password = password;
 		gson = new GsonBuilder().create();
+		keyIvPair = gson.fromJson(password, KeyIVPair.class);
 	}
 	
 	public String encryptText(String text) {
 		if(text == null || text.isEmpty())
 			return text;
 		
-		assert(password != null);
-		assert(!password.isEmpty());
-		
 		try {
-			Cipher cipher = Cipher.getInstance("DES");
-			int maxKeySize = 8;
-			SecretKeySpec keySpec = new SecretKeySpec(normalizeKey(password.getBytes(), maxKeySize),
"DES");
-			cipher.init(Cipher.ENCRYPT_MODE, keySpec);
+			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+			SecretKeySpec keySpec = new SecretKeySpec(keyIvPair.getKeyBytes(), "AES");
+
+			cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(keyIvPair.getIvBytes()));
+		
 			byte[] encryptedBytes = cipher.doFinal(text.getBytes());
 			return Base64.encodeBase64URLSafeString(encryptedBytes);
 		} catch (NoSuchAlgorithmException e) {
@@ -72,6 +75,9 @@ public class ConsoleProxyPasswordBasedEncryptor {
 		} catch (InvalidKeyException e) {
 			s_logger.error("Unexpected exception ", e);
 			return null;
+		} catch (InvalidAlgorithmParameterException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
 		}
 	}
 
@@ -79,14 +85,10 @@ public class ConsoleProxyPasswordBasedEncryptor {
 		if(encryptedText == null || encryptedText.isEmpty())
 			return encryptedText;
 
-		assert(password != null);
-		assert(!password.isEmpty());
-
 		try {
-			Cipher cipher = Cipher.getInstance("DES");
-			int maxKeySize = 8;
-			SecretKeySpec keySpec = new SecretKeySpec(normalizeKey(password.getBytes(), maxKeySize),
"DES");
-			cipher.init(Cipher.DECRYPT_MODE, keySpec);
+			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+			SecretKeySpec keySpec = new SecretKeySpec(keyIvPair.getKeyBytes(), "AES");
+			cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(keyIvPair.getIvBytes()));
 			
 			byte[] encryptedBytes = Base64.decodeBase64(encryptedText);
 			return new String(cipher.doFinal(encryptedBytes));
@@ -105,6 +107,9 @@ public class ConsoleProxyPasswordBasedEncryptor {
 		} catch (InvalidKeyException e) {
 			s_logger.error("Unexpected exception ", e);
 			return null;
+		} catch (InvalidAlgorithmParameterException e) {
+			s_logger.error("Unexpected exception ", e);
+			return null;
 		}
 	}
 	
@@ -125,13 +130,63 @@ public class ConsoleProxyPasswordBasedEncryptor {
 		return (T)gson.fromJson(json, clz);
 	}
 	
-	private static byte[] normalizeKey(byte[] keyBytes, int keySize) {
-		assert(keySize > 0);
-		byte[] key = new byte[keySize];
+	public static class KeyIVPair {
+		String base64EncodedKeyBytes;
+		String base64EncodedIvBytes;
+		
+		public KeyIVPair() {
+		}
 		
-		for(int i = 0; i < keyBytes.length; i++)
-			key[i%keySize] ^= keyBytes[i];
+		public KeyIVPair(String base64EncodedKeyBytes, String base64EncodedIvBytes) {
+			this.base64EncodedKeyBytes = base64EncodedKeyBytes;
+			this.base64EncodedIvBytes = base64EncodedIvBytes;
+		}
+
+		public byte[] getKeyBytes() {
+			return Base64.decodeBase64(base64EncodedKeyBytes);
+		}
 		
-		return key;
+		public void setKeyBytes(byte[] keyBytes) {
+			base64EncodedKeyBytes = Base64.encodeBase64URLSafeString(keyBytes);
+		}
+
+		public byte[] getIvBytes() {
+			return Base64.decodeBase64(base64EncodedIvBytes);
+		}
+		
+		public void setIvBytes(byte[] ivBytes) {
+			base64EncodedIvBytes = Base64.encodeBase64URLSafeString(ivBytes);
+		}
 	}
+	
+	public static void main(String[] args) {
+		SecureRandom random;
+		try {
+			random = SecureRandom.getInstance("SHA1PRNG");
+	        byte[] keyBytes = new byte[16];
+	        random.nextBytes(keyBytes);
+	        
+	        byte[] ivBytes = new byte[16];
+	        random.nextBytes(ivBytes);
+			
+			KeyIVPair keyIvPair = new KeyIVPair("8x/xUBgX0Up+3UEo39dSeG277JhVj31+ElHkN5+EC0Q=", "Y2SUiIN6JXTdKNK/ZMDyVtLB7gAM9MCCiyrP1xd3bSQ=");
+			//keyIvPair.setKeyBytes(keyBytes);	
+			//keyIvPair.setIvBytes(ivBytes);
+			
+			Gson gson = new GsonBuilder().create();
+			ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(gson.toJson(keyIvPair));
+			
+			String encrypted = encryptor.encryptText("Hello, world");
+			
+			System.out.println("Encrypted result: " + encrypted);
+			
+			String decrypted = encryptor.decryptText(encrypted);
+			
+			System.out.println("Decrypted result: " + decrypted);
+			
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		}
+ 	}
 }
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/73ed03ba/server/src/com/cloud/servlet/ConsoleProxyServlet.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/servlet/ConsoleProxyServlet.java b/server/src/com/cloud/servlet/ConsoleProxyServlet.java
index c4b9334..ebb9174 100644
--- a/server/src/com/cloud/servlet/ConsoleProxyServlet.java
+++ b/server/src/com/cloud/servlet/ConsoleProxyServlet.java
@@ -55,6 +55,8 @@ import com.cloud.utils.db.Transaction;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineManager;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 
 /**
  * Thumbnail access : /console?cmd=thumbnail&vm=xxx&w=xxx&h=xxx
@@ -75,6 +77,8 @@ public class ConsoleProxyServlet extends HttpServlet {
 
     static ManagementServer s_ms;
 
+    private Gson _gson = new GsonBuilder().create();
+
     public ConsoleProxyServlet() {
     }
   
@@ -327,6 +331,14 @@ public class ConsoleProxyServlet extends HttpServlet {
         return new Ternary<String, String, String>(host, tunnelUrl, tunnelSession);
     }
 
+    private String getEncryptorPassword() {
+    	String key = _ms.getEncryptionKey();
+    	String iv = _ms.getEncryptionIV();
+    	
+    	ConsoleProxyPasswordBasedEncryptor.KeyIVPair keyIvPair = new ConsoleProxyPasswordBasedEncryptor.KeyIVPair(key,
iv);
+		return _gson.toJson(keyIvPair);
+    }
+    
     private String composeThumbnailUrl(String rootUrl, VMInstanceVO vm, HostVO hostVo, int
w, int h) {
         StringBuffer sb = new StringBuffer(rootUrl);
 
@@ -340,7 +352,7 @@ public class ConsoleProxyServlet extends HttpServlet {
         tag = _identityService.getIdentityUuid("vm_instance", tag);
         String ticket = genAccessTicket(host, String.valueOf(portInfo.second()), sid, tag);
 
-        ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(_ms.getHashKey());
+        ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(getEncryptorPassword());
         ConsoleProxyClientParam param = new ConsoleProxyClientParam();
         param.setClientHostAddress(parsedHostInfo.first());
         param.setClientHostPort(portInfo.second());
@@ -376,7 +388,7 @@ public class ConsoleProxyServlet extends HttpServlet {
         String tag = String.valueOf(vm.getId());
         tag = _identityService.getIdentityUuid("vm_instance", tag);
         String ticket = genAccessTicket(host, String.valueOf(portInfo.second()), sid, tag);
-        ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(_ms.getHashKey());
+        ConsoleProxyPasswordBasedEncryptor encryptor = new ConsoleProxyPasswordBasedEncryptor(getEncryptorPassword());
         ConsoleProxyClientParam param = new ConsoleProxyClientParam();
         param.setClientHostAddress(parsedHostInfo.first());
         param.setClientHostPort(portInfo.second());


Mime
View raw message