Files
finance_tjia/encrypt-key.ps1
2026-10-29 14:26:48 +08:00

98 lines
3.8 KiB
PowerShell

#requires -Version 5.1
[CmdletBinding()]
param(
[switch]$UpdateConfig,
[string]$ConfigPath
)
$ErrorActionPreference = 'Stop'
if ([string]::IsNullOrWhiteSpace($ConfigPath)) {
$scriptDirectory = $PSScriptRoot
if ([string]::IsNullOrWhiteSpace($scriptDirectory) -and
-not [string]::IsNullOrWhiteSpace($MyInvocation.MyCommand.Path)) {
$scriptDirectory = Split-Path -Parent $MyInvocation.MyCommand.Path
}
if ([string]::IsNullOrWhiteSpace($scriptDirectory)) {
throw 'Cannot determine the script directory. Specify -ConfigPath with the full config path.'
}
$ConfigPath = Join-Path $scriptDirectory 'appsettings.Development.json'
}
function ConvertTo-EncryptedValue {
param(
[Security.SecureString]$Value,
[byte[]]$AesKey,
[byte[]]$AesIv
)
$pointer = [IntPtr]::Zero
$bytes = $null
$aes = $null
$encryptor = $null
try {
$pointer = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Value)
$bytes = [Text.Encoding]::UTF8.GetBytes([Runtime.InteropServices.Marshal]::PtrToStringBSTR($pointer))
$aes = [Security.Cryptography.Aes]::Create()
$aes.Key = $AesKey
$aes.IV = $AesIv
$encryptor = $aes.CreateEncryptor()
$encrypted = $encryptor.TransformFinalBlock($bytes, 0, $bytes.Length)
return 'ENC(' + [Convert]::ToBase64String($encrypted) + ')'
}
finally {
if ($null -ne $encryptor) { $encryptor.Dispose() }
if ($null -ne $aes) { $aes.Dispose() }
if ($null -ne $bytes) { [Array]::Clear($bytes, 0, $bytes.Length) }
if ($pointer -ne [IntPtr]::Zero) { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($pointer) }
}
}
# Read the same machine variables as CryptoHelper.cs on the deployment server.
$key = [Text.Encoding]::UTF8.GetBytes([string][Environment]::GetEnvironmentVariable('ENC_AES_KEY', 'Machine'))
$iv = [Text.Encoding]::UTF8.GetBytes([string][Environment]::GetEnvironmentVariable('ENC_AES_IV', 'Machine'))
if ($key.Length -notin @(16, 24, 32) -or $iv.Length -ne 16) {
throw 'ENC_AES_KEY must be 16/24/32 UTF-8 bytes and ENC_AES_IV must be 16 UTF-8 bytes. Run on the deployment server.'
}
$config = $null
if ($UpdateConfig) {
$ConfigPath = [IO.Path]::GetFullPath($ConfigPath)
$config = [IO.File]::ReadAllText($ConfigPath)
foreach ($field in @('AccessKeyId', 'AccessKeySecret')) {
if ([regex]::Matches($config, '("' + $field + '"\s*:\s*)"[^"\r\n]*"').Count -ne 1) {
throw "Expected exactly one $field field in the config. No changes were made."
}
}
}
$id = $null
$secret = $null
try {
$id = Read-Host 'Enter the complete RAM user AccessKey ID (hidden input)' -AsSecureString
$secret = Read-Host 'Enter the complete RAM user AccessKey Secret (hidden input)' -AsSecureString
if ($id.Length -eq 0 -or $secret.Length -eq 0) {
throw 'AccessKey ID and AccessKey Secret cannot be empty. No changes were made.'
}
$encryptedId = ConvertTo-EncryptedValue -Value $id -AesKey $key -AesIv $iv
$encryptedSecret = ConvertTo-EncryptedValue -Value $secret -AesKey $key -AesIv $iv
if ($UpdateConfig) {
$config = [regex]::Replace($config, '("AccessKeyId"\s*:\s*)"[^"\r\n]*"', '${1}"' + $encryptedId + '"')
$config = [regex]::Replace($config, '("AccessKeySecret"\s*:\s*)"[^"\r\n]*"', '${1}"' + $encryptedSecret + '"')
[IO.File]::WriteAllText($ConfigPath, $config, [Text.UTF8Encoding]::new($false))
Write-Host 'Encrypted credentials saved. Deploy the updated config and restart the service.'
}
else {
Write-Output ('AccessKeyId: ' + $encryptedId)
Write-Output ('AccessKeySecret: ' + $encryptedSecret)
}
}
finally {
if ($null -ne $id) { $id.Dispose() }
if ($null -ne $secret) { $secret.Dispose() }
[Array]::Clear($key, 0, $key.Length)
[Array]::Clear($iv, 0, $iv.Length)
}