Exemple #1
0
        /// <summary>
        /// Constructs a key chain by decrypting bytes returned by a previous
        /// call to <see cref="Encrypt" />.
        /// </summary>
        /// <param name="key">The <see cref="SymmetricKey" /> to be used for decrypting.</param>
        /// <param name="encrypted">The encrypted key chain.</param>
        /// <exception cref="CryptographicException">Thrown if the decrypted key chain is malformed.</exception>
        public KeyChain(SymmetricKey key, byte[] encrypted)
        {
            try
            {
                using (var ms = new EnhancedMemoryStream(Crypto.Decrypt(encrypted, key)))
                {
                    if (ms.ReadInt32() != Magic)
                    {
                        throw new Exception();
                    }

                    int count;

                    count = ms.ReadInt32();
                    keys  = new Dictionary <string, string>(count);

                    for (int i = 0; i < count; i++)
                    {
                        Add(ms.ReadString16());
                    }
                }
            }
            catch (Exception e)
            {
                throw new CryptographicException("Key chain is malformed.", e);
            }
        }
Exemple #2
0
        public void EnhancedMemoryStream_Int32()
        {
            var es = new EnhancedMemoryStream();

            es.WriteInt32(0);
            es.WriteInt32(65121);
            es.WriteInt32(0x12345678);

            es.Seek(0, SeekOrigin.Begin);

            Assert.AreEqual(0, es.ReadInt32());
            Assert.AreEqual(65121, es.ReadInt32());
            Assert.AreEqual(0x12345678, es.ReadInt32());
        }
Exemple #3
0
        /// <summary>
        /// Decrypts authentication <see cref="Credentials" /> from a
        /// byte array using the specified public asymmetric private key and
        /// algorithm.
        /// </summary>
        /// <param name="encrypted">The encrypted credential bytes.</param>
        /// <param name="algorithm">The encryption algorithm.</param>
        /// <param name="key">The private key.</param>
        /// <returns>The decrypted <see cref="Credentials" />.</returns>
        /// <remarks>
        /// <note>
        /// The current implementation supports only the "RSA" provider.
        /// </note>
        /// </remarks>
        /// <exception cref="SecurityException">Thrown if the credentials are corrupt.</exception>
        public static Credentials DecryptCredentials(byte[] encrypted, string algorithm, string key)
        {
            try
            {
                var decrypted = Decrypt(algorithm, key, encrypted);

                using (var ms = new EnhancedMemoryStream(decrypted))
                {
                    string realm;
                    string account;
                    string password;

                    if (ms.ReadInt32() != Crypto.CredentialMagic)
                    {
                        throw new SecurityException(Crypto.CorruptCredentialsMsg);
                    }

                    realm    = ms.ReadString16();
                    account  = ms.ReadString16();
                    password = ms.ReadString16();

                    return(new Credentials(realm, account, password));
                }
            }
            catch (Exception e)
            {
                throw new SecurityException(Crypto.CorruptCredentialsMsg, e);
            }
        }
Exemple #4
0
        /// <summary>
        /// Decrypts data encrypted using <see cref="Encrypt(SymmetricKey,byte[],int)" />.
        /// </summary>
        /// <param name="symmetricKey">The symmetric algorithm arguments.</param>
        /// <param name="cipherText">The encrypted data.</param>
        /// <returns>The decrypted result.</returns>
        public static byte[] Decrypt(SymmetricKey symmetricKey, byte[] cipherText)
        {
            EnhancedMemoryStream input     = new EnhancedMemoryStream(cipherText);
            EnhancedMemoryStream ms        = new EnhancedMemoryStream(cipherText.Length);
            BlockDecryptor       decryptor = null;

            try
            {
                // Read the header fields

                if (input.ReadInt32() != Magic)
                {
                    throw new CryptographicException(BadFormatMsg);
                }

                if (input.ReadInt32() != 0)
                {
                    throw new CryptographicException("Unsupported secure data format version.");
                }

                decryptor = new BlockDecryptor(symmetricKey);

                // Decrypt the contents

                ms.WriteBytesNoLen(decryptor.Decrypt(input.ReadBytes32()));
                ms.Position = 0;

                if (ms.ReadInt32() != Magic)
                {
                    throw new CryptographicException("Secure data content is corrupt.");
                }

                ms.Position += 8;   // Skip over the salt

                return(ms.ReadBytes32());
            }
            finally
            {
                if (decryptor != null)
                {
                    decryptor.Dispose();
                }

                input.Close();
                ms.Close();
            }
        }
Exemple #5
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);
            }
        }
Exemple #6
0
        /// <summary>
        /// Called when the client receives a response.
        /// </summary>
        /// <param name="responseBytes">The serialized response.</param>
        private void OnResponse(byte[] responseBytes)
        {
            try
            {
                using (var input = new EnhancedMemoryStream(responseBytes))
                {
                    int typeCode = input.ReadInt32();
                    SharedMemMessage response;
                    PendingOperation operation;

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

                    response.InternalReadFrom(input);
                    response.ReadFrom(input);

                    lock (syncLock)
                    {
                        if (!pendingOperations.TryGetValue(response.InternalRequestId, out operation))
                        {
                            // The response received does not correlate to a pending operation
                            // (probably due to the client side timing it out).  We'll just
                            // ignore it.

                            return;
                        }
                    }

                    if (response.InternalError != null)
                    {
                        operation.Tcs.TrySetException(new SharedMemException(response.InternalError));
                    }
                    else
                    {
                        operation.Tcs.TrySetResult(response);
                    }
                }
            }
            catch (Exception e)
            {
                SysLog.LogException(e);
            }
        }
Exemple #7
0
        /// <summary>
        /// Verifies request arguments against a signature using a shared <see cref="SymmetricKey" />
        /// and the current time.
        /// </summary>
        /// <param name="sharedKey">The shared <see cref="SymmetricKey" />.</param>
        /// <param name="signature">The base-64 encoded signature.</param>
        /// <param name="args">The request argument collection.</param>
        /// <param name="signatureKey">
        /// The name of the signature key within the event arguments or <c>null</c>
        /// if the signature is not present.
        /// </param>
        /// <param name="graceInterval">Specifies the time period used for verifying the signature request time.</param>
        /// <returns><c>true</c> if the signature is valid.</returns>
        /// <remarks>
        /// <para>
        /// <paramref name="graceInterval" /> is used when comparing the request time (UTC) embedded
        /// in the signature with the current machine time (UTC).  Request times within the range of:
        /// </para>
        /// <code language="none">
        /// DateTime.UtcNow - graceInterval &lt;= requestTime &lt;= DateTime.UtcNow + graceInterval
        /// </code>
        /// <para>
        /// will be considered to be valid.  Request times outside this range will be invalid.
        /// Larger grace intervals provide help avoid the problems of incorrect system times or
        /// long request delivery delays but at the price of the increased exposure to replay
        /// attacks.
        /// </para>
        /// <note>
        /// If the signature is present in the arguments, then the <paramref name="signatureKey" /> <b>must</b>
        /// be passed as its name or else the verification will always fail.  The reason for this is
        /// that the hash was originally computed before the signature was added so the hash will be
        /// different if it includes the signature.
        /// </note>
        /// </remarks>
        public static bool TryVerify(SymmetricKey sharedKey, string signature, ArgCollection args, string signatureKey, TimeSpan graceInterval)
        {
            try
            {
                byte[]   encrypted = Convert.FromBase64String(signature);
                byte[]   decrypted;
                byte[]   requestHash;
                byte[]   hash;
                DateTime requestTime;
                DateTime now;

                decrypted = Crypto.Decrypt(encrypted, sharedKey);
                if (decrypted.Length != Size)
                {
                    return(false);
                }

                using (var ms = new EnhancedMemoryStream(decrypted))
                {
                    ms.Position = 8;
                    if (ms.ReadInt32() != Magic)
                    {
                        return(false);
                    }

                    requestTime = new DateTime(ms.ReadInt64());
                    requestHash = ms.ReadBytes(SHA1Hasher.DigestSize);
                }

                now = DateTime.UtcNow;
                if (!Helper.Within(requestTime, now, graceInterval))
                {
                    return(false);
                }

                hash = ComputeHash(args, signatureKey);
                return(Helper.ArrayEquals(requestHash, hash));
            }
            catch
            {
                return(false);
            }
        }
Exemple #8
0
        /// <summary>
        /// Decrypts the password change parameters encrypted by <see cref="EncryptPasswordChange" />.
        /// </summary>
        /// <param name="encryptedPasswords">The encryoted password change parameters.</param>
        /// <param name="originalPassword">Returns as the original password.</param>
        /// <param name="newPassword">Returns as the new password.</param>
        /// <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>
        /// <exception cref="SecurityException">Thrown if the parameters are corrupt.</exception>
        public static void DecryptPasswordChange(byte[] encryptedPasswords, out string originalPassword, out string newPassword)
        {
            try
            {
                var decrypted = DecryptWithSalt8(encryptedPasswords, credentialsKey);

                using (var ms = new EnhancedMemoryStream(decrypted))
                {
                    if (ms.ReadInt32() != CredentialMagic)
                    {
                        throw new SecurityException(CorruptCredentialsMsg);
                    }

                    originalPassword = ms.ReadString16();
                    newPassword      = ms.ReadString16();
                }
            }
            catch (Exception e)
            {
                throw new SecurityException(CorruptCredentialsMsg, e);
            }
        }
Exemple #9
0
        /// <summary>
        /// Decrypts a byte array encrypted using <see cref="Encrypt(string ,byte[],string,int,int,out SymmetricKey)" />.
        /// </summary>
        /// <param name="rsaKey">The decrypting RSA key as XML or as a secure key container name.</param>
        /// <param name="cipherText">The encrypted data.</param>
        /// <param name="symmetricKey">Returns as the symmetric encryption algorithm arguments.</param>
        /// <returns>The decrypted data.</returns>
        /// <exception cref="CryptographicException">Thrown is the encrypted data block is incorrectly formatted.</exception>
        /// <remarks>
        /// 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.
        /// </remarks>
        public static byte[] Decrypt(string rsaKey, byte[] cipherText, out SymmetricKey symmetricKey)
        {
            EnhancedMemoryStream input     = new EnhancedMemoryStream(cipherText);
            EnhancedMemoryStream ms        = new EnhancedMemoryStream(cipherText.Length);
            BlockDecryptor       decryptor = null;

            byte[] symKey;
            byte[] symIV;
            string algorithm;

            try
            {
                // Read the header fields

                if (input.ReadInt32() != Magic)
                {
                    throw new CryptographicException(BadFormatMsg);
                }

                if (input.ReadInt32() != 0)
                {
                    throw new CryptographicException("Unsupported secure data format version.");
                }

                // Decrypt the encryption info

                ms.WriteBytesNoLen(AsymmetricCrypto.Decrypt(CryptoAlgorithm.RSA, rsaKey, input.ReadBytes16()));
                ms.Position = 0;

                algorithm    = ms.ReadString16();
                symKey       = ms.ReadBytes16();
                symIV        = ms.ReadBytes16();
                symmetricKey = new SymmetricKey(algorithm, symKey, symIV);
                decryptor    = new BlockDecryptor(algorithm, symKey, symIV);

                // Decrypt the contents

                ms.SetLength(0);
                ms.WriteBytesNoLen(decryptor.Decrypt(input.ReadBytes32()));
                ms.Position = 0;

                if (ms.ReadInt32() != Magic)
                {
                    throw new CryptographicException("Secure data content is corrupt.");
                }

                ms.Position += 8;   // Skip over the salt

                return(ms.ReadBytes32());
            }
            finally
            {
                if (decryptor != null)
                {
                    decryptor.Dispose();
                }

                input.Close();
                ms.Close();
            }
        }