用 PowerShell 加密用 C# 解密
Powershell, SecureString, Secure String, ProtectData,
引言
使用 PowerShell 在本機進行加解密。過程中使用 SecureString 結構存儲存與交換;其基底是 ProtectedData 類別。SecureString 是用本機的秘密金鑰加解密,故換主機後會無效。
注意事項:加解密的編解碼是用 Unicode (UTF-16) 故中文字無效。另外 ProtectedData 類別只能在 windows 環境執行。
※注意:SecureString 加密的 key 是依據當時所在的 host 與 account。也就是換了機器或換了帳號就不會通。
加密
$plainText = 'YourDataBaseConnString'
$secureString = ConvertTo-SecureString -String $plainText -AsPlainText -Force
$encryptedString = ConvertFrom-SecureString -SecureString $secureString
$encryptedString
解密
$decryptedString = ConvertTo-SecureString -String $encryptedString
$Marshal = [System.Runtime.InteropServices.Marshal]
$Bstr = $Marshal::SecureStringToBSTR($decryptedString)
$decryptedText = $Marshal::PtrToStringAuto($Bstr)
$Marshal::ZeroFreeBSTR($Bstr)
$decryptedText
解密 with ASP.NET Core
安裝套件
Install-Package System.Security.Cryptography.ProtectedData
加解密
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Text;
/// <summary>
/// SecureString 的基底是 ProtectedData 類別。
/// 因為用 Uincode 進行編解碼故不適用中文字。
/// </summary>
internal class SecureStringService
{
public string Decrypt(string encryptedText)
{
// Remove all new-lines
encryptedText = encryptedText.Replace(Environment.NewLine, "");
// 解開 Protected SecureString
string decryptedText = DoUpprotectText(encryptedText);
return decryptedText;
}
public string Encrypt(string encryptedText)
{
string cypherText = DoProtectText(encryptedText);
return cypherText;
}
/// <summary>
/// 說明:SecureString 的基底是 ProtectedData 類別。
/// </summary>
static string DoUpprotectText(string cypherText)
{
// Convert the hex dump to byte array
int length = cypherText.Length / 2;
byte[] encryptedData = new byte[length];
for (int index = 0; index < length; ++index)
{
var chunk = cypherText.Substring(2 * index, 2);
encryptedData[index] = byte.Parse(chunk, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
byte[] data = ProtectedData.Unprotect(encryptedData, null, DataProtectionScope.LocalMachine);
string unprotectedText = Encoding.Unicode.GetString(data);
return unprotectedText;
}
/// <summary>
/// 說明:SecureString 的基底是 ProtectedData 類別。
/// </summary>
static string DoProtectText(string plainText)
{
byte[] plainBlob = Encoding.Unicode.GetBytes(plainText);
byte[] cypherBlob = ProtectedData.Protect(plainBlob, null, DataProtectionScope.LocalMachine);
string cypherText = Convert.ToHexString(cypherBlob);
return cypherText;
}
}
參考文章
完整原始碼
補充 on 2024-10-04
明文加密再 AES128 加密後才 base64 編碼。
# $plainText => $secureString => (AES128) => $base64EncryptedString
$plainText = 'YourDataBaseConnString'
$secureString = ConvertTo-SecureString -String $plainText -AsPlainText -Force
$base64EncryptedString = ConvertFrom-SecureString -SecureString $secureString -Key (1..16)
$base64EncryptedString
# $base64EncryptedString => (deAES128) => $secureString => $plainText
$decryptedSecureString = ConvertTo-SecureString -String $base64EncryptedString -Key (1..16)
$decryptedText = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($decryptedSecureString))
$decryptedText
明文加密後用 base64 編碼。
# $plainText => $secureString => (HexString) => $base64String
$plainText = 'YourDataBaseConnString'
$secureString = ConvertTo-SecureString -String $plainText -AsPlainText -Force
$encryptedString = ConvertFrom-SecureString -SecureString $secureString
$bytes = for ($i = 0; $i -lt $encryptedString.Length; $i += 2) {
[Convert]::ToByte($encryptedString.Substring($i, 2), 16)
}
$base64String = [Convert]::ToBase64String($bytes)
$base64String
# $base64String => $hexString => (SecureString) => $decryptedText
$bytes = [Convert]::FromBase64String($base64String)
$hexString = -join ($bytes | ForEach-Object { $_.ToString("x2") })
$decryptedString = ConvertTo-SecureString -String $hexString
$Marshal = [System.Runtime.InteropServices.Marshal]
$Bstr = $Marshal::SecureStringToBSTR($decryptedString)
$decryptedText = $Marshal::PtrToStringAuto($Bstr)
$Marshal::ZeroFreeBSTR($Bstr)
$decryptedText
Last updated