Example #1
0
        /// <summary>
        /// Called when the server receives an unserialized request.
        /// </summary>
        /// <param name="requestBytes">The serialized request.</param>
        private void OnRequest(byte[] requestBytes)
        {
            try
            {
                using (var input = new EnhancedMemoryStream(requestBytes))
                {
                    int typeCode = input.ReadInt32();
                    SharedMemMessage request;
                    SharedMemMessage response;

                    if (typeCode < 0)
                    {
                        request = new SharedMemErrorMessage();
                    }
                    else
                    {
                        request = messageFactory.Create(typeCode);
                    }

                    request.InternalReadFrom(input);
                    request.ReadFrom(input);

                    try
                    {
                        response = requestHandler(request);

                        if (response == null)
                        {
                            throw new NullReferenceException("Server request handler returned a NULL response message.");
                        }
                    }
                    catch (Exception e)
                    {
                        response = new SharedMemErrorMessage();
                        response.InternalError = string.Format("{0}: {1}", e.GetType().FullName, e.Message);
                    }

                    response.InternalRequestId   = request.InternalRequestId;
                    response.InternalClientInbox = request.InternalClientInbox;

                    using (var output = new EnhancedMemoryStream(response.SerializedCapacityHint))
                    {
                        output.WriteInt32(response.TypeCode);
                        response.InternalWriteTo(output);
                        response.WriteTo(output);

                        // This call is synchronous but should execute very quickly (microseconds).

                        outbox.Send(response.InternalClientInbox, output.ToArray());
                    }
                }
            }
            catch (Exception e)
            {
                SysLog.LogException(e);
            }
        }
Example #2
0
        /// <summary>
        /// Casually encrypts the old and new password to be used to during
        /// a change password operation.
        /// </summary>
        /// <param name="originalPassword">The original password.</param>
        /// <param name="newPassword">The new password.</param>
        /// <returns>The encrypted password change parameters.</returns>
        /// <remarks>
        /// <note>
        /// This method is designed to provide a low level of security during development
        /// and testing, when the overhead of configuring SSL certificates is not worth
        /// the trouble.  Do not rely on this method as your only mechanism for securing
        /// credentials during transmission in production environments.
        /// </note>
        /// </remarks>
        public static byte[] EncryptPasswordChange(string originalPassword, string newPassword)
        {
            using (var ms = new EnhancedMemoryStream(256))
            {
                ms.WriteInt32(CredentialMagic);
                ms.WriteString16(originalPassword);
                ms.WriteString16(newPassword);

                return(EncryptWithSalt8(ms.ToArray(), credentialsKey));
            }
        }
Example #3
0
        /// <summary>
        /// Generates a request signature using a shared <see cref="SymmetricKey" />
        /// for request arguments as well as the current time.
        /// </summary>
        /// <param name="sharedKey">The shared <see cref="SymmetricKey" />.</param>
        /// <param name="args">The request argument collection.</param>
        /// <returns>The base-64 encoded signature.</returns>
        public static string Generate(SymmetricKey sharedKey, ArgCollection args)
        {
            using (var ms = new EnhancedMemoryStream(512))
            {
                ms.WriteBytesNoLen(Crypto.GetSalt8());
                ms.WriteInt32(Magic);
                ms.WriteInt64(DateTime.UtcNow.Ticks);
                ms.WriteBytesNoLen(ComputeHash(args, null));

                return(Convert.ToBase64String(Crypto.Encrypt(ms.ToArray(), sharedKey)));
            }
        }
Example #4
0
        /// <summary>
        /// Casually encrypts authentication <see cref="Credentials" /> into a byte
        /// array using using the <see cref="CredentialsKey" />.
        /// </summary>
        /// <param name="credentials">The <see cref="Credentials" />.</param>
        /// <returns>The encrypted credentials.</returns>
        /// <remarks>
        /// <note>
        /// This method is designed to provide a low level of security during development
        /// and testing, when the overhead of configuring SSL certificates is not worth
        /// the trouble.  Do not rely on this method as your only mechanism for securing
        /// credentials during transmission in production environments.
        /// </note>
        /// </remarks>
        public static byte[] EncryptCredentials(Credentials credentials)
        {
            using (var ms = new EnhancedMemoryStream(256))
            {
                ms.WriteInt32(CredentialMagic);
                ms.WriteString16(credentials.Realm);
                ms.WriteString16(credentials.Account);
                ms.WriteString16(credentials.Password);

                return(EncryptWithSalt8(ms.ToArray(), credentialsKey));
            }
        }
Example #5
0
        /// <summary>
        /// Asynchronously submits a <see cref="SharedMemMessage"/> request message to the server
        /// and waits for and returns the response <see cref="SharedMemMessage"/>.
        /// </summary>
        /// <param name="request">The request message.</param>
        /// <param name="timeout">The optional timeout to override the <see cref="Timeout"/> property.
        /// </param>
        /// <returns>The response <see cref="SharedMemMessage"/>.</returns>
        public Task <SharedMemMessage> CallAsync(SharedMemMessage request, TimeSpan?timeout = null)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            if (request.InternalRequestId != Guid.Empty)
            {
                throw new InvalidOperationException("Cannot reuse a [SharedMemMessage] request instance previously submitted for a call operation.");
            }

            request.InternalRequestId   = Guid.NewGuid();
            request.InternalClientInbox = this.ClientName;

            if (!timeout.HasValue)
            {
                timeout = this.Timeout;
            }

            var operation = new PendingOperation(request, new TaskCompletionSource <SharedMemMessage>(), stopwatch.Elapsed + timeout.Value);

            lock (syncLock)
            {
                pendingOperations.Add(request.InternalRequestId, operation);
            }

            try
            {
                using (var output = new EnhancedMemoryStream(request.SerializedCapacityHint))
                {
                    output.WriteInt32(request.TypeCode);
                    request.InternalWriteTo(output);
                    request.WriteTo(output);

                    // This call is synchronous but should execute very quickly (microseconds).

                    outbox.Send(ServerName, output.ToArray());
                }
            }
            catch (Exception e)
            {
                lock (syncLock)
                {
                    pendingOperations.Remove(operation.RequestMessage.InternalRequestId);
                }

                operation.Tcs.TrySetException(e);
            }

            return(operation.Tcs.Task);
        }
Example #6
0
        /// <summary>
        /// Encrypts authentication <see cref="Credentials" /> into a byte
        /// array using the specified public asymmetric public key and
        /// algorithm.
        /// </summary>
        /// <param name="credentials">The <see cref="Credentials" />.</param>
        /// <param name="algorithm">The encryption algorithm.</param>
        /// <param name="key">The public key.</param>
        /// <returns>The encrypted credentials.</returns>
        /// <remarks>
        /// The current implementation supports only the "RSA" provider.
        /// </remarks>
        public static byte[] EncryptCredentials(Credentials credentials, string algorithm, string key)
        {
            using (var ms = new EnhancedMemoryStream(256))
            {
                ms.WriteInt32(Crypto.CredentialMagic);
                ms.WriteString16(credentials.Realm);
                ms.WriteString16(credentials.Account);
                ms.WriteString16(credentials.Password);
                ms.WriteBytesNoLen(Crypto.GetSalt4());

                return(Encrypt(algorithm, key, ms.ToArray()));
            }
        }
Example #7
0
        public void EnhancedMemoryStream_ToByteArray()
        {
            var es = new EnhancedMemoryStream();

            byte[] buf;

            es.Write(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 0, 10);
            buf = es.ToArray();
            CollectionAssert.AreEqual(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, buf);

            buf[0]      = 255;
            es.Position = 0;
            Assert.AreEqual(0, es.ReadByte());
        }
Example #8
0
        /// <summary>
        /// Serializes the instance to a byte array.
        /// </summary>
        /// <returns>The serialized array.</returns>
        public byte[] ToArray()
        {
            var ms = new EnhancedMemoryStream();

            try
            {
                Write(ms);
                return(ms.ToArray());
            }
            finally
            {
                ms.Close();
            }
        }
Example #9
0
        /// <summary>
        /// Encrypts the keys using the symmetric key passed.
        /// </summary>
        /// <returns>The encrypted key chain.</returns>
        public byte[] Encrypt(SymmetricKey key)
        {
            using (var ms = new EnhancedMemoryStream())
            {
                ms.WriteInt32(Magic);
                ms.WriteInt32(keys.Count);

                foreach (string privateKey in keys.Values)
                {
                    ms.WriteString16(privateKey);
                }

                ms.WriteBytesNoLen(Crypto.GetSalt8());

                return(Crypto.Encrypt(ms.ToArray(), key));
            }
        }
Example #10
0
        /// <summary>
        /// Serializes and encrypts the message into a byte array.
        /// </summary>
        /// <param name="sharedKey">The shared encryption key.</param>
        /// <returns>The serialized message.</returns>
        public byte[] ToArray(SymmetricKey sharedKey)
        {
            if (this.HostEntry == null)
            {
                throw new InvalidOperationException("HostEntry property cannot be null.");
            }

            using (var ms = new EnhancedMemoryStream(2048))
            {
                ms.WriteInt32Le(Magic);
                ms.WriteByte((byte)FormatVer);
                ms.WriteInt64Le(TimeStampUtc.Ticks);
                ms.WriteInt32Le((int)Flags);
                ms.WriteString16(this.HostEntry.ToString());
                ms.WriteBytesNoLen(Crypto.GetSalt4());

                return(Crypto.Encrypt(ms.ToArray(), sharedKey));
            }
        }
Example #11
0
        /// <summary>
        /// Performs a secure symmetric encryption including cryptographic salt, padding, and
        /// data validation.
        /// </summary>
        /// <param name="symmetricKey">The symmetric algorithm arguments.</param>
        /// <param name="plainText">The unencrypted data.</param>
        /// <param name="paddedSize">Specifies the minimum padded size of the encrypted content.</param>
        /// <returns>The encrypted result.</returns>
        public static byte[] Encrypt(SymmetricKey symmetricKey, byte[] plainText, int paddedSize)
        {
            EnhancedMemoryStream output    = new EnhancedMemoryStream(Math.Max(plainText.Length, paddedSize) + 512);
            EnhancedMemoryStream ms        = new EnhancedMemoryStream(512);
            BlockEncryptor       encryptor = new BlockEncryptor(symmetricKey);

            try
            {
                // Write header fields

                output.WriteInt32(Magic);
                output.WriteInt32(0);

                // Write encrypted contents

                ms.WriteInt32(Magic);
                ms.WriteBytesNoLen(Crypto.GetSalt8());
                ms.WriteBytes32(plainText);

                for (int i = plainText.Length; i < paddedSize; i++)
                {
                    ms.WriteByte((byte)i);     // Padding bytes
                }
                output.WriteBytes32(encryptor.Encrypt(ms.ToArray()));

                // That's it, we're done.

                return(output.ToArray());
            }
            finally
            {
                if (encryptor != null)
                {
                    encryptor.Dispose();
                }

                output.Close();
                ms.Close();
            }
        }
Example #12
0
        /// <summary>
        /// Serializes and encrypts the message into a byte array.
        /// </summary>
        /// <param name="sharedKey">The shared encryption key.</param>
        /// <returns>The serialized message.</returns>
        public byte[] ToArray(SymmetricKey sharedKey)
        {
            using (var ms = new EnhancedMemoryStream(2048))
            {
                var addressBytes = SourceAddress.GetAddressBytes();

                if (addressBytes.Length != 4)
                {
                    throw new InvalidOperationException("UdpBroadcastMessage supports only IPv4 address.");
                }

                ms.WriteInt32Le(Magic);
                ms.WriteInt64Le(TimeStampUtc.Ticks);
                ms.WriteBytesNoLen(SourceAddress.GetAddressBytes());
                ms.WriteByte((byte)MessageType);
                ms.WriteByte((byte)BroadcastGroup);
                ms.WriteBytes16(Payload);
                ms.WriteBytesNoLen(Crypto.GetSalt4());

                return(Crypto.Encrypt(ms.ToArray(), sharedKey));
            }
        }
Example #13
0
        public void HttpRequest_Content_ChunkedTransfer()
        {
            HttpRequest          r;
            EnhancedMemoryStream ms;

            byte[] bufOut;
            byte[] buf;

            bufOut = new byte[300];
            for (int i = 0; i < bufOut.Length; i++)
            {
                bufOut[i] = (byte)i;
            }

            // Test parsing where the entire request is in a single input block.

            ms = new EnhancedMemoryStream();
            ms.WriteBytesNoLen(Encoding.ASCII.GetBytes("GET /foo.htm HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"));

            ms.WriteBytesNoLen(Encoding.ASCII.GetBytes("12c; extra crap\r\n"));     // 12c = 300 as hex
            ms.WriteBytesNoLen(bufOut);
            ms.WriteBytesNoLen(Encoding.ASCII.GetBytes("\r\n"));

            ms.WriteBytesNoLen(Encoding.ASCII.GetBytes("0; extra crap\r\n\r\n"));

            buf = ms.ToArray();
            r   = new HttpRequest();
            r.BeginParse(80);
            Assert.IsTrue(r.Parse(buf, buf.Length));
            r.EndParse();

            Assert.AreEqual(bufOut.Length, r.Content.Size);
            CollectionAssert.AreEqual(bufOut, r.Content.ToByteArray());

            // Test parsing of two chunks in a single input block.

            ms = new EnhancedMemoryStream();
            ms.WriteBytesNoLen(Encoding.ASCII.GetBytes("GET /foo.htm HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n"));

            ms.WriteBytesNoLen(Encoding.ASCII.GetBytes("FF\r\n"));     // FF = 255 as hex
            ms.Write(bufOut, 0, 255);
            ms.WriteBytesNoLen(Encoding.ASCII.GetBytes("\r\n"));

            ms.WriteBytesNoLen(Encoding.ASCII.GetBytes("2D\r\n"));     // 2D = 45 as hex (300 - 255)
            ms.Write(bufOut, 255, 45);
            ms.WriteBytesNoLen(Encoding.ASCII.GetBytes("\r\n"));

            ms.WriteBytesNoLen(Encoding.ASCII.GetBytes("0\r\n\r\n"));

            buf = ms.ToArray();
            r   = new HttpRequest();
            r.BeginParse(80);
            Assert.IsTrue(r.Parse(buf, buf.Length));
            r.EndParse();

            Assert.AreEqual(bufOut.Length, r.Content.Size);
            CollectionAssert.AreEqual(bufOut, r.Content.ToByteArray());

            // Repeat the 2 chunk test but this time break the input into blocks of
            // only a single byte each.  This will torture test the parsing state machines.

            buf = ms.ToArray();
            r   = new HttpRequest();
            r.BeginParse(80);

            for (int i = 0; i < buf.Length - 1; i++)
            {
                Assert.IsFalse(r.Parse(new byte[] { buf[i] }, 1));
            }

            Assert.IsTrue(r.Parse(new byte[] { buf[buf.Length - 1] }, 1));

            r.EndParse();

            Assert.AreEqual(bufOut.Length, r.Content.Size);
            CollectionAssert.AreEqual(bufOut, r.Content.ToByteArray());
        }
Example #14
0
        /// <summary>
        /// Encrypts a byte array using a combination of an asymmetric RSA key and the
        /// specified symmetric encryption algorithm and a one-time key generated by
        /// the method.
        /// </summary>
        /// <param name="rsaKey">The encrypting RSA key as XML or as a secure key container name.</param>
        /// <param name="plainText">The data to be encrypted.</param>
        /// <param name="algorithm">The symmetric encryption algorithm name.</param>
        /// <param name="keySize">The one-time symmetric key size to generate in bits.</param>
        /// <param name="paddedSize">Specifies the minimum padded size of the encrypted content.</param>
        /// <param name="symmetricKey">Returns as the symmetric encryption algorithm arguments.</param>
        /// <returns>The encrypted result.</returns>
        /// <remarks>
        /// <para>
        /// Note that applications should take some care to ensure that the <paramref name="symmetricKey" />
        /// value return is disposed so that the symmetric encryption key will be cleared.
        /// </para>
        /// <para>
        /// The current supported cross platform encryption algorithms
        /// are: "DES", "RC2", "TripleDES", and "AES" (Rijndael).
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentException">Thrown if the requested encryption algorithm is unknown.</exception>
        public static byte[] Encrypt(string rsaKey, byte[] plainText, string algorithm, int keySize, int paddedSize,
                                     out SymmetricKey symmetricKey)
        {
            EnhancedMemoryStream output    = new EnhancedMemoryStream(Math.Max(plainText.Length, paddedSize) + 512);
            EnhancedMemoryStream ms        = new EnhancedMemoryStream(512);
            BlockEncryptor       encryptor = null;

            byte[] symKey;
            byte[] symIV;

            Crypto.GenerateSymmetricKey(algorithm, keySize, out symKey, out symIV);

            encryptor    = new BlockEncryptor(algorithm, symKey, symIV);
            symmetricKey = new SymmetricKey(algorithm, (byte[])symKey.Clone(), (byte[])symIV.Clone());

            try
            {
                // Write header fields

                output.WriteInt32(Magic);
                output.WriteInt32(0);

                // Write encryption Info

                ms.WriteString16(algorithm);
                ms.WriteBytes16(symKey);
                ms.WriteBytes16(symIV);
                ms.WriteBytesNoLen(Crypto.GetSalt8());
                output.WriteBytes16(AsymmetricCrypto.Encrypt(CryptoAlgorithm.RSA, rsaKey, ms.ToArray()));

                // Write encrypted contents

                ms.SetLength(0);
                ms.WriteInt32(Magic);
                ms.WriteBytesNoLen(Crypto.GetSalt8());
                ms.WriteBytes32(plainText);

                for (int i = plainText.Length; i < paddedSize; i++)
                {
                    ms.WriteByte((byte)i);     // Padding bytes
                }
                output.WriteBytes32(encryptor.Encrypt(ms.ToArray()));

                // That's it, we're done.

                return(output.ToArray());
            }
            finally
            {
                if (symKey != null)
                {
                    Array.Clear(symKey, 0, symKey.Length);
                }

                if (symIV != null)
                {
                    Array.Clear(symIV, 0, symIV.Length);
                }

                if (encryptor != null)
                {
                    encryptor.Dispose();
                }

                output.Close();
                ms.Close();
            }
        }
Example #15
0
        public void SecureFile_File_KeyChain()
        {
            string encryptName            = Path.GetTempFileName();
            string privateKey             = AsymmetricCrypto.CreatePrivateKey(CryptoAlgorithm.RSA, 1024);
            string publicKey              = AsymmetricCrypto.GetPublicKey(CryptoAlgorithm.RSA, privateKey);
            EnhancedMemoryStream original = new EnhancedMemoryStream();
            SecureFile           secure   = null;

            try
            {
                for (int i = 0; i < 100; i++)
                {
                    original.WriteByte((byte)i);
                }

                // Verify that SecureFile can find the correct private key in the key chain.

                secure = new SecureFile(original, SecureFileMode.Encrypt, publicKey);
                Assert.IsTrue(secure.SavePublicKey);
                Assert.AreEqual(publicKey, secure.PublicKey);

                original.Position = 0;
                secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256);
                secure.Close();
                secure = null;

                var keyChain  = new KeyChain();
                var decrypted = new EnhancedMemoryStream();

                keyChain.Add(privateKey);

                secure = new SecureFile(encryptName, keyChain);
                secure.DecryptTo(decrypted);
                secure.Close();
                secure = null;

                CollectionAssert.AreEqual(original.ToArray(), decrypted.ToArray());

                // Verify that SecureFile throws a CryptographicException if the
                // key is not present in the chain.

                keyChain.Clear();

                try
                {
                    secure = new SecureFile(encryptName, keyChain);
                    secure.DecryptTo(decrypted);
                    Assert.Fail("Expecting a CryptographicException");
                }
                catch (CryptographicException)
                {
                    // Expecting this
                }
                finally
                {
                    if (secure != null)
                    {
                        secure.Close();
                        secure = null;
                    }
                }

                // Verify that SecureFile throws a CryptographicException if the
                // public key was not saved to the file.

                keyChain.Add(privateKey);

                secure = new SecureFile(original, SecureFileMode.Encrypt, publicKey);
                secure.SavePublicKey = false;

                original.Position = 0;

                secure.EncryptTo(encryptName, CryptoAlgorithm.AES, 256);
                secure.Close();
                secure = null;

                try
                {
                    secure = new SecureFile(encryptName, keyChain);
                    secure.DecryptTo(decrypted);
                    Assert.Fail("Expecting a CryptographicException");
                }
                catch (CryptographicException)
                {
                    // Expecting this
                }
                finally
                {
                    if (secure != null)
                    {
                        secure.Close();
                        secure = null;
                    }
                }
            }
            finally
            {
                System.IO.File.Delete(encryptName);
            }
        }