/**
 * CipherSuites
 * 
 * An enumeration of cipher-suites available for TLS to use, along with
 * their properties, and some convenience methods
 * Copyright (c) 2007 Henri Torgemane
 * 
 * See LICENSE.txt for full license information.
 */
package com.hurlant.crypto.tls {
	import com.hurlant.crypto.hash.MD5;
	import com.hurlant.crypto.hash.SHA1;
	
	public class CipherSuites {
		
		
		// only the lines marked "ok" are currently implemented.
		
		// rfc 2246
		
		public static const TLS_NULL_WITH_NULL_NULL:uint				= 0x0000; // ok
		public static const TLS_RSA_WITH_NULL_MD5:uint					= 0x0001; // ok
		public static const TLS_RSA_WITH_NULL_SHA:uint					= 0x0002; // ok
		public static const TLS_RSA_WITH_RC4_128_MD5:uint				= 0x0004; // ok
		public static const TLS_RSA_WITH_RC4_128_SHA:uint				= 0x0005; // ok
		public static const TLS_RSA_WITH_IDEA_CBC_SHA:uint				= 0x0007;
		public static const TLS_RSA_WITH_DES_CBC_SHA:uint				= 0x0009; // ok
		public static const TLS_RSA_WITH_3DES_EDE_CBC_SHA:uint			= 0x000A; // ok
		
		public static const TLS_DH_DSS_WITH_DES_CBC_SHA:uint			= 0x000C;
		public static const TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:uint		= 0x000D;
		public static const TLS_DH_RSA_WITH_DES_CBC_SHA:uint			= 0x000F;
		public static const TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:uint		= 0x0010;
		public static const TLS_DHE_DSS_WITH_DES_CBC_SHA:uint			= 0x0012;
		public static const TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:uint		= 0x0013;
		public static const TLS_DHE_RSA_WITH_DES_CBC_SHA:uint			= 0x0015;
		public static const TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:uint		= 0x0016;
		
		public static const TLS_DH_anon_WITH_RC4_128_MD5:uint			= 0x0018;
		public static const TLS_DH_anon_WITH_DES_CBC_SHA:uint			= 0x001A;
		public static const TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:uint		= 0x001B;
		
		// rfc3268
		
		public static const TLS_RSA_WITH_AES_128_CBC_SHA:uint			= 0x002F; // ok
		public static const TLS_DH_DSS_WITH_AES_128_CBC_SHA:uint		= 0x0030;
		public static const TLS_DH_RSA_WITH_AES_128_CBC_SHA:uint		= 0x0031;
		public static const TLS_DHE_DSS_WITH_AES_128_CBC_SHA:uint		= 0x0032;
		public static const TLS_DHE_RSA_WITH_AES_128_CBC_SHA:uint		= 0x0033;
		public static const TLS_DH_anon_WITH_AES_128_CBC_SHA:uint		= 0x0034;
		
		public static const TLS_RSA_WITH_AES_256_CBC_SHA:uint			= 0x0035; // ok
		public static const TLS_DH_DSS_WITH_AES_256_CBC_SHA:uint		= 0x0036;
		public static const TLS_DH_RSA_WITH_AES_256_CBC_SHA:uint		= 0x0037;
		public static const TLS_DHE_DSS_WITH_AES_256_CBC_SHA:uint		= 0x0038;
		public static const TLS_DHE_RSA_WITH_AES_256_CBC_SHA:uint		= 0x0039;
		public static const TLS_DH_anon_WITH_AES_256_CBC_SHA:uint		= 0x003A;
		
		private static var _props:Array;
		
		init();
		private static function init():void {
			_props = [];
			_props[TLS_NULL_WITH_NULL_NULL]			= new CipherSuites(BulkCiphers.NULL, MACs.NULL, KeyExchanges.NULL);
			_props[TLS_RSA_WITH_NULL_MD5]			= new CipherSuites(BulkCiphers.NULL, MACs.MD5, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_NULL_SHA]			= new CipherSuites(BulkCiphers.NULL, MACs.SHA1, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_RC4_128_MD5]		= new CipherSuites(BulkCiphers.RC4_128, MACs.MD5, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_RC4_128_SHA]		= new CipherSuites(BulkCiphers.RC4_128, MACs.SHA1, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_DES_CBC_SHA]		= new CipherSuites(BulkCiphers.DES_CBC, MACs.SHA1, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_3DES_EDE_CBC_SHA]	= new CipherSuites(BulkCiphers.DES3_EDE_CBC, MACs.SHA1, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_AES_128_CBC_SHA]	= new CipherSuites(BulkCiphers.AES_128, MACs.SHA1, KeyExchanges.RSA);
			_props[TLS_RSA_WITH_AES_256_CBC_SHA]	= new CipherSuites(BulkCiphers.AES_256, MACs.SHA1, KeyExchanges.RSA);
			
			// ...
			// more later
		}
		
		private static function getProp(cipher:uint):CipherSuites {
			var p:CipherSuites = _props[cipher];
			if (p==null) {
				throw new Error("Unknown cipher "+cipher.toString(16));
			}
			return p;
		}
		public static function getBulkCipher(cipher:uint):uint {
			return getProp(cipher).cipher;
		}
		public static function getMac(cipher:uint):uint {
			return getProp(cipher).hash;
		}
		public static function getKeyExchange(cipher:uint):uint {
			return getProp(cipher).key;
		}
		
		public static function getDefaultSuites():Array {
			// a list of acceptable ciphers, sorted by preference.
			return [
				TLS_RSA_WITH_AES_256_CBC_SHA,
				TLS_RSA_WITH_3DES_EDE_CBC_SHA,
				TLS_RSA_WITH_AES_128_CBC_SHA,
				TLS_RSA_WITH_RC4_128_SHA,
				TLS_RSA_WITH_RC4_128_MD5,
				TLS_RSA_WITH_DES_CBC_SHA
			];
		}
		
		public var cipher:uint;
		public var hash:uint;
		public var key:uint;
		
		public function CipherSuites(cipher:uint, hash:uint, key:uint) {
			this.cipher = cipher;
			this.hash = hash;
			this.key = key;
		}
	}
}
