问题
I am trying to encrypt a text using AWS KMS and creating a powershell script. So I used New-KMSDataKey
to encrypt my KMS master key which in output returns plaintextDataKey
and ciphertextblob
.
Now I am using plaintextDataKey
to encrypt my plaintext using Invoke-KMSEncrypt
but I get Invalid Operation error as shown below:
Below is my script:
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
What can I do to make it right? Am I doing anything wrong here? There is no other cmdlets here to encrypt data: http://docs.aws.amazon.com/powershell/latest/reference/Index.html
Could anyone please help here? How can I use the above plaintext data key to encrypt my content?
回答1:
The code presented has many of the right bones in it to be a part of this animal, but it has several issues that prevent it from working, including missing some of the concepts underpinning KMS. Using data keys is a great way to work with KMS, but when you do that, you must understand that you need to rely on your host system's ability to encrypt and decrypt the data with the keys provided.
KMS Data Keys provide envelope encryption support and the encryption and decryption that KMS provides is for the key itself, not your data. When using data keys, you must use the plaintext key that the KMS provides to encrypt your data, and then store the ciphertext version of the key that you were provided alongside the data. When it is time to decrypt your ciphertext, you use KMS to decrypt the data key and then use the plaintext derived from the data key ciphertext key as the key in your AES decryption.
Here's an example of a test run from working pair of scripts that I derived from the code you provided, with the KMS key ID scrubbed:
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
And here are the encrypt and decrypt scripts:
encrypt.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 http://stackoverflow.com/a/24778625/424301
# 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))
}
decrypt.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
}
来源:https://stackoverflow.com/questions/40667685/how-to-encrypt-data-using-kms-key-in-aws-powershell-script