Stuart Mathews
  • Home

    Latest

    • Functional XML (Game Development) 19-02-2023
    • Midnight in Paris (Blog) 04-01-2023
    • Christmas Run (Running) 26-12-2022
    • So far, it works (Game Development) 25-12-2022
    • Traveling Europe (Blog) 01-11-2022
    • Applying and Evaluating Pattern-Oriented Designs In Improving Code Quality In Complex Software (Code) 01-10-2022
    • Knoydart Peninsula, Scotland (Running) 01-10-2022
    • CppGameLib (Game Development) 12-09-2022
    • Thoughts on Multiplayer Game Co-operation and Distributed Computing (Game Development) 04-07-2022
    • The fading importance of ego and the utility of the checklist (Blog) 18-04-2022

    Most Read This Year

    • Thoughts on Multiplayer Game Co-operation and Distributed Computing (Game Development)
    • The fading importance of ego and the utility of the checklist (Blog)
    • Differential Calculus (Blog)
    • Traveling Europe (Blog)
    • Knoydart Peninsula, Scotland (Running)
    • CppGameLib (Game Development)
    • Applying and Evaluating Pattern-Oriented Designs In Improving Code Quality In Complex Software (Code)
    • So far, it works (Game Development)
    • Christmas Run (Running)
    • Midnight in Paris (Blog)

    Recently Featured

    • Functional XML (Game Development)
    • So far, it works (Game Development)
    • Thoughts on Multiplayer Game Co-operation and Distributed Computing (Game Development)
    • A software engineering process for delivering software (Code)
    • Encrypting strings at rest (Code)
    • ISO27001, Machine-Learning and Game dev (Blog)
    • Implementing a Vignette (Code)
    • Fixing the thunder in my feet (Running)
    • Sufficiently Complex (Blog)
    • Try Monad, Progress and Lockdown Rules (Blog)
    • Downloads
  • Blog

    Recent in Blog

    • Midnight in Paris 04-01-2023
    • Traveling Europe 01-11-2022
    • The fading importance of ego and the utility of the checklist 18-04-2022
    • Differential Calculus 14-04-2022
    • Fading importance and the utility of lists 29-12-2021
    • Abstractions and Patterns 11-10-2021
    • Mind Maps 02-10-2021
    • ISO27001, Machine-Learning and Game dev 23-04-2021
    • Sufficiently Complex 02-12-2020
    • Deadlocks and databases 19-10-2020

    Most Read In Blog This Year

    • The fading importance of ego and the utility of the checklist (Blog)
    • Differential Calculus (Blog)
    • Traveling Europe (Blog)
    • Midnight in Paris (Blog)

    Featured In Blog

    • ISO27001, Machine-Learning and Game dev (Blog)
    • Sufficiently Complex (Blog)
    • Try Monad, Progress and Lockdown Rules (Blog)
    • Rails, Euclid and Generating Mazes (Blog)
    • Set Theory, Ruby and Upgrades (Blog)
    • Time shifting, CS algorithms and Game Architecture (Blog)
    • The Fourier transform, math, malware and decoupling (Blog)
    • Encryption and network protocols (Blog)
    • Mazer Game Design and Network Security (Blog)
    • Changing object states and 3D transformations (Blog)
  • Code

    Recent in Code

    • Applying and Evaluating Pattern-Oriented Designs In Improving Code Quality In Complex Software 01-10-2022
    • Polynomial Calculator 16-03-2022
    • A software engineering process for delivering software 27-02-2022
    • Counting and Permutations 08-02-2022
    • Encrypting strings at rest 10-12-2021
    • Implementing a Vignette 26-01-2021
    • Functional programming paradigms and techniques 19-07-2020
    • Ruby RSpec let and let! diffirences 08-07-2020
    • Convolution, Running and Finite State Machines 08-03-2020
    • LanguageExt tutorial, games and timing 08-08-2019

    Most Read In Code This Year

    • Thoughts on Multiplayer Game Co-operation and Distributed Computing (Game Development)
    • CppGameLib (Game Development)
    • Applying and Evaluating Pattern-Oriented Designs In Improving Code Quality In Complex Software (Code)
    • So far, it works (Game Development)
    • Functional XML (Game Development)

    Featured In Code

    • Functional XML (Game Development)
    • So far, it works (Game Development)
    • Thoughts on Multiplayer Game Co-operation and Distributed Computing (Game Development)
    • A software engineering process for delivering software (Code)
    • Encrypting strings at rest (Code)
    • Implementing a Vignette (Code)
    • Protocols, Packets and Prototypes (Game Development)
    • Animated aliens and alternatives algorithms (Game Development)
    • Retro sounds, Event Manager and some running (Game Development)
    • Basic key frame animations, implicit casts and some other aspect (Game Development)
  • Running

    Recent in Running

    • Christmas Run 26-12-2022
    • Knoydart Peninsula, Scotland 01-10-2022
    • Winter running 09-12-2021
    • Itchy legs and tracksuit bottoms 03-09-2021
    • Heart rate inconsistency 26-04-2021
    • Chequered Leaves and the Yellow Runner 01-01-2021
    • Fixing the thunder in my feet 04-12-2020
    • Faster than usual 17-06-2020
    • The uncomfortable steady-state 03-06-2020
    • Hot weather running 31-05-2020

    Most Read In Running This Year

    • Knoydart Peninsula, Scotland (Running)
    • Christmas Run (Running)

    Featured in Running

    • Smashrun
    • Strava profile
  • Gaming

    Recent in Gaming

    • Functional XML 19-02-2023
    • So far, it works 25-12-2022
    • CppGameLib 12-09-2022
    • Thoughts on Multiplayer Game Co-operation and Distributed Computing 04-07-2022
    • Applying and Evaluating Functional Programming Paradigms and Techniques in Developing Games 19-02-2022
    • Christmas Period Tinkering 29-12-2021
    • Mazer Game Architecture Report 22-11-2020
    • Ruby Mazer 26-05-2020
    • Protocols, Packets and Prototypes 29-11-2019
    • Pleasure And the Execution of Thoughfulness 29-09-2019

    Most Read In Gaming This Year

    • Thoughts on Multiplayer Game Co-operation and Distributed Computing (Game Development)
    • CppGameLib (Game Development)
    • So far, it works (Game Development)
    • Functional XML (Game Development)

    Featured in Gaming

    • Game loop
    • Featured
  • Portfolio

    Featured in Portfolio

    • App-V (Citrix)
    • Citrix Fast Connect SDK
    • AppDNA
    • Cloud Copy and Paste
    • Software Audit Pro
    • Investment Manager
    • Meal tracker
    • Cross platform broker
  • About

Encrypting strings at rest

Details
Stuart Mathews
Code
10 December 2021
Created: 10 December 2021
Last Updated: 27 December 2021
Hits: 1004

Since, ISO27001, Machine-Learning and Game dev, I recently wanted to store some sensitive data (private key) in a string in C# and keep it in memory during the duration of an operation.

Due to the design of some 3rd party APIs that required a string representation of the private key, I decided on encrypting the string and only unencrypting it when I want to use it. In all other instances, the encrypted string would be copied or passed around, while the unencrypted string would not be.

I did some reading about System.Security.Cryptography's ProtectedMemory function, which allows you to encrypt a block of bytes of which needs to be a multiple of 16 bytes. The interesting thing about doing this is being able to encode the length of your sensitive string within the actual encrypted 16n byte block so that when you unencrypt that block, you can retrieve from it the length of the original string, and recover the original string. This is kind of what you do when you encode the length of a packet that you send down the network.

The implementation of an object that can encrypt a string, store it internally and decrypt upon request, is a ProtectedString:

using System;
using System.Security.Cryptography;
using System.Text;

namespace X.Y.Z
{
    /// <summary>
    /// Store string encrypted at rest.
    /// </summary>
    /// <remarks>You can copy this object freely</remarks>
    /// <remarks>Portable alternative to SecureString, using DPAPI</remarks>
    /// <remarks>Note SecureString is not recommended for new development</remarks>
    /// <remarks>https://docs.microsoft.com/en-us/dotnet/api/system.security.securestring</remarks>
    public class ProtectedString : IProtectedString
    {
       /// <summary>
       /// Secret area that is encrypted/decrypted
       /// </summary>
       private byte[] _secretData;

       private readonly object _lock = new();

       private bool IsProtected { get; set; }

       /// <summary>
       /// DPAPI access control for securing data
       /// </summary>
       private readonly MemoryProtectionScope _scope;

       /// <summary>
       /// Creates a ProtectedString
       /// </summary>
       /// <param name="sensitiveString">Sensitive string</param>
       /// <param name="scope">Scope of the protection</param>
       public ProtectedString(string sensitiveString = null,
                              MemoryProtectionScope scope = MemoryProtectionScope.SameProcess)
        {
            _scope = scope;

            // Store secret if provided and valid
            if(InputValid(sensitiveString))
                Set(sensitiveString);
        }

       private static bool InputValid(string sensitiveString)
       {
           return sensitiveString != null;
       }

       /// <inheritdoc />
        public void Set(string sensitiveString)
        {
            try
            {
                lock (_lock)
                {
                    if(!InputValid(sensitiveString))
                        throw new InvalidInputException();

                    // The secretData length should be a multiple of 16 bytes
                    
                    var secretDataLength = RoundUp(
                        sizeof(int) + // We will store the length of the
                                      // sensitiveString as the first sizeof(int) bytes in secretData
                        sensitiveString.Length, 16);

                    // Allocate array, all values set to \0 by .Net
                    _secretData = new byte[secretDataLength];

                    // Copy the length of the sensitiveString into the secretData
                    // first, starting at the first byte
                    BitConverter.GetBytes(sensitiveString.Length).CopyTo(_secretData, 0);

                    // Copy the sensitiveString itself after the bytes the above bytes
                    Encoding.ASCII.GetBytes(sensitiveString).CopyTo(_secretData, sizeof(int));

                    // Encrypt our encoded secretData using DPAPI
                    ProtectedMemory.Protect(_secretData, _scope);

                    IsProtected = true;
                }
            }
            catch (Exception e)
            {
                IsProtected = false;

                if (e is ProtectedStringException)
                    throw;

                throw new Exception("Unexpected error while storing data from protected memory");
            }
        }

        /// <inheritdoc />
        public string Get()
        {
            try
            {
                lock (_lock)
                {
                    if (!IsProtected)
                        throw new NotProtectedException();

                    // Decrypt secretData
                    ProtectedMemory.Unprotect(_secretData, _scope);

                    // Determine how long our sensitiveString was by reading the integer at byte 0
                    var secretLength = BitConverter.ToInt32(_secretData, 0);

                    // Read that many bytes to recover the original sensitiveString
                    var sensitiveString = Encoding.ASCII.GetString(_secretData, sizeof(int), secretLength);

                    // Re-protect secretData after retrieval
                    Set(sensitiveString);

                    // Return a reference to unprotected string.
                    return sensitiveString;
                }
            }
            catch (Exception e)
            {
                if (e is ProtectedStringException)
                    throw;

                throw new Exception("Unexpected error while retrieving data from protected memory");
            }
        }

        private static int RoundUp(int numToRound, int multiple)
        {
            if (multiple == 0)
                return numToRound;

            int remainder = numToRound % multiple;
            if (remainder == 0)
                return numToRound;

            return numToRound + multiple - remainder;
        }
    }
}

The question is if this is really useful at all from a security standpoint?

As soon as you unencrypt the contents, you get an unencrypted string back, and that string lives in memory and in theory, can be looked at by memory scanning. Also when that memory is freed (provided you don't have a reference to it), the garbage collector will free it but won't zero it out (securely clear it), so it'll be somewhere in memory, ...unencrypted.

Ultimately I never used this because of the reasons mentioned above, but it's still interesting...

Now, despite this, the above is still useful in some ways, provided you:

  • a) only copy or store the protected string or pass it between functions.
  • b) don't store the unencrypted string anywhere.

The other advantage is that the window of exposure of the unencrypted string is small (but it'll still get garbage collected), as you only unencrypt the ProtectedString when you want to use it, otherwise the secret is encrypted at rest.

Still, it doesn't help with the original problem of having unencrypted string copies lingering in system memory somewhere....

 

Encryption C# Software Engineering Design
Write comment (0 Comments)

More Articles ...

  1. ISO27001, Machine-Learning and Game dev
  2. Implementing a Vignette
  3. Fixing the thunder in my feet
  4. Sufficiently Complex
  5. Try Monad, Progress and Lockdown Rules
  6. Rails, Euclid and Generating Mazes
  7. Set Theory, Ruby and Upgrades
  8. Time shifting, CS algorithms and Game Architecture
  9. The Fourier transform, math, malware and decoupling
  10. Encryption and network protocols
Page 5 of 65
  • Start
  • Prev
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • Next
  • End

Topics

Running (36) Programming (34) Game development (28) Random (22) Impressions (19) holiday (19) Math (18) C++ (16) Wierd (12) Gym (11) Traveling (10) Functional programming (10) Software Engineering (10) TCP/IP (9) Networking and security (7) Investing (6) Linux kernel (6) DirectX (6) XML (5) Ruby (5)

Twitter

Tweets by @stumathews

Latest

  • Functional XML (Game Development) 19-02-2023
  • Midnight in Paris (Blog) 04-01-2023
  • Christmas Run (Running) 26-12-2022
  • So far, it works (Game Development) 25-12-2022
  • Traveling Europe (Blog) 01-11-2022
  • Applying and Evaluating Pattern-Oriented Designs In Improving Code Quality In Complex Software (Code) 01-10-2022
  • Knoydart Peninsula, Scotland (Running) 01-10-2022
  • CppGameLib (Game Development) 12-09-2022
  • Thoughts on Multiplayer Game Co-operation and Distributed Computing (Game Development) 04-07-2022
  • The fading importance of ego and the utility of the checklist (Blog) 18-04-2022

Recent

  • Functional XML
  • Midnight in Paris
  • Christmas Run
  • So far, it works
  • Current Reading

Share This

Follow Me

Login

  • Login
  • Webmail
  • Admin
  • Downloads
Bootstrap is a front-end framework of Twitter, Inc. Code licensed under MIT License. Font Awesome font licensed under SIL OFL 1.1.