1

I've written a C# piece that encrypts/decrypts a string using RtlEncryptMemory/RtlDecryptMemory. This string is then saved in a config file, it all works well but the problem is that once I logoff/logon, I can no longer decrypt the string. I am using the RTL_ENCRYPT_OPTION_SAME_LOGON option which means the internal mechanism uses something from the Windows session in order to perform the decryption. I am looking for a solution that works in the same manner but is tied to the network user (or token, etc...). Is Windows providing something already?

My goal is to be able to decrypt the string from anywhere as long as the process is running under the same user (network credentials). I also do not want to have the user type in a password or use an internal value as that could be compromised. Ideally it would be just like the RTL functions but provide an RTL_ENCRYPT_OPTION_SAME_USER option.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Teknix1
  • 23
  • 1
  • 1
  • 3
  • 4
    You should not be using RtlEncryptMemory if you want to store the string, it is meant to only keep strings secure inside the running applications memory, it therefore can be stored/serialized and decrypted. – Kevin Feb 28 '20 at 20:01
  • 1
    Have a look at this thread, I think the DPAPI would meet your needs. https://stackoverflow.com/questions/34194223/dpapi-password-encryption-in-c-sharp-and-saving-into-database-then-decrypting-it – Kevin Feb 28 '20 at 20:20
  • Yes, I totally understand RtlEncryptMemory isn't the way to go. It looks like Kevin's suggestion might be the way to go, I will have to prototype this. Thanks for the replies. – Teknix1 Mar 02 '20 at 16:05
  • I just finished testing out the DPAPI suggestion by Kevin, this is the most inline with my requirements. Unfortunately the encrypted data is still tied to the machine key but it is better than my original implementation using RTL. Kevin if you don't mind posting your suggestion as a solution I could mark it as accepted. Thanks! – Teknix1 Mar 02 '20 at 19:12
  • @Teknex1 - Done! Glad it helped. – Kevin Mar 02 '20 at 22:40

3 Answers3

3

You want to use the DataProtection API

Here is a simple implementation that adds Encrypt and Decrypt string extensions...

public static class StringExtensions
{
    public static string Encrypt(this string s)
    {
        if (String.IsNullOrEmpty(s))
        {
            return s;
        }
        else
        {
            var encoding = new UTF8Encoding();
            byte[] plain = encoding.GetBytes(s);
            byte[] secret = ProtectedData.Protect(plain, null, DataProtectionScope.CurrentUser);
            return Convert.ToBase64String(secret);
        }
    }
    public static string Decrypt(this string s)
    {
        if (String.IsNullOrEmpty(s))
        {
            return s;
        }
        else
        {
            byte[] secret = Convert.FromBase64String(s);
            byte[] plain = ProtectedData.Unprotect(secret, null, DataProtectionScope.CurrentUser);
            var encoding = new UTF8Encoding();
            return encoding.GetString(plain);
        }
    }
}

Here is an example...

    class Program
{
    static void Main(string[] args)
    {
        string password = "Monkey123";
        string encrypted = password.Encrypt();
        Console.WriteLine($"Encrypted password = '{encrypted}'");
        string decrypted = encrypted.Decrypt();
        Console.WriteLine($"Decrypted password = '{decrypted}'");
    }
}

Which produces this output...

Encrypted password = 'AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAA/6wDgM21DkStrNJQ35QDiwAAAAACAAAAAAAQZgAAAAEAACAAAAAPr3/aqafbt/RRoPVe75b+PFBhE6h9MLcQ2Ivsd3adOwAAAAAOgAAAAAIAACAAAABYxqEdzotL+7qXpWnbbpPRkfWZF6oh/meFsXzFtLPnrBAAAAB59VGbboP4Tye1N3dB7E3jQAAAAMQn8cAlnTDe1mwDEJriADizdT2Qr0DtPgpMje+rbjdkVpL+cKiEQs4om4i1hlLPgPn5MG5oVWFFnxU0d4c9TFg='
Decrypted password = 'Monkey123'

Notes:

  1. Only the currently logged in user can decrypt the data encrypted with this code. This works across the network as long as the current user has a roaming profile.
  2. Alternatively the scope can be local machine in which case only users logged in to the same machine can decrypt the data.
  3. This is .NET Core 3.1 code and works only on Windows machines

Using statements...

using System;
using System.Security.Cryptography;
using System.Text;
AQuirky
  • 4,691
  • 2
  • 32
  • 51
1

You should not be using RtlEncryptMemory if you want to store the string, it is meant to only keep strings secure inside the running applications memory, it therefore can be stored/serialized and decrypted.

Have a look at DPAPI password encryption I think it should meet your needs.

Kevin
  • 2,566
  • 1
  • 11
  • 12
0

enter image description here

I have a Nuget package you might like:

DataJuggler.Net.Cryptography .Net Framework

DataJuggler.Core.Cryptography Dot Net Core

Pretty simple to work with, here is a live demo:

https://blazorcrypto.datajuggler.com/

Source code and video link is available above also.

Usage:

Encryption:

// get the encryptedText
encryptedResult = CryptographyHelper.EncryptString(textToEncrypt, keyCode);

Decryption:

// get thedecryptedText
decryptedResult = CryptographyHelper.DecryptString(textToDecrypt, keyCode);

It also includes password hashing.

Let me know if you think it is worth the price of free.

  • Thanks for the suggestion, looks like a great package, unfortunately it uses a key code or passphrase which I'd like to avoid if possible. – Teknix1 Mar 02 '20 at 16:08