cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bfede...@apache.org
Subject [39/50] [abbrv] git commit: updated refs/heads/ui-new-project-switcher to a748988
Date Tue, 16 Apr 2013 18:04:12 GMT
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/34f8f795
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/34f8f795
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/34f8f795

Branch: refs/heads/ui-new-project-switcher
Commit: 34f8f795e15b89477f72aa6f1e69f7797c930db4
Parents: 8d33353
Author: Kelven Yang <kelveny@gmail.com>
Authored: Mon Apr 15 16:51:50 2013 -0700
Committer: Kelven Yang <kelveny@gmail.com>
Committed: Mon Apr 15 16:52:22 2013 -0700

----------------------------------------------------------------------
 server/src/com/cloud/configuration/Config.java     |    2 +
 .../AgentBasedConsoleProxyManager.java             |    8 +-
 .../src/com/cloud/consoleproxy/AgentHookBase.java  |   50 ++-
 .../consoleproxy/ConsoleProxyManagerImpl.java      |   21 +-
 server/src/com/cloud/server/ManagementServer.java  |    3 +
 .../src/com/cloud/server/ManagementServerImpl.java |   63 ++++-
 .../ConsoleProxyPasswordBasedEncryptor.java        |   99 +++++--
 .../src/com/cloud/servlet/ConsoleProxyServlet.java |   16 +-
 .../ConsoleProxyPasswordBasedEncryptor.java        |  253 +++++++++------
 9 files changed, 358 insertions(+), 157 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/34f8f795/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 e3e3053..e69ea19 100755
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -305,6 +305,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/34f8f795/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java
index ff6e64e..df53e0d 100755
--- a/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java
+++ b/server/src/com/cloud/consoleproxy/AgentBasedConsoleProxyManager.java
@@ -33,6 +33,7 @@ import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
 import com.cloud.info.ConsoleProxyInfo;
 import com.cloud.keystore.KeystoreManager;
+import com.cloud.server.ManagementServer;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.vm.ConsoleProxyVO;
@@ -69,12 +70,13 @@ public class AgentBasedConsoleProxyManager extends ManagerBase implements
Consol
     protected KeystoreManager _ksMgr;
 
     @Inject ConfigurationDao _configDao;
+    @Inject ManagementServer _ms;
 
     public class AgentBasedAgentHook extends AgentHookBase {
 
         public AgentBasedAgentHook(VMInstanceDao instanceDao, HostDao hostDao, ConfigurationDao
cfgDao,
-                KeystoreManager ksMgr, AgentManager agentMgr) {
-            super(instanceDao, hostDao, cfgDao, ksMgr, agentMgr);
+                KeystoreManager ksMgr, AgentManager agentMgr, ManagementServer ms) {
+            super(instanceDao, hostDao, cfgDao, ksMgr, agentMgr, ms);
         }
 
         @Override
@@ -120,7 +122,7 @@ public class AgentBasedConsoleProxyManager extends ManagerBase implements
Consol
         _consoleProxyUrlDomain = configs.get("consoleproxy.url.domain");
 
         _listener =
-                new ConsoleProxyListener(new AgentBasedAgentHook(_instanceDao, _hostDao,
_configDao, _ksMgr, _agentMgr));
+                new ConsoleProxyListener(new AgentBasedAgentHook(_instanceDao, _hostDao,
_configDao, _ksMgr, _agentMgr, _ms));
         _agentMgr.registerForHostEvents(_listener, true, true, false);
 
         if (s_logger.isInfoEnabled()) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/34f8f795/server/src/com/cloud/consoleproxy/AgentHookBase.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/consoleproxy/AgentHookBase.java b/server/src/com/cloud/consoleproxy/AgentHookBase.java
index b969f6d..2748a8c 100644
--- a/server/src/com/cloud/consoleproxy/AgentHookBase.java
+++ b/server/src/com/cloud/consoleproxy/AgentHookBase.java
@@ -42,10 +42,14 @@ import com.cloud.host.HostVO;
 import com.cloud.host.Status;
 import com.cloud.host.dao.HostDao;
 import com.cloud.keystore.KeystoreManager;
+import com.cloud.server.ManagementServer;
+import com.cloud.servlet.ConsoleProxyPasswordBasedEncryptor;
 import com.cloud.servlet.ConsoleProxyServlet;
 import com.cloud.utils.Ternary;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.dao.VMInstanceDao;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 
 /**
  * Utility class to manage interactions with agent-based console access
@@ -60,28 +64,19 @@ public abstract class AgentHookBase implements AgentHook {
     ConfigurationDao _configDao;
     AgentManager _agentMgr;
     KeystoreManager _ksMgr;
+    ManagementServer _ms;
     final Random _random = new Random(System.currentTimeMillis());
     private String _hashKey;
 
 
     public AgentHookBase(VMInstanceDao instanceDao, HostDao hostDao, ConfigurationDao cfgDao,
KeystoreManager ksMgr,
-            AgentManager agentMgr) {
+            AgentManager agentMgr, ManagementServer ms) {
         this._instanceDao = instanceDao;
         this._hostDao = hostDao;
         this._agentMgr = agentMgr;
         this._configDao = cfgDao;
         this._ksMgr = ksMgr;
-    }
-
-    public String getHashKey() {
-        // although we may have race condition 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;
+        this._ms = ms;
     }
 
     public AgentControlAnswer onConsoleAccessAuthentication(ConsoleAccessAuthenticationCommand
cmd) {
@@ -212,10 +207,10 @@ public abstract class AgentHookBase implements AgentHook {
                 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 {
@@ -246,6 +241,33 @@ public abstract class AgentHookBase implements AgentHook {
                             + startupCmd.getProxyVmId(), e);
         }
     }
+    
+    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);
+    }
+     
 
     protected abstract HostVO findConsoleProxyHost(StartupProxyCommand cmd);
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/34f8f795/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 9740d28..c4ad817 100755
--- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java
+++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java
@@ -95,8 +95,10 @@ 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.ConsoleProxyPasswordBasedEncryptor;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePoolStatus;
 import com.cloud.storage.VMTemplateHostVO;
@@ -220,6 +222,8 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy
     TemplateManager templateMgr;
     @Inject
     IPAddressDao _ipAddressDao;
+    @Inject
+    ManagementServer _ms;
 
     private ConsoleProxyListener _listener;
 
@@ -254,7 +258,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;
 
@@ -448,8 +451,8 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy
     public class VmBasedAgentHook extends AgentHookBase {
 
         public VmBasedAgentHook(VMInstanceDao instanceDao, HostDao hostDao, ConfigurationDao
cfgDao,
-                KeystoreManager ksMgr, AgentManager agentMgr) {
-            super(instanceDao, hostDao, cfgDao, ksMgr, agentMgr);
+                KeystoreManager ksMgr, AgentManager agentMgr, ManagementServer ms) {
+            super(instanceDao, hostDao, cfgDao, ksMgr, agentMgr, ms);
         }
 
         @Override
@@ -1439,7 +1442,7 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements
ConsoleProxy
 
         _listener =
                 new ConsoleProxyListener(new VmBasedAgentHook(_instanceDao, _hostDao, _configDao,
_ksMgr,
-                        _agentMgr));
+                        _agentMgr, _ms));
         _agentMgr.registerForHostEvents(_listener, true, true, false);
 
         _itMgr.registerGuru(VirtualMachine.Type.ConsoleProxy, this);
@@ -1884,15 +1887,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,
@@ -1912,4 +1906,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/34f8f795/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 6773725..240464e 100755
--- a/server/src/com/cloud/server/ManagementServer.java
+++ b/server/src/com/cloud/server/ManagementServer.java
@@ -95,6 +95,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/34f8f795/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 50b21ab..5ed0c92 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;
@@ -400,7 +402,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
 
     @Inject ClusterManager _clusterMgr;
     private String _hashKey = null;
-
+    private String _encryptionKey = null;
+    private String _encryptionIV = null;
+    
     @Inject
     protected AffinityGroupVMMapDao _affinityGroupVMMapDao;
 
@@ -3000,16 +3004,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/34f8f795/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/34f8f795/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());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/34f8f795/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java
----------------------------------------------------------------------
diff --git a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java
b/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java
index 29826f0..5a7241a 100644
--- a/services/console-proxy/server/src/com/cloud/consoleproxy/ConsoleProxyPasswordBasedEncryptor.java
+++ b/services/console-proxy/server/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();
+		}
+ 	}
 }


Mime
View raw message