如何在 AWS Powershell 脚本中使用 KMS 密钥加密数据

How to encrypt data using KMS key in AWS Powershell script

我正在尝试使用 AWS KMS 加密文本并创建 powershell 脚本。所以我使用 New-KMSDataKey 加密我的 KMS 主密钥,输出 returns plaintextDataKeyciphertextblob

现在我正在使用 plaintextDataKey 使用 Invoke-KMSEncrypt 加密我的明文,但我收到无效操作错误,如下所示:

下面是我的脚本:

param([string]$zonesecret, [string]$KMSKey, [string]$Keyspec, [string]$region= 'us-east-1', [string]$AccessKey, [string]$SecretKey)

# splat
$splat = @{KeyId=$KMSKey; KeySpec=$Keyspec; Region=$region}
# generate a data key 
$datakey = New-KMSDataKey @splat

$plaintextDataKey = [Convert]::ToBase64String($datakey.Plaintext.ToArray())
$encryptedDataKey = [Convert]::ToBase64String($datakey.CiphertextBlob.ToArray())
Write-Host $plaintextDataKey
Write-Host $encryptedDataKey

#encrypt using aes-256; pass zonesecret and plaintextDataKey
# memory stream
[byte[]]$byteArray = [System.Text.Encoding]::UTF8.GetBytes($zonesecret)
$memoryStream = New-Object System.IO.MemoryStream($byteArray,0,$byteArray.Length)

$splat = @{Plaintext=$memoryStream; KeyId=$plaintextDataKey; Region=$region;}
if(![string]::IsNullOrEmpty($AccessKey)){$splat += @{AccessKey=$AccessKey;}}
if(![string]::IsNullOrEmpty($SecretKey)){$splat += @{SecretKey=$SecretKey;}}

# encrypt
**$encryptedMemoryStream = Invoke-KMSEncrypt @splat** # ERROR: 
Write-Host $encryptedMemoryStream

$base64encrypted = [System.Convert]::ToBase64String($encryptedMemoryStream.CiphertextBlob.ToArray())
Write-Host $base64encrypted

我该怎么做才能使它正确?我在这里做错了什么吗?这里没有其他 cmdlet 来加密数据:http://docs.aws.amazon.com/powershell/latest/reference/Index.html

有人可以帮忙吗?如何使用上述明文数据密钥来加密我的内容?

提供的代码中有许多正确的骨骼可以成为这种动物的一部分,但它有几个问题阻止它工作,包括缺少一些支持 KMS 的概念。使用数据密钥是使用 KMS 的一种很好的方式,但是当您这样做时,您必须了解您需要依赖主机系统的能力来使用提供的密钥加密和解密数据。

KMS 数据密钥提供 envelope encryption 支持,KMS 提供的加密和解密是针对密钥本身,而不是您的数据。使用数据密钥时,您必须使用 KMS 提供的明文密钥来加密您的数据,然后将您提供的密钥的密文版本与数据一起存储。当需要解密您的密文时,您使用 KMS 解密 数据密钥 ,然后使用从数据密钥密文密钥派生的明文作为 AES 解密中的密钥。

这是我从您提供的代码派生的工作脚本对 运行 的测试示例,已清除 KMS 密钥 ID:

PS C:\Users\Administrator> $kmskey =  'abcdef01-2345-6789-0123-0123456789ab'
PS C:\Users\Administrator> ./encrypt.ps1 "This is a test" -KMSKey $kmskey | ConvertTo-Json > message.json
PS C:\Users\Administrator> type message.json
{
    "encryptedDataKey":      "AQEDAHix3RkObJxNv8rJGn2Oyy0bRR9GOvSOFTHR2OQ6SBt76wAAAH4wfAYJKoZIhvcNAQcGoG8wbQIBADBoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDGui8Ycxf+XoJkAkuQIBEIA7R6eiM6PREoJdnaNA5gaeZfcSA3fC3UlRYGE6Epo96U+SqYPYzyXKOEyqB+1+3pCHz2zgZZlbcgzThrs=",
    "ciphertext":  "76492d1116743f0423413b16050a5345MgB8AGwANgBEAEwAaQB5AFQAOQByAGgAYgBPAGcAagBKAGIAQQBBAEwAQgBkAEEAPQA9AHwAMgAzADIAYgA0AGEAYgBlADgAMAA5AGQAZABkADEAOQBlADkAYgBjADgAZgA2ADgAMAA0ADgAZABhADQANQA5ADYAMABiAGIAYQAxADQANABiADAAOAA2ADYANgBlAGYANwAxADkANQA2ADEAMgBjAGEANQBjADAAYgBjAGMANAA=\r\n"
}
PS C:\Users\Administrator> ConvertFrom-JSON $(Get-Content .\message.json | Out-String) | .\decrypt.ps1 -KMSKey $kmskey

plaintext
---------
This is a test

PS C:\Users\Administrator> ./encrypt.ps1 "Super Secret Stuff" -KMSKey $kmskey | .\decrypt.ps1 -KMSKey $kmskey

plaintext
---------
Super Secret Stuff

这里是加密和解密脚本:

加密。ps1

param(
    [Parameter(Mandatory=$True)]
    [string]$secret,

    [Parameter(Mandatory=$True)]
    [string]$KMSKey,

    [string]$Keyspec = 'AES_256',

    [string]$region = 'us-east-1'
)

# generate a data key
$datakey = New-KMSDataKey -KeyId $KMSKey -KeySpec $Keyspec -Region $region

[byte[]]$plaintextDataKey = $datakey.Plaintext.ToArray()
[byte[]]$encryptedDataKey = $datakey.CiphertextBlob.ToArray()

# Encrypt using AES using Powershell's SecureString facilities
# Any AES encryption method would do, this is just the most convenient
# way to do this from Powershell.
#
# Note that trying to use the Invoke-KMSEncrypt method is not what you want
# to do when using Data Keys and envelope encryption.
$encrypted = ConvertTo-SecureString $secret -AsPlainText -Force `
    | ConvertFrom-SecureString -key $plaintextDataKey `
    | Out-String

# Thanks to  
# for the tip on using psobject return values and
# ValueFromPipelineByPropertyName parameters (see decrypt.ps1)
return New-Object psobject -property @{ 
    "ciphertext" = $encrypted;
    "encryptedDataKey" = $([Convert]::ToBase64String($encryptedDataKey))
}

解密.ps1

[CmdletBinding()]
param(
    [Parameter(Mandatory=$true,
        Position=0,
        ValueFromPipelineByPropertyName=$true)]
    [string]$ciphertext,

    [Parameter(Mandatory=$true,
        Position=1,
        ValueFromPipelineByPropertyName=$true)]
    [string]$encryptedDataKey,

    [Parameter(Mandatory=$true,
        Position=2,
        ValueFromPipelineByPropertyName=$true)]
    [string]$KMSKey
)

[byte[]]$bytes = $([Convert]::FromBase64String($encryptedDataKey))
$stream = new-object System.IO.MemoryStream (,$bytes)

# decrypt the data key 
$response = Invoke-KMSDecrypt -CiphertextBlob $stream
if ($response.HttpStatusCode -eq 200) {
    $dataKey = $response.Plaintext.ToArray()
} else {
    throw "KMS data key decrypt failed: $(ConvertTo-Json $response)"
}
# Now AES decrypt the ciphertext and emit the plaintext
$secureString = ConvertTo-SecureString $ciphertext -key $dataKey
$plaintext =  [Runtime.InteropServices.Marshal]::PtrToStringAuto( `
    [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString))
return  New-Object psobject -property @{
    "plaintext" = $plaintext
}