April 29th, 2024
heart10 reactions

Encrypting secrets locally

If you are involved in support or development, often you need to use secrets, passwords, orsubscription keys in PowerShell scripts. These need to be kept secure and separate from your scriptsbut you also need access to them ALL THE TIME.

So instead of hand entering them every time they should be stored in a key store of some sort thatyou can access programmatically. Often off the shelf keystores are not available in your environmentor are clumsy to access with PowerShell. A simple way to have easy access to these secrets withPowerShell would be helpful.

You could simply have them in plain text, on your machine only, making it relatively secure.However, there are many risks with this approach, so adding some additional security is an excellentidea.

The .NET classes sitting behind PowerShell provide some simple ways to do this. This blog will gothrough

  • Basic encryption / decryption
  • Using it day-to-day
  • Your own form-based key store

Basic encryption / decryption

Theprotect andunprotect methods available as part of the cryptography classes areeasy to use. However they use Byte arrays that we can simplify by wrapping their use in a String.

The following examples can be found at theMachineAndUserEncryption.ps1 module in myps-community-blog repository on GitHub.

Encryption

Function Protect-WithUserKey {    param(        [Parameter(Mandatory=$true)]        [string]$secret    )    Add-Type -AssemblyName System.Security    $bytes = [System.Text.Encoding]::Unicode.GetBytes($secret)    $SecureStr = [Security.Cryptography.ProtectedData]::Protect(        $bytes,     # contains data to encrypt        $null,      # optional data to increase entropy        [Security.Cryptography.DataProtectionScope]::CurrentUser # scope of the encryption    )    $SecureStrBase64 = [System.Convert]::ToBase64String($SecureStr)    return $SecureStrBase64}

Just going through the lines we can see

  1. PowerShell needs to know about the .NET classes (I have tested under version 5 & 7 of PowerShell)
  2. We need to convert our string into a Byte array
  3. Use the .NET class to encrypt
  4. Convert the encrypted Byte array to a string for easy storage and retrieval
  5. Return that string

Decryption

Function Unprotect-WithUserKey {    param (        [Parameter(Mandatory=$true)]        [string]$enc_secret    )    Add-Type -AssemblyName System.Security    $SecureStr = [System.Convert]::FromBase64String($enc_secret)    $bytes = [Security.Cryptography.ProtectedData]::Unprotect(        $SecureStr,     # bytes to decrypt        $null,          # optional entropy data        [Security.Cryptography.DataProtectionScope]::CurrentUser) # scope of the decryption    $secret = [System.Text.Encoding]::Unicode.GetString($bytes)    return $secret}

Steps are identical for the decryption, using slightly different methods

  1. PowerShell needs to know about the .NET classes
  2. We need to convert our string into a Byte array
  3. Use the .NET class to decrypt
  4. Convert the encrypted Byte array to a string
  5. Return that string

Using it day-to-day

This is really useful if you are doing repetitive tasks that need these values. Often in a supportrole, investigations using API’s can speed up the process of analysis, and also provide you with aquick way to do fixes that don’t require heavy use of a GUI based environment.

Assigning a key to a secret value, and storing that in a hash table format is the simplest way tohave access to these values AND keep them stored locally with a degree of security. Your code canthen dynamically look up these values, and if other support people store the same key locally thesame way (often with different values, think of an API password and or username pair) then yourscript can work for everyone.

Again,MachineAndUserEncryption.ps1 in my repository on my GitHub has functions for persisting andusing this information. For compatibility with version 5 & 7 you also need the functionConvertToHashtableV5.

I would also recommend usingProtect-WithMachineAndUserKey andUnprotect-WithMachineAndUserKeywhen implementing locally, they add another layer of protection.

Your own form-based key store

If you have followed my other 2 blogs about ascalable environment andsimple form development then using the resources from these we can easily create our own formto manage our secrets. In fact, if you have downloaded and installed the modules for either of thoseblogs (they are the same, and this blog references the same as well), you have it ready to go.

Once you have your environment set up, simply run the cmdlet:

New-EncryptKeyForm

and if all is set up correctly, you should see

key-value-secret-store

Conclusion

Balancing the pragmatic ease of use and security concerns around secrets you may need to use all dayevery day can be a fine balancing act. Using some simple methods, we can strike that balance andhopefully be securely productive.

Lets secure some stuff!

7 comments

Discussion is closed.Login to edit/delete existing comments.

Stay informed

Get notified when new posts are published.
Follow this blog
facebook