SecretStore Module

SecretManagement module is a Powershell module intended to make it easier to store and retrieve secrets.

The secrets are stored in SecretManagement extension vaults. An extension vault is a PowerShell module that has been registered to SecretManagement, and exports five module functions required by SecretManagement. An extension vault can store secrets locally or remotely. Extension vaults are registered to the current logged in user context, and will be available only to that user (unless also registered to other users).

SecretManagement Module on Github

This is a really cool project and an awesome tool that Microsoft created. I see it get referred to a lot in different Powershell communities as a recommended solution for dealing with secrets in automation. I haven’t had any occasion to use it myself but I had often thought about writing a Powershell based password manager (until SecretManagement was released).

Relevant to my interests then if you want to just store secrets locally on your computer for use in scripts you’ll want to look at the SecretStore module.
SecretStore Module on Github

It stores secrets locally on file for the current user account context, and uses .NET crypto APIs to encrypt file contents. Secrets remain encrypted in-memory, and are only decrypted when retrieved and passed to the user. This module works over all supported PowerShell platforms on Windows, Linux, and macOS.

Since theirs is cross platform and mine isn’t it’s probably different .NET in the backend, but the class is likely the same. For reference, in .NET it’s referred to by its RFC “Rfc2898DeriveBytes”. Since this is all publicly available on Github I thought I would search through the relevant CS code and try to understand how they did it differently. Here is the file I found where I believe PBKDF2 is happening:
Utils.cs

There’s two sections that drew my attention. The first:

private static byte[] DeriveKeyFromPassword(
    byte[] passwordData,
    int keyLength)
{
    try
    {
        using (var derivedBytes = new Rfc2898DeriveBytes(
            password: passwordData, 
            salt: salt, 
            iterations: 1000))
        {
            return derivedBytes.GetBytes(keyLength);
        }
    }
    finally
    {
        ZeroOutData(passwordData);
    }
}

And the second:

private static AesKey DeriveKeyFromKeyAndPasswordOrUser(
        SecureString passWord,
        AesKey key,
        bool useOrigUserNameCasing = false)
    {            
        var passWordData = GetPasswordOrUserData(passWord, useOrigUserNameCasing);
        try
        {
            byte[] newKey;
            using (var derivedBytes = new Rfc2898DeriveBytes(
                password: passWordData, 
                salt: key.Key, 
                iterations: 1000))
            {
                newKey = derivedBytes.GetBytes(key.Key.Length);
            }

            byte[] newIV;
            using (var derivedBytes = new Rfc2898DeriveBytes(
                password: passWordData,
                salt: key.IV,
                iterations: 1000))
            {
                newIV = derivedBytes.GetBytes(key.IV.Length);
            }

            return new AesKey(
                key: newKey,
                iv: newIV);
        }
        finally
        {
            ZeroOutData(passWordData);
        }
    }

Backstory

Remember how quickly everyone bailed on LastPass after their breach? It was revealed that they were using PBKDF2 with SHA256 and only 100,001 iterations (Article from The Verge). In some cases, if the account was older, it was even worse than that at only 5000 iterations. For comparison, OWASP has been recommending 310,000 iterations (SHA256) since at least 2021 and as of today recommends 600,000.

Essentially, LastPass left people’s vaults more vulnerable to brute force attack (after the breach) because it wasn’t computationally costly to iterate through millions of attempted master passwords.

The Problem

Having spent time in Powershell leveraging the Rfc2898DeriveBytes class (PBKDF2) quite a bit with my ProtectStrings module I spent a bit of time reading up on the available hash algorithms, recommended salt lengths and iteration counts and made sure to pick values that I thought would make it not worth while to try to brute force any keys generated using my code.

I was trying to find a deep dive article anywhere online that got in to how the SecretStore module functioned at a cryptographic level but couldn’t find anything. I’m still not 100% sure at what point these implementations of PBKDF2 are being leveraged but from what I can tell the way they’re being called leverages the default constructors.
Reading the actual RFC it appears that the default constructor (from 2000) leverages SHA1 and 1000 iterations.

Now, it would certainly not be an easy task to brute force this, but this is production code being advertised for essentially the same purpose as LastPass: protect your secrets. In this module’s case the data would be stored locally on your computer, as compared to someone else’s server, but the fact remains that this code is leveraging 23 year old constructors that even Microsoft says are deprecated.
PBKDF2Constructors
PBKDF2

Seems like poor form for Microsoft to call out all these deprecated constructors as obsolete and insecure and then go ahead and use them in their Powershell module specifically made for storing secrets.

2024

Powershell Summit 2024

less than 1 minute read

I got the opportunity this week to attend the 2024 Powershell Summit in Bellevue Washington. If you have an opportunity to go to this, whether you’re brand ...

Back to top ↑

2023

SecretStore Module

3 minute read

SecretManagement module is a Powershell module intended to make it easier to store and retrieve secrets. The secrets are stored in SecretManagement extens...

Reset Expiration Clock

10 minute read

With more and more people working remotely there’s been a huge uptick in VPN usage. A lot of organizations have had to completely rethink some of their prev...

Status Update

1 minute read

Hi all. Just wanted to provide a brief status update. It’s been a while since my last post and while I have been busy, and making frequent use of Powershel...

Back to top ↑

2022

Get-GeoLocation

13 minute read

Getting GPS Coordinates From A Windows Machine Since 2020 a lot of organizations have ended up with a more distributed workforce than they previously had. T...

Quick Tip on ParameterSetNames

3 minute read

I was writing a new function today. Oddly enough I was actually re-writing a function today and hadn’t realized it. Let me explain. Story Time About a hal...

ProtectStrings. A Module Story

20 minute read

I’ve had an itch lately to do something with AES encryption in Powershell. I’ve tossed around the idea of building a password manager in Powershell, but I g...

Powershell all of the things. And more logging

9 minute read

“If all you have is a hammer, everything looks like a nail” - Abraham Maslow. I use a variation of this quote a lot, and I typically use it in jest, but it’s...

Back to top ↑

2021

Get-WindowsFirewallBlocks

6 minute read

Introduction I’ve had some exposure to Microsoft Defender here and there, but I was in a class with Microsoft recently where they were going over some more f...

Logging in Powershell scripts; Continued

22 minute read

In my previous post I explained a bit about some of my justifications for logging in Powershell. My interest in logging has continued since then and I spent...

Logging in Powershell scripts

7 minute read

Everyone has a different use for Powershell. Some people use it for daily administrative tasks at work. Some people are hard at work developing Powershell m...

Parsing log files with Powershell

7 minute read

Early on when I first started using Powershell I was dealing with some firewall logs from a perimeter firewall. They were exported from a SIEM in CSV format...

Get-Connections; netstat for Powershell

5 minute read

One of the tools I feel like I’ve been using for years is Netstat. It exists in both Linux and Windows (with some differences) and has similar syntax. It’s ...

Secure Credentials in Powershell

7 minute read

A coworker from a neighboring department had an interesting request one day. They wanted a scheduled task to run on a server. Through whatever mechanism the ...

Get-ADPasswordInfo

4 minute read

When I first started getting in to Powershell I was working in an IT Security position and was sifting through a lot of “noise” in the SIEM alerts. The main...

Jekyll & Minimal Mistakes; Done

less than 1 minute read

“Hello World” and all that. What started as a small conversation turned in to an Idea that I couldn’t shake: I wanted a blog. But I didn’t want a WordPress...

Back to top ↑