summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crypto/crypto.csproj5
-rw-r--r--crypto/src/crypto/tls/EncryptionAlgorithm.cs17
-rw-r--r--crypto/src/crypto/tls/NewSessionTicket.cs53
-rw-r--r--crypto/src/crypto/tls/TlsUtilities.cs886
4 files changed, 876 insertions, 85 deletions
diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index 83d0305c2..c361d5d80 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -4464,6 +4464,11 @@
                     BuildAction = "Compile"
                 />
                 <File
+                    RelPath = "src\crypto\tls\NewSessionTicket.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
+                <File
                     RelPath = "src\crypto\tls\PrfAlgorithm.cs"
                     SubType = "Code"
                     BuildAction = "Compile"
diff --git a/crypto/src/crypto/tls/EncryptionAlgorithm.cs b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
index dbeaa3356..05d1c5d7a 100644
--- a/crypto/src/crypto/tls/EncryptionAlgorithm.cs
+++ b/crypto/src/crypto/tls/EncryptionAlgorithm.cs
@@ -50,9 +50,20 @@ namespace Org.BouncyCastle.Crypto.Tls
         public const int AES_256_CCM_8 = 18;
 
         /*
-         * TBD[draft-josefsson-salsa20-tls-02] 
+         * RFC 6367
          */
-        const int ESTREAM_SALSA20 = 100;
-        const int SALSA20 = 101;
+        public const int CAMELLIA_128_GCM = 19;
+        public const int CAMELLIA_256_GCM = 20;
+
+        /*
+         * draft-josefsson-salsa20-tls-04 
+         */
+        public const int ESTREAM_SALSA20 = 100;
+        public const int SALSA20 = 101;
+
+        /*
+         * draft-agl-tls-chacha20poly1305-04
+         */
+        public const int AEAD_CHACHA20_POLY1305 = 102;
     }
 }
diff --git a/crypto/src/crypto/tls/NewSessionTicket.cs b/crypto/src/crypto/tls/NewSessionTicket.cs
new file mode 100644
index 000000000..b75838b03
--- /dev/null
+++ b/crypto/src/crypto/tls/NewSessionTicket.cs
@@ -0,0 +1,53 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class NewSessionTicket
+    {
+        protected long mTicketLifetimeHint;
+        protected byte[] mTicket;
+
+        public NewSessionTicket(long ticketLifetimeHint, byte[] ticket)
+        {
+            this.mTicketLifetimeHint = ticketLifetimeHint;
+            this.mTicket = ticket;
+        }
+
+        public virtual long TicketLifetimeHint
+        {
+            get { return mTicketLifetimeHint; }
+        }
+
+        public virtual byte[] Ticket
+        {
+            get { return mTicket; }
+        }
+
+        /**
+         * Encode this {@link NewSessionTicket} to a {@link Stream}.
+         *
+         * @param output the {@link Stream} to encode to.
+         * @throws IOException
+         */
+        public virtual void Encode(Stream output)
+        {
+            TlsUtilities.WriteUint32(mTicketLifetimeHint, output);
+            TlsUtilities.WriteOpaque16(mTicket, output);
+        }
+
+        /**
+         * Parse a {@link NewSessionTicket} from a {@link Stream}.
+         *
+         * @param input the {@link Stream} to parse from.
+         * @return a {@link NewSessionTicket} object.
+         * @throws IOException
+         */
+        public static NewSessionTicket Parse(Stream input)
+        {
+            long ticketLifetimeHint = TlsUtilities.ReadUint32(input);
+            byte[] ticket = TlsUtilities.ReadOpaque16(input);
+            return new NewSessionTicket(ticketLifetimeHint, ticket);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index 644d079c1..f07626852 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -37,6 +37,24 @@ namespace Org.BouncyCastle.Crypto.Tls
                 throw new TlsFatalAlert(AlertDescription.internal_error);
         }
 
+        public static void CheckUint32(long i)
+        {
+            if (!IsValidUint32(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint48(long i)
+        {
+            if (!IsValidUint48(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
+        public static void CheckUint64(long i)
+        {
+            if (!IsValidUint64(i))
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+        }
+
         public static bool IsValidUint8(int i)
         {
             return (i & 0xFF) == i;
@@ -51,10 +69,24 @@ namespace Org.BouncyCastle.Crypto.Tls
         {
             return (i & 0xFFFFFF) == i;
         }
+        public static bool IsValidUint32(long i)
+        {
+            return (i & 0xFFFFFFFFL) == i;
+        }
 
-        public static void WriteUint8(byte i, Stream os)
+        public static bool IsValidUint48(long i)
         {
-            os.WriteByte(i);
+            return (i & 0xFFFFFFFFFFFFL) == i;
+        }
+
+        public static bool IsValidUint64(long i)
+        {
+            return true;
+        }
+
+        public static void WriteUint8(byte i, Stream output)
+        {
+            output.WriteByte(i);
         }
 
         public static void WriteUint8(byte i, byte[] buf, int offset)
@@ -62,10 +94,10 @@ namespace Org.BouncyCastle.Crypto.Tls
             buf[offset] = i;
         }
 
-        public static void WriteUint16(int i, Stream os)
+        public static void WriteUint16(int i, Stream output)
         {
-            os.WriteByte((byte)(i >> 8));
-            os.WriteByte((byte)i);
+            output.WriteByte((byte)(i >> 8));
+            output.WriteByte((byte)i);
         }
 
         public static void WriteUint16(int i, byte[] buf, int offset)
@@ -74,30 +106,66 @@ namespace Org.BouncyCastle.Crypto.Tls
             buf[offset + 1] = (byte)i;
         }
 
-        public static void WriteUint24(int i, Stream os)
+        public static void WriteUint24(int i, Stream output)
         {
-            os.WriteByte((byte)(i >> 16));
-            os.WriteByte((byte)(i >> 8));
-            os.WriteByte((byte)i);
+            output.WriteByte((byte)(i >> 16));
+            output.WriteByte((byte)(i >> 8));
+            output.WriteByte((byte)i);
         }
 
         public static void WriteUint24(int i, byte[] buf, int offset)
         {
             buf[offset] = (byte)(i >> 16);
             buf[offset + 1] = (byte)(i >> 8);
-            buf[offset + 2] = (byte)(i);
+            buf[offset + 2] = (byte)i;
+        }
+
+        public static void WriteUint32(long i, Stream output)
+        {
+            output.WriteByte((byte)(i >> 24));
+            output.WriteByte((byte)(i >> 16));
+            output.WriteByte((byte)(i >> 8));
+            output.WriteByte((byte)i);
+        }
+
+        public static void WriteUint32(long i, byte[] buf, int offset)
+        {
+            buf[offset] = (byte)(i >> 24);
+            buf[offset + 1] = (byte)(i >> 16);
+            buf[offset + 2] = (byte)(i >> 8);
+            buf[offset + 3] = (byte)i;
         }
 
-        public static void WriteUint64(long i, Stream os)
+        public static void WriteUint48(long i, Stream output)
         {
-            os.WriteByte((byte)(i >> 56));
-            os.WriteByte((byte)(i >> 48));
-            os.WriteByte((byte)(i >> 40));
-            os.WriteByte((byte)(i >> 32));
-            os.WriteByte((byte)(i >> 24));
-            os.WriteByte((byte)(i >> 16));
-            os.WriteByte((byte)(i >> 8));
-            os.WriteByte((byte)i);
+            output.WriteByte((byte)(i >> 40));
+            output.WriteByte((byte)(i >> 32));
+            output.WriteByte((byte)(i >> 24));
+            output.WriteByte((byte)(i >> 16));
+            output.WriteByte((byte)(i >> 8));
+            output.WriteByte((byte)i);
+        }
+
+        public static void WriteUint48(long i, byte[] buf, int offset)
+        {
+            buf[offset] = (byte)(i >> 40);
+            buf[offset + 1] = (byte)(i >> 32);
+            buf[offset + 2] = (byte)(i >> 24);
+            buf[offset + 3] = (byte)(i >> 16);
+            buf[offset + 4] = (byte)(i >> 8);
+            buf[offset + 5] = (byte)i;
+        }
+
+        public static void WriteUint64(long i, Stream output)
+        {
+            output.WriteByte((byte)(i >> 56));
+            output.WriteByte((byte)(i >> 48));
+            output.WriteByte((byte)(i >> 40));
+            output.WriteByte((byte)(i >> 32));
+            output.WriteByte((byte)(i >> 24));
+            output.WriteByte((byte)(i >> 16));
+            output.WriteByte((byte)(i >> 8));
+            output.WriteByte((byte)i);
         }
 
         public static void WriteUint64(long i, byte[] buf, int offset)
@@ -109,30 +177,30 @@ namespace Org.BouncyCastle.Crypto.Tls
             buf[offset + 4] = (byte)(i >> 24);
             buf[offset + 5] = (byte)(i >> 16);
             buf[offset + 6] = (byte)(i >> 8);
-            buf[offset + 7] = (byte)(i);
+            buf[offset + 7] = (byte)i;
         }
 
-        public static void WriteOpaque8(byte[] buf, Stream os)
+        public static void WriteOpaque8(byte[] buf, Stream output)
         {
-            WriteUint8((byte)buf.Length, os);
-            os.Write(buf, 0, buf.Length);
+            WriteUint8((byte)buf.Length, output);
+            output.Write(buf, 0, buf.Length);
         }
 
-        public static void WriteOpaque16(byte[] buf, Stream os)
+        public static void WriteOpaque16(byte[] buf, Stream output)
         {
-            WriteUint16(buf.Length, os);
-            os.Write(buf, 0, buf.Length);
+            WriteUint16(buf.Length, output);
+            output.Write(buf, 0, buf.Length);
         }
 
-        public static void WriteOpaque24(byte[] buf, Stream os)
+        public static void WriteOpaque24(byte[] buf, Stream output)
         {
-            WriteUint24(buf.Length, os);
-            os.Write(buf, 0, buf.Length);
+            WriteUint24(buf.Length, output);
+            output.Write(buf, 0, buf.Length);
         }
 
-        public static void WriteUint8Array(byte[] uints, Stream os)
+        public static void WriteUint8Array(byte[] uints, Stream output)
         {
-            os.Write(uints, 0, uints.Length);
+            output.Write(uints, 0, uints.Length);
         }
 
         public static void WriteUint8Array(byte[] uints, byte[] buf, int offset)
@@ -158,11 +226,11 @@ namespace Org.BouncyCastle.Crypto.Tls
             WriteUint8Array(uints, buf, offset + 1);
         }
 
-        public static void WriteUint16Array(int[] uints, Stream os)
+        public static void WriteUint16Array(int[] uints, Stream output)
         {
             for (int i = 0; i < uints.Length; ++i)
             {
-                WriteUint16(uints[i], os);
+                WriteUint16(uints[i], output);
             }
         }
 
@@ -212,9 +280,9 @@ namespace Org.BouncyCastle.Crypto.Tls
             return result;
         }
 
-        public static byte ReadUint8(Stream inStr)
+        public static byte ReadUint8(Stream input)
         {
-            int i = inStr.ReadByte();
+            int i = input.ReadByte();
             if (i < 0)
             {
                 throw new EndOfStreamException();
@@ -222,10 +290,15 @@ namespace Org.BouncyCastle.Crypto.Tls
             return (byte)i;
         }
 
-        public static int ReadUint16(Stream inStr)
+        public static byte ReadUint8(byte[] buf, int offset)
+        {
+            return buf[offset];
+        }
+
+        public static int ReadUint16(Stream input)
         {
-            int i1 = inStr.ReadByte();
-            int i2 = inStr.ReadByte();
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
             if ((i1 | i2) < 0)
             {
                 throw new EndOfStreamException();
@@ -233,11 +306,18 @@ namespace Org.BouncyCastle.Crypto.Tls
             return i1 << 8 | i2;
         }
 
-        public static int ReadUint24(Stream inStr)
+        public static int ReadUint16(byte[] buf, int offset)
         {
-            int i1 = inStr.ReadByte();
-            int i2 = inStr.ReadByte();
-            int i3 = inStr.ReadByte();
+            uint n = (uint)buf[offset] << 8;
+            n |= (uint)buf[++offset];
+            return (int)n;
+        }
+
+        public static int ReadUint24(Stream input)
+        {
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
+            int i3 = input.ReadByte();
             if ((i1 | i2 | i3) < 0)
             {
                 throw new EndOfStreamException();
@@ -245,6 +325,63 @@ namespace Org.BouncyCastle.Crypto.Tls
             return (i1 << 16) | (i2 << 8) | i3;
         }
 
+        public static int ReadUint24(byte[] buf, int offset)
+        {
+            uint n = (uint)buf[offset] << 16;
+            n |= (uint)buf[++offset] << 8;
+            n |= (uint)buf[++offset];
+            return (int)n;
+        }
+
+        public static long ReadUint32(Stream input)
+        {
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
+            int i3 = input.ReadByte();
+            int i4 = input.ReadByte();
+            if (i4 < 0)
+            {
+                throw new EndOfStreamException();
+            }
+            return (long)(uint)((i1 << 24) | (i2 << 16) | (i3 << 8) | i4);
+        }
+
+        public static long ReadUint32(byte[] buf, int offset)
+        {
+            uint n = (uint)buf[offset] << 24;
+            n |= (uint)buf[++offset] << 16;
+            n |= (uint)buf[++offset] << 8;
+            n |= (uint)buf[++offset];
+            return (long)n;
+        }
+
+        public static long ReadUint48(Stream input)
+        {
+            int hi = ReadUint24(input);
+            int lo = ReadUint24(input);
+            return ((long)(hi & 0xffffffffL) << 24) | (long)(lo & 0xffffffffL);
+        }
+
+        public static long ReadUint48(byte[] buf, int offset)
+        {
+            int hi = ReadUint24(buf, offset);
+            int lo = ReadUint24(buf, offset + 3);
+            return ((long)(hi & 0xffffffffL) << 24) | (long)(lo & 0xffffffffL);
+        }
+
+        public static byte[] ReadAllOrNothing(int length, Stream input)
+        {
+            if (length < 1)
+                return EmptyBytes;
+            byte[] buf = new byte[length];
+            int read = Streams.ReadFully(input, buf);
+            if (read == 0)
+                return null;
+            if (read != length)
+                throw new EndOfStreamException();
+            return buf;
+        }
+
         public static byte[] ReadFully(int length, Stream input)
         {
             if (length < 1)
@@ -255,25 +392,25 @@ namespace Org.BouncyCastle.Crypto.Tls
             return buf;
         }
 
-        public static void ReadFully(byte[] buf, Stream inStr)
+        public static void ReadFully(byte[] buf, Stream input)
         {
-            if (Streams.ReadFully(inStr, buf, 0, buf.Length) < buf.Length)
+            if (Streams.ReadFully(input, buf, 0, buf.Length) < buf.Length)
                 throw new EndOfStreamException();
         }
 
-        public static byte[] ReadOpaque8(Stream inStr)
+        public static byte[] ReadOpaque8(Stream input)
         {
-            byte length = ReadUint8(inStr);
+            byte length = ReadUint8(input);
             byte[] bytes = new byte[length];
-            ReadFully(bytes, inStr);
+            ReadFully(bytes, input);
             return bytes;
         }
 
-        public static byte[] ReadOpaque16(Stream inStr)
+        public static byte[] ReadOpaque16(Stream input)
         {
-            int length = ReadUint16(inStr);
+            int length = ReadUint16(input);
             byte[] bytes = new byte[length];
-            ReadFully(bytes, inStr);
+            ReadFully(bytes, input);
             return bytes;
         }
 
@@ -303,24 +440,58 @@ namespace Org.BouncyCastle.Crypto.Tls
             return uints;
         }
 
-        public static void CheckVersion(byte[] readVersion)
+        [Obsolete]
+        public static void CheckVersion(byte[] ReadVersion)
         {
-            if ((readVersion[0] != 3) || (readVersion[1] != 1))
+            if ((ReadVersion[0] != 3) || (ReadVersion[1] != 1))
             {
                 throw new TlsFatalAlert(AlertDescription.protocol_version);
             }
         }
 
-        public static void CheckVersion(Stream inStr)
+        [Obsolete]
+        public static void CheckVersion(Stream input)
         {
-            int i1 = inStr.ReadByte();
-            int i2 = inStr.ReadByte();
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
             if ((i1 != 3) || (i2 != 1))
             {
                 throw new TlsFatalAlert(AlertDescription.protocol_version);
             }
         }
 
+        public static ProtocolVersion ReadVersion(byte[] buf, int offset)
+        {
+            return ProtocolVersion.Get(buf[offset], buf[offset + 1]);
+        }
+
+        public static ProtocolVersion ReadVersion(Stream input)
+        {
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
+            if (i2 < 0)
+            {
+                throw new EndOfStreamException();
+            }
+            return ProtocolVersion.Get(i1, i2);
+        }
+
+        public static int ReadVersionRaw(byte[] buf, int offset)
+        {
+            return (buf[offset] << 8) | buf[offset + 1];
+        }
+
+        public static int ReadVersionRaw(Stream input)
+        {
+            int i1 = input.ReadByte();
+            int i2 = input.ReadByte();
+            if (i2 < 0)
+            {
+                throw new EndOfStreamException();
+            }
+            return (i1 << 8) | i2;
+        }
+
         public static Asn1Object ReadAsn1Object(byte[] encoding)
         {
             Asn1InputStream asn1 = new Asn1InputStream(encoding);
@@ -354,18 +525,47 @@ namespace Org.BouncyCastle.Crypto.Tls
             buf[offset + 3] = (byte)t;
         }
 
-        public static void WriteVersion(Stream os)
+        [Obsolete]
+        public static void WriteVersion(Stream output)
         {
-            os.WriteByte(3);
-            os.WriteByte(1);
+            output.WriteByte(3);
+            output.WriteByte(1);
         }
 
+        [Obsolete]
         public static void WriteVersion(byte[] buf, int offset)
         {
             buf[offset] = 3;
             buf[offset + 1] = 1;
         }
 
+        public static void WriteVersion(ProtocolVersion version, Stream output)
+        {
+            output.WriteByte((byte)version.MajorVersion);
+            output.WriteByte((byte)version.MinorVersion);
+        }
+
+        public static void WriteVersion(ProtocolVersion version, byte[] buf, int offset)
+        {
+            buf[offset] = (byte)version.MajorVersion;
+            buf[offset + 1] = (byte)version.MinorVersion;
+        }
+
+        public static IList GetDefaultDssSignatureAlgorithms()
+        {
+            return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.dsa));
+        }
+
+        public static IList GetDefaultECDsaSignatureAlgorithms()
+        {
+            return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa));
+        }
+
+        public static IList GetDefaultRsaSignatureAlgorithms()
+        {
+            return VectorOfOne(new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa));
+        }
+
         public static byte[] GetExtensionData(Hashtable extensions, int extensionType)
         {
             return extensions == null ? null : (byte[])extensions[extensionType];
@@ -411,27 +611,6 @@ namespace Org.BouncyCastle.Crypto.Tls
             }
         }
 
-        private static void hmac_hash(IDigest digest, byte[] secret, byte[] seed, byte[] output)
-        {
-            HMac mac = new HMac(digest);
-            mac.Init(new KeyParameter(secret));
-            byte[] a = seed;
-            int size = digest.GetDigestSize();
-            int iterations = (output.Length + size - 1) / size;
-            byte[] buf = new byte[mac.GetMacSize()];
-            byte[] buf2 = new byte[mac.GetMacSize()];
-            for (int i = 0; i < iterations; i++)
-            {
-                mac.BlockUpdate(a, 0, a.Length);
-                mac.DoFinal(buf, 0);
-                a = buf;
-                mac.BlockUpdate(a, 0, a.Length);
-                mac.BlockUpdate(seed, 0, seed.Length);
-                mac.DoFinal(buf2, 0);
-                Array.Copy(buf2, 0, output, (size * i), System.Math.Min(size, output.Length - (size * i)));
-            }
-        }
-
         internal static byte[] PRF(byte[] secret, string asciiLabel, byte[] seed, int size)
         {
             byte[] label = Strings.ToAsciiByteArray(asciiLabel);
@@ -446,8 +625,8 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             byte[] buf = new byte[size];
             byte[] prf = new byte[size];
-            hmac_hash(new MD5Digest(), s1, ls, prf);
-            hmac_hash(new Sha1Digest(), s2, ls, buf);
+            HMacHash(new MD5Digest(), s1, ls, prf);
+            HMacHash(new Sha1Digest(), s2, ls, buf);
             for (int i = 0; i < size; i++)
             {
                 buf[i] ^= prf[i];
@@ -461,7 +640,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             byte[] labelSeed = Concat(label, seed);
 
             byte[] buf = new byte[size];
-            hmac_hash(digest, secret, labelSeed, buf);
+            HMacHash(digest, secret, labelSeed, buf);
             return buf;
         }
 
@@ -473,6 +652,27 @@ namespace Org.BouncyCastle.Crypto.Tls
             return c;
         }
 
+        internal static void HMacHash(IDigest digest, byte[] secret, byte[] seed, byte[] output)
+        {
+            HMac mac = new HMac(digest);
+            mac.Init(new KeyParameter(secret));
+            byte[] a = seed;
+            int size = digest.GetDigestSize();
+            int iterations = (output.Length + size - 1) / size;
+            byte[] buf = new byte[mac.GetMacSize()];
+            byte[] buf2 = new byte[mac.GetMacSize()];
+            for (int i = 0; i < iterations; i++)
+            {
+                mac.BlockUpdate(a, 0, a.Length);
+                mac.DoFinal(buf, 0);
+                a = buf;
+                mac.BlockUpdate(a, 0, a.Length);
+                mac.BlockUpdate(seed, 0, seed.Length);
+                mac.DoFinal(buf2, 0);
+                Array.Copy(buf2, 0, output, (size * i), System.Math.Min(size, output.Length - (size * i)));
+            }
+        }
+
         internal static void ValidateKeyUsage(X509CertificateStructure c, int keyUsageBits)
         {
             X509Extensions exts = c.TbsCertificate.Extensions;
@@ -490,5 +690,527 @@ namespace Org.BouncyCastle.Crypto.Tls
                 }
             }
         }
+
+        public static IDigest CreateHash(byte hashAlgorithm)
+        {
+            switch (hashAlgorithm)
+            {
+            case HashAlgorithm.md5:
+                return new MD5Digest();
+            case HashAlgorithm.sha1:
+                return new Sha1Digest();
+            case HashAlgorithm.sha224:
+                return new Sha224Digest();
+            case HashAlgorithm.sha256:
+                return new Sha256Digest();
+            case HashAlgorithm.sha384:
+                return new Sha384Digest();
+            case HashAlgorithm.sha512:
+                return new Sha512Digest();
+            default:
+                throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+            }
+        }
+
+        public static IDigest CloneHash(byte hashAlgorithm, IDigest hash)
+        {
+            switch (hashAlgorithm)
+            {
+            case HashAlgorithm.md5:
+                return new MD5Digest((MD5Digest)hash);
+            case HashAlgorithm.sha1:
+                return new Sha1Digest((Sha1Digest)hash);
+            case HashAlgorithm.sha224:
+                return new Sha224Digest((Sha224Digest)hash);
+            case HashAlgorithm.sha256:
+                return new Sha256Digest((Sha256Digest)hash);
+            case HashAlgorithm.sha384:
+                return new Sha384Digest((Sha384Digest)hash);
+            case HashAlgorithm.sha512:
+                return new Sha512Digest((Sha512Digest)hash);
+            default:
+                throw new ArgumentException("unknown HashAlgorithm", "hashAlgorithm");
+            }
+        }
+
+        private static IList VectorOfOne(object obj)
+        {
+            IList v = Platform.CreateArrayList(1);
+            v.Add(obj);
+            return v;
+        }
+
+        public static int GetEncryptionAlgorithm(int ciphersuite)
+        {
+            switch (ciphersuite)
+            {
+            case CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA:
+                return EncryptionAlgorithm.cls_3DES_EDE_CBC;
+
+            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+                return EncryptionAlgorithm.AEAD_CHACHA20_POLY1305;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
+                return EncryptionAlgorithm.AES_128_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+                return EncryptionAlgorithm.AES_128_CBC;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+                return EncryptionAlgorithm.AES_128_CCM;
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+                return EncryptionAlgorithm.AES_128_CCM_8;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+                return EncryptionAlgorithm.AES_128_GCM;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:
+            case CipherSuite.TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
+                return EncryptionAlgorithm.AES_256_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+                return EncryptionAlgorithm.AES_256_CBC;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+                return EncryptionAlgorithm.AES_256_CBC;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+                return EncryptionAlgorithm.AES_256_CCM;
+
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+                return EncryptionAlgorithm.AES_256_CCM_8;
+
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+                return EncryptionAlgorithm.AES_256_GCM;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA:
+                return EncryptionAlgorithm.CAMELLIA_128_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+                return EncryptionAlgorithm.CAMELLIA_128_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+                return EncryptionAlgorithm.CAMELLIA_128_GCM;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA:
+                return EncryptionAlgorithm.CAMELLIA_256_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+                return EncryptionAlgorithm.CAMELLIA_256_CBC;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384:
+                return EncryptionAlgorithm.CAMELLIA_256_CBC;
+
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+                return EncryptionAlgorithm.CAMELLIA_256_GCM;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_DHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_PSK_WITH_ESTREAM_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1:
+                return EncryptionAlgorithm.ESTREAM_SALSA20;
+
+            case CipherSuite.TLS_RSA_WITH_NULL_MD5:
+                return EncryptionAlgorithm.NULL;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_NULL_SHA:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA:
+                return EncryptionAlgorithm.NULL;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA256:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+                return EncryptionAlgorithm.NULL;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_PSK_WITH_NULL_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384:
+                return EncryptionAlgorithm.NULL;
+
+            case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_MD5:
+                return EncryptionAlgorithm.RC4_128;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_anon_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDH_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_PSK_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_WITH_RC4_128_SHA:
+            case CipherSuite.TLS_RSA_PSK_WITH_RC4_128_SHA:
+                return EncryptionAlgorithm.RC4_128;
+
+            case CipherSuite.TLS_DHE_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_DHE_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_PSK_WITH_SALSA20_SHA1:
+            case CipherSuite.TLS_RSA_WITH_SALSA20_SHA1:
+                return EncryptionAlgorithm.SALSA20;
+
+            case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DHE_DSS_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_DHE_RSA_WITH_SEED_CBC_SHA:
+            case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA:
+                return EncryptionAlgorithm.SEED_CBC;
+
+            default:
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+            }
+        }
+
+        public static ProtocolVersion GetMinimumVersion(int ciphersuite)
+        {
+            switch (ciphersuite)
+            {
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM:
+            case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM:
+            case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8:
+            case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256:
+            case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384:
+            case CipherSuite.TLS_RSA_WITH_NULL_SHA256:
+                return ProtocolVersion.TLSv12;
+
+            default:
+                return ProtocolVersion.SSLv3;
+            }
+        }
+
+        public static bool IsAeadCipherSuite(int ciphersuite)
+        {
+            switch (GetEncryptionAlgorithm(ciphersuite))
+            {
+            case EncryptionAlgorithm.AES_128_GCM:
+            case EncryptionAlgorithm.AES_256_GCM:
+            case EncryptionAlgorithm.AES_128_CCM:
+            case EncryptionAlgorithm.AES_128_CCM_8:
+            case EncryptionAlgorithm.AES_256_CCM:
+            case EncryptionAlgorithm.AES_256_CCM_8:
+            case EncryptionAlgorithm.CAMELLIA_128_GCM:
+            case EncryptionAlgorithm.CAMELLIA_256_GCM:
+            case EncryptionAlgorithm.AEAD_CHACHA20_POLY1305:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public static bool IsBlockCipherSuite(int ciphersuite)
+        {
+            switch (GetEncryptionAlgorithm(ciphersuite))
+            {
+            case EncryptionAlgorithm.RC2_CBC_40:
+            case EncryptionAlgorithm.IDEA_CBC:
+            case EncryptionAlgorithm.DES40_CBC:
+            case EncryptionAlgorithm.DES_CBC:
+            case EncryptionAlgorithm.cls_3DES_EDE_CBC:
+            case EncryptionAlgorithm.AES_128_CBC:
+            case EncryptionAlgorithm.AES_256_CBC:
+            case EncryptionAlgorithm.CAMELLIA_128_CBC:
+            case EncryptionAlgorithm.CAMELLIA_256_CBC:
+            case EncryptionAlgorithm.SEED_CBC:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public static bool IsStreamCipherSuite(int ciphersuite)
+        {
+            switch (GetEncryptionAlgorithm(ciphersuite))
+            {
+            case EncryptionAlgorithm.RC4_40:
+            case EncryptionAlgorithm.RC4_128:
+            case EncryptionAlgorithm.ESTREAM_SALSA20:
+            case EncryptionAlgorithm.SALSA20:
+                return true;
+            default:
+                return false;
+            }
+        }
+
+        public static bool IsValidCipherSuiteForVersion(int cipherSuite, ProtocolVersion serverVersion)
+        {
+            return GetMinimumVersion(cipherSuite).IsEqualOrEarlierVersionOf(serverVersion.GetEquivalentTLSVersion());
+        }
     }
 }