2

We have a class that holds the user's logon profiles, it's a simple class that we just serialize to disk. We could certainly encrypt, compress, etc. etc. the serialization process, however, I want to keep it simple for other reasons.

One item that is serialized is the Password (string) property. I don't mind that it's being serialized but I want the value that is serialized to be 3DES encrypted so if someone were to open the file in some reader it wouldn't compromise the password. I know I can simply SET the password value as the encrypted value and GET the encrypted value but I want to automate it a little bit so that when the GET'er is called it handles the decryption, the SET'er handles the encryption so it's seamless.

What do you suggest is the best way to go about this? What I'm thinking is I need to mark the "Password" property to be ignored by the serializer and it's just a path to another property that holds the encrypted value and therefore returns it decrypted. Is this the best/only way to handle this? Just want to see if there is a simpler way before I go coding this up via the only way I can see doing this to keep the encryption/decryption within the serialized class logic.

Thanks.

Neal
  • 9,487
  • 15
  • 58
  • 101
  • 1
    On a side note: why would you want to store the password itself? Can't you make a salt and a hash and store those instead? Still probably a good idea to encrypt those as well of course... – Jeroen Apr 17 '12 at 21:00
  • 2
    Why wouldn't the passwords already be hashed? Please tell me you're not using plain text passwords that are encrypted. – Stephen Gilboy Apr 17 '12 at 21:00
  • @Jeroen Why bother encrypting the salted password hash? The whole point is that you don't care all that much if someone gets ahold of it, as long as you salt it and don't use a terrible hashing algorithm. – Servy Apr 17 '12 at 21:01
  • You shouldn't be storing user passwords at all. You should store a hash of the password. This answer links to a bunch of related questions: http://stackoverflow.com/a/1054033/385844 – phoog Apr 17 '12 at 21:01

3 Answers3

11

You can mark the password property to be ignored by serialization and use kind of an wrapper property to be serialized:

public class LogonInfo
{
    [XmlIgnore]
    public string Password { get; set; }

    public string EncPassword {
    {
        get
        {
            return Encrypt(Password);
        }
        set
        {
            Password = Decrypt(value);
        }
    }

    // TODO: add Encrypt and Decrypt methods
}
MatthiasG
  • 4,434
  • 3
  • 27
  • 47
  • Not sure this will work, it's the same concept I was thinking, I don't think it's coded correctly in this sample. – Neal Apr 17 '12 at 21:23
  • The code in getters/setters should be in the XmlIgnore property "Password" so it decrypts EncPassword on GET and on SET it Encrypts the value. If you edit your code I'll mark it as the answer, it just needs to be touched up. Thanks. – Neal Apr 17 '12 at 21:52
  • 1
    Wouldn't that just be a inversion of responsibilities and not changing anything? Not sure about it, but the code feels right. Time for unit tests ;) – MatthiasG Apr 17 '12 at 21:58
  • Not working because if it loaded from XML the encrypted string is encrypted again. – Suplanus Jan 16 '20 at 12:32
2

You can use ExtendedXmlSerializer. If you have a class with a property that needs to be encrypted:

public class Person
{
    public string Name { get; set; }
    public string Password { get; set; }
}

You must implement interface IPropertyEncryption. For example, it will show the Base64 encoding, but in the real world better to use something safer, eg. RSA.:

public class Base64PropertyEncryption : IPropertyEncryption
{
    public string Encrypt(string value)
    {
        return Convert.ToBase64String(Encoding.UTF8.GetBytes(value));
    }

    public string Decrypt(string value)
    {
        return Encoding.UTF8.GetString(Convert.FromBase64String(value));
    }
}

In the Person class configuration you need to specify which properties are to be encrypted:

public class PersonConfig : ExtendedXmlSerializerConfig<Person>
{
    public PersonConfig()
    {
        Encrypt(p => p.Password);
    }
}

Then, you must register your PersonConfig class and your implementation of IPropertyEncryption. In documentation is describe configuration using Autofac. There is simple configuration:

var toolsFactory = new SimpleSerializationToolsFactory();

// Register your config class
toolsFactory.Configurations.Add(new PersonConfig());

// If you want to use property encryption you must register your implementation of IPropertyEncryption, e.g.:
toolsFactory.EncryptionAlgorithm = new Base64PropertyEncryption(); 

ExtendedXmlSerializer serializer = new ExtendedXmlSerializer(toolsFactory);

Then you can serialize object:

var obj = new Person {Name = "John", Password = "Ab238ds2"};
var xml = serializer.Serialize(obj);

Your xml will look like:

<?xml version="1.0" encoding="utf-8"?>
<Person type="ExtendedXmlSerialization.Samples.Encrypt.Person">
    <Name>John</Name>
    <Password>QWIyMzhkczI=</Password>
</Person>

ExtendedXmlSerializer has many other useful features:

  • Deserialization xml from standard XMLSerializer
  • Serialization class with property interface
  • Serialization circular reference and reference Id
  • Deserialization of old version of xml
  • Property encryption
  • Custom serializer

ExtendedXmlSerializer supports .net 4.5 and .net Core. You can integrate it with WebApi and AspCore.

1

I would store the hashed value of the password, using whatever method you like, eg MD5. At no point, in memory or on disk is the actual password stored. Then to authenticate, take the entered clear text password, hash it again, and check it against the stored the hash. That way the authentication still works, but at no point other than initial entry is the password cleartext available. During the initial entry, the password would be vulnerable to attack, as it has to be in memory between receiving the data and hashing it for comparison. As this time is so short, an attack is unlikely, but possible.

At this stage of the program, SecureString would be a good choice for storing the password before hashing. This provides automatic encryption of the password before hashing, and allows you to specify when the object is removed from memory.

If a 3rd party obtains the hash, it is useless to them , as it is non-reversible with the correct alogorithim. Also your program would hash it again if they tried to log in using the hash, failing the check. To be extra paranoid, you could always encrypt the entire file as well!

I am assuming that this is happening locally, or that the network connection is encrypted (eg, https). As per the comments above, never send a cleartext password over the network.

Venatu
  • 1,264
  • 1
  • 13
  • 24
  • 1
    The password has to be in memory at some point; otherwise, how will you calculate its hash? – phoog Apr 17 '12 at 21:04
  • True, but only momentarily. I should have been clearer. I meant that while your program was running, and the files deserialized into memory, there was not a cleartext password stored. When you check it, it will momentarily be available before hashing, but the short time window should be fine. Apologies for the confusion – Venatu Apr 17 '12 at 21:07
  • Also, never send a cleartext password over the network as others have mentioned. I am assuming its using an encrypted data stream, as you seem to be inputting an unencrypted password into your program – Venatu Apr 17 '12 at 21:08
  • No need to apologize; I wasn't confused (and I'm also not the OP!). Thank you for clarifying your answer. – phoog Apr 17 '12 at 21:12
  • Good point, thought you were! Should I edit it in, or leave it in the comments? – Venatu Apr 17 '12 at 21:15
  • I'd say - editing question is better than just comments - easier to read. Also consider mentioning SecureString while you are at it. – Alexei Levenkov Apr 17 '12 at 21:47