Once again, there’s nothing Media Center specific in this article, but this is functionality that the add-in requires nonetheless:

Storing Network Credentials Securely

A few instalments ago, we introduced the concept of storing network credentials as a way of improving the usability of a Media Center add-on; since the primary means of input is a remote control, we want to minimise text entry wherever possible. However, with storing credentials, we’re bound by responsibility to do so in a secure fashion. After all, this is sensitive information.

It was obvious, therefore, that some form of encryption should be used. However, it doesn’t matter how strong an encryption algorithm is if you don’t protect the key(s). We have to persist the keys in some way, otherwise there’d be no way of decrypting the credentials on the add-in’s next run. Software developed in .NET is particularly succeptible to dissassembling and decompiling, and it would be very easy to extract an encryption key if it were stored as a constant or string resource. So, this poses something of a challenge…

Enter, the Microsoft Cryptographic API. This API not only provides cryptographic algorithms (RSA, DES, etc) but also provides interoperability with the Windows key store. By using the CryptoAPI, the onice is no longer on your code to store and retrieve encryption keys; it’s all handled transparently and securely.

Design

StoredCredential class

The StoredCredential class holds all properties needed to access a network resource (domain, username and password), as well as a context (path). A determination is also made as to whether the password will be persisted; if not, the password will be held in memory for the life of the process only. The process of finding the correct credentials for any given path simply involves finding the instance with the deepest partially (or completely) matching path.

This type is designed to be stored in an ordinary XML application settings file. At run-time, the password can be decrypted. When serialised to XML, only the encrypted password is saved.

Implementation

The choice of an encryption algorithm is largely arbitrary for a project like this. I’ve chosen RSA because it’s well-supported and has a relatively long key length. To reduce overheads, the StoredCredential class uses a static variable containing an instance of RSACryptoServiceProvider to perform encryption and decryption for the session. In order to instruct the CryptoAPI to handle key storage for us, we merely have to provide a name for the key container:

CspParameters param = new CspParameters();
param.KeyContainerName = "NetworkCopy";
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(param);

We’re then free to start encrypting/decrypting passwords without having to worry about state:

private static byte[] Encrypt(string input) {
    return sRSA.Encrypt(Encoding.ASCII.GetBytes(input), false);
}

private static string Decrypt(byte[] input) {
    return Encoding.ASCII.GetString(sRSA.Decrypt(input, false));
}

As you can see, all we have to do is transform the data into a byte array (using ASCII encoding in this case – this is appropriate for English language systems).

EncryptedPassword is implemented as an auto-property, because it has no special get/set logic. The Password property, however, uses the following logic:

private string mTempPassword;

[XmlIgnore]
public string Password {
    get {
        if (!IncludesPassword)
            return mTempPassword;
        else
            return Decrypt(EncryptedPassword);
    }
    set {
        mTempPassword = value;               
        if (Properties.Settings.Default.StorePasswords) EncryptedPassword = Encrypt(value);
    }
}

The XmlIgnore attribute ensures that the clear-text password is never serialised. If we’re not persisting the password, we can just get and set the temporary password variable; otherwise, we get the password by decrypting and set the password by encrypting using the aforementioned methods. The StorePasswords application setting simply determines whether passwords are being persisted.

And that’s pretty much it! When serialised, a stored set of credentials appears in a similar manner to this:

<StoredCredential>
  <Path>\\Computer\Share</Path>
  <Domain>MyDomain</Domain>
  <Username>MyUser</Username>
  <EncryptedPassword>WIGTDn5W/U0Gj9SxJVBd35G+XjBwzAQrULfteOhQMkavN9UZCijrhj4pcyV2J5EiCwzIvD0YT3DEsLXq2gKdKlE7uKLpZ3XNzZdw8pklXTuyT3KCk8bywvKyAUWf+CU7YUxjywAE9ltKgEb6WGi9QanNafUzxUgtd0IsHFBsQ4c=</EncryptedPassword>
</StoredCredential>

That’s All, Folks!

Yes, you heard correctly – this is the last instalment of my series on Media Center add-in development! Where do we go from here? Well, I will soon be placing the complete project code and binaries on a dedicated section of this website. Until then, I hope this series has given you a few pointers as to how to get things done in the Media Center SDK. I look forward to getting back to covering a diverse and interesting range of topics 🙂

5 thoughts on “Developing with the Media Center SDK, Part 8

  1. vote

    I found mcnetworkcopy after my comment. I see the Z sample in the SDK use WCF server outside of Media Center and your plugin use WCF server in Media Center. Which way is better or does it not matter?

    Thanks
    Jimmy

    Reply
    • vote

      The advantage of running the WCF server inside Media Center is that it can access the API, and that the server auto-starts along with Media Center. In my opinion, this is the best approach.

      Reply
  2. vote

    Hi Bradley,

    I’m trying to build a plugin that must target x86 platform to work. It works fine on Windows 7 32bit but on Windows 7 64bit I get the following error.

    Exception Microsoft.MediaCenter.Hosting.Infrastructure.InvalidAddInException: Unable to load invalid add-in Test.BackgroundAddIn, Test,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=b5858f5e428c5a86 at MediaCenter.Extensibility.ExtensibilityPlugInEntryPointInfo.ExtensibilityPlugInLaunchInfo.LoadAddIn()

    InnerException System.IO.FileNotFoundException: Could not load file or assembly ‘Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b5858f5e428c5a86’ or one of its dependencies. The system cannot find the file specified.

    I am using the WIX setup template added to the project by Media Center SDK to install the plugin. Do you know how I can register a x86 dll to work with Media Center on Windows 7 64bit? Building the plugin with the AnyCPU option allows the plugin to load but it does not work correctly. Also I created a test console app and build as x86 and when I click the exe file it works on Windows 7 64bit.

    Thanks
    Jimmy

    Reply

Leave a reply to Bradley Smith Cancel reply

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> 

required