This blog is about how you can use the .Net cryptography model to encrypt and decrypt sensitive information such as passwords with PowerShell. It is specifically for the encryption in transit and encryption at rest scenarios, where, for example, you may be sending data to a backend service and securely storing it in that service. If you just want to secure data on a local machine, the ConvertTo-SecureString and ConvertFrom-SecureString cmdlets may suffice.
Broadly there are two types of encryption, symmetric and asymmetric encryption. Symmetric encryption uses the same key to encrypt and decrypt, whereas asymmetric uses a public/private key pair. Which you use really depends on your requirements – I use both in different scenarios.
At the end of the blog you’ll find the functions and full code for the following examples.
Symmetric encryption uses the same both to encrypt and decrypt, which means you must keep this key secure. This type of encryption can be more useful where the encryption key is not publicly exposed. For example, I use this kind of encryption to encrypt sensitive data for rest and storage within Azure services. The encryption is done within Azure and so the key is never exposed or accessible outside our Azure environment.
I am using AES to create a 256-bit key using the CBC cipher mode, which are the current .Net defaults. We first need to create a key and an initialization vector (IV), which helps to hide observable patterns in the resulting ciphertext. Both the key and the IV and needed to both encrypt and decrypt the text.
The following code creates the key and the IV as base64 strings.
$AES = [System.Security.Cryptography.Aes]::Create() $Key = [System.Convert]::ToBase64String($aes.Key) $IV = [System.Convert]::ToBase64String($aes.IV)
If you intend to re-use the same key to encrypt other data, the recommendation is to generate a new IV each time:
$AES.GenerateIV() $IV = [System.Convert]::ToBase64String($aes.IV)
To encrypt a string, simply do:
$TextToEncrypt = "SuperSenstiveData" $EncryptedText = Encrypt-Data -Data $TextToEncrypt -Key $Key -IVector $IV
This will return the encrypted text as a base64 string.
To decrypt, pass the same key and IV you used to encrypt the text:
$DecryptedText = Decrypt-Data -Data $EncryptedText -Key $Key -IVector $IV
Asymmetric encryption uses a public and private key pair. The public key is not sensitive and is ok to store in a script etc as the key can only encrypt but not decrypt the data. The private key, however, must be secured and should not be publicly accessible. This type of encryption is useful for securing sensitive data in transit. For example, I may gather some secret from a client workstation and send this to a backend service in a web request. The client has the public key and encrypts the data before sending, but only the backend service which processes the data has the private key for decryption.
I am using RSACng with a key size of 3072 and a padding type of OaepSHA384 with UTF8 encoding. There are a few things to note with this:
- RSACng uses the Windows CNG libraries and therefore will only work on a Windows OS
- .Net framework 4.6 minimum is required
- Only short strings can be encrypted, depending on the padding mode used
- For example, using OeapSHA384 padding and UTF8 encoding a maximum of 286 bytes can be encrypted. This will typically equate to 286 characters of text
- Using the same padding with Unicode encoding can also encode a maximum or 286 bytes, but this will be only 143 characters because each character is 2 bytes wide
The following code creates the public and private keys as base64 strings.
$RSACNG = [System.Security.Cryptography.RSACng]::new(3072) $ExportedPublicKey = $RSACNG.key.Export([System.Security.Cryptography.CngKeyBlobFormat]::GenericPublicBlob) $ExportedPrivateKey = $RSACNG.key.Export([System.Security.Cryptography.CngKeyBlobFormat]::GenericPrivateBlob) $PublicKey = [System.Convert]::ToBase64String($ExportedPublicKey) $PrivateKey = [System.Convert]::ToBase64String($ExportedPrivateKey)
To encrypt, use the public key:
$TextToEncrypt = "SuperSenstiveData" $EncryptedText = Encrypt-Data -Data $TextToEncrypt -PublicKey $PublicKey
And use the private key to decrypt:
$DecryptedText = Decrypt-Data -Data $EncryptedText -PrivateKey $PrivateKey