用 PowerShell 加密用 C# 解密

Powershell, SecureString, Secure String, ProtectData,

引言

使用 PowerShell 在本機進行加解密。過程中使用 SecureString 結構存儲存與交換;其基底是 ProtectedData 類別。SecureString 是用本機的秘密金鑰加解密,故換主機後會無效。

加密

$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

加解密

SecureStringService.cs
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