Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[KeyVault] Support byte array in invoke-azkeyvaultkeyoperation #23706

Merged
merged 1 commit into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/KeyVault/KeyVault/Az.KeyVault.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ TypesToProcess = @()

# Format files (.ps1xml) to be loaded when importing this module
FormatsToProcess = 'KeyVault.Autorest/Az.KeyVault.format.ps1xml',
'KeyVault.format.ps1xml'
'KeyVault.format.ps1xml', 'keyvault.generated.format.ps1xml'

# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
NestedModules = @('./Az.KeyVault.Extension',
Expand Down
8 changes: 8 additions & 0 deletions src/KeyVault/KeyVault/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
- Additional information about change #1
-->
## Upcoming Release
* Added parameter `ByteArrayValue` in `Invoke-AzKeyVaultKeyOperation` to support operating byte array without conversion to secure string.
* Added Property `RawResult` in the output type `PSKeyOperationResult` of `Invoke-AzKeyVaultKeyOperation`.
* [Upcoming Breaking Change] Added breaking change warning message for parameter `Value` in `Invoke-AzKeyVaultKeyOperation`.
- Parameter `Value` is expected to be removed in Az.KeyVault 6.0.0
- `ByteArrayValue` is the alternative of parameter `Value` in byte array format
* [Upcoming Breaking Change] Added breaking change warning message for the output type `PSKeyOperationResult` of `Invoke-AzKeyVaultKeyOperation`.
- Property `Result` is expected to be removed in Az.KeyVault 6.0.0
- Property `RawResult` is the alternative of parameter `Result` in byte array format

## Version 5.0.1
* Removed redundant Microsoft Graph API calls for access policy in `Get-AzKeyVault`.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using Microsoft.Azure.Commands.KeyVault.Models;
using Microsoft.Azure.Commands.Common.Exceptions;
using Microsoft.Azure.Commands.KeyVault.Models;
using Microsoft.Azure.Commands.ResourceManager.Common.ArgumentCompleters;
using Microsoft.WindowsAzure.Commands.Common.CustomAttributes;
using Microsoft.WindowsAzure.Commands.Utilities.Common;

using System;
using System.Collections;
using System.Management.Automation;
using System.Security;
using System.Text;
Expand All @@ -14,6 +18,7 @@ namespace Microsoft.Azure.Commands.KeyVault.Commands.Key
/// 3. Wraps a symmetric key using a specified key.
/// 4. Unwraps a symmetric key using the specified key that was initially used for wrapping that key.
/// </summary>
[CmdletOutputBreakingChangeWithVersion(typeof(PSKeyOperationResult), "12.0.0", "6.0.0", DeprecatedOutputProperties = new string[] { "Result" }, NewOutputProperties = new string[] { "RawResult" })]
[Cmdlet(VerbsLifecycle.Invoke, ResourceManager.Common.AzureRMConstants.AzurePrefix + "KeyVaultKeyOperation", SupportsShouldProcess = true, DefaultParameterSetName = ByVaultNameParameterSet)]
[OutputType(typeof(PSKeyOperationResult))]
public class InvokeAzureKeyVaultKeyOperation : KeyVaultKeyCmdletBase
Expand Down Expand Up @@ -52,51 +57,89 @@ enum Operations
[Alias("EncryptionAlgorithm", "WrapAlgorithm")]
public string Algorithm { get; set; }

[Parameter(Mandatory = true,
HelpMessage = "The value to be operated")]
[Parameter(Mandatory = false, HelpMessage = "The value to be operated. This parameter will be converted to byte array in UTF-8 encoding way. If your value can't be encoded by UTF-8, please use parameter ByteArrayValue as its alternative.")]
[ValidateNotNullOrEmpty]
[CmdletParameterBreakingChangeWithVersion(nameof(Value), "12.0.0", "6.0.0", ReplaceMentCmdletParameterName = nameof(ByteArrayValue))]
public SecureString Value { get; set; }

[Parameter(Mandatory = false, HelpMessage = "The value to be operated in byte array format.")]
[ValidateNotNullOrEmpty]
public byte[] ByteArrayValue { get; set; }

#endregion Input Parameter Definitions

private Operations opt = Operations.Unknown;

internal void ValidateParameters()
{
if (this.IsParameterBound(c => c.Value) && this.IsParameterBound(c => c.ByteArrayValue))
{
throw new AzPSArgumentException(string.Format("Please provide only one of parameter Value and ByteArrayValue"), nameof(ByteArrayValue));
}
else if (!this.IsParameterBound(c => c.Value) && !this.IsParameterBound(c => c.ByteArrayValue))
{
throw new AzPSArgumentException(string.Format("Must provide one of parameter Value and ByteArrayValue"), nameof(ByteArrayValue));
}
}

internal override void NormalizeParameterSets()
{

if (InputObject != null)
{
Version = Version ?? InputObject.Version;
}

Enum.TryParse(Operation, out opt);

if (this.IsParameterBound(c => c.Value))
{
switch (opt)
{
case Operations.Encrypt:
ByteArrayValue = Encoding.UTF8.GetBytes(Value.ConvertToString());
break;
case Operations.Decrypt:
ByteArrayValue = Convert.FromBase64String(Value.ConvertToString());
break;
case Operations.Wrap:
ByteArrayValue = Encoding.UTF8.GetBytes(Value.ConvertToString());
break;
case Operations.Unwrap:
ByteArrayValue = Convert.FromBase64String(Value.ConvertToString());
break;
default:
throw new NotSupportedException("Not supported ${Operation} yet");
}
}

base.NormalizeParameterSets();
}

public override void ExecuteCmdlet()
{
ValidateParameters();
NormalizeParameterSets();

Operations opt = Operations.Unknown;
Enum.TryParse(Operation, out opt);

if (string.IsNullOrEmpty(HsmName))
{
switch (opt)
{
case Operations.Encrypt:
this.WriteObject(
this.Track2DataClient.Encrypt(VaultName, Name, Version,
Encoding.UTF8.GetBytes(Value.ConvertToString()), Algorithm));
this.Track2DataClient.Encrypt(VaultName, Name, Version, ByteArrayValue, Algorithm));
break;
case Operations.Decrypt:
this.WriteObject(
this.Track2DataClient.Decrypt(VaultName, Name, Version,
Convert.FromBase64String(Value.ConvertToString()), Algorithm));
this.Track2DataClient.Decrypt(VaultName, Name, Version, ByteArrayValue, Algorithm));
break;
case Operations.Wrap:
this.WriteObject(
this.Track2DataClient.WrapKey(VaultName, Name, Version,
Encoding.UTF8.GetBytes(Value.ConvertToString()), Algorithm));
this.Track2DataClient.WrapKey(VaultName, Name, Version, ByteArrayValue, Algorithm));
break;
case Operations.Unwrap:
this.WriteObject(
this.Track2DataClient.UnwrapKey(VaultName, Name, Version,
Convert.FromBase64String(Value.ConvertToString()), Algorithm));
this.Track2DataClient.UnwrapKey(VaultName, Name, Version, ByteArrayValue, Algorithm));
break;
case Operations.Unknown:
throw new NotSupportedException("Not supported ${Operation} yet");
Expand All @@ -108,23 +151,19 @@ public override void ExecuteCmdlet()
{
case Operations.Encrypt:
this.WriteObject(
this.Track2DataClient.ManagedHsmKeyEncrypt(HsmName, Name, Version,
Encoding.UTF8.GetBytes(Value.ConvertToString()), Algorithm));
this.Track2DataClient.ManagedHsmKeyEncrypt(HsmName, Name, Version, ByteArrayValue, Algorithm));
break;
case Operations.Decrypt:
this.WriteObject(
this.Track2DataClient.ManagedHsmKeyDecrypt(HsmName, Name, Version,
Convert.FromBase64String(Value.ConvertToString()), Algorithm));
this.Track2DataClient.ManagedHsmKeyDecrypt(HsmName, Name, Version, ByteArrayValue, Algorithm));
break;
case Operations.Wrap:
this.WriteObject(
this.Track2DataClient.ManagedHsmWrapKey(HsmName, Name, Version,
Encoding.UTF8.GetBytes(Value.ConvertToString()), Algorithm));
this.Track2DataClient.ManagedHsmWrapKey(HsmName, Name, Version, ByteArrayValue, Algorithm));
break;
case Operations.Unwrap:
this.WriteObject(
this.Track2DataClient.ManagedHsmUnwrapKey(HsmName, Name, Version,
Convert.FromBase64String(Value.ConvertToString()), Algorithm));
this.Track2DataClient.ManagedHsmUnwrapKey(HsmName, Name, Version, ByteArrayValue, Algorithm));
break;
case Operations.Unknown:
throw new NotSupportedException("Not supported ${Operation} yet");
Expand Down
18 changes: 18 additions & 0 deletions src/KeyVault/KeyVault/Models/Key/PSKeyOperationResult.cs
Original file line number Diff line number Diff line change
@@ -1,45 +1,63 @@
using Azure.Security.KeyVault.Keys.Cryptography;

using Microsoft.WindowsAzure.Commands.Common.Attributes;

namespace Microsoft.Azure.Commands.KeyVault.Models
{
/// <summary>
///
/// </summary>
public class PSKeyOperationResult
{

// Summary: Key identifier
[Ps1Xml(Target = ViewControl.List, Label = nameof(KeyId), Position = 0)]
public string KeyId { get; }

/// <summary>
/// If operation is Wrap, the value is wrapped key
/// If operation is Unwrap, the value is unwrapped key
/// If operation is Encrypt, the value is encryted data
/// If operation is Decrypt, the value is decrypted data
/// </summary>
[Ps1Xml(Target = ViewControl.List, Label = nameof(RawResult), Position = 1)]
public byte[] RawResult { get; }

// Summary: encryted result or wraped result is base64 format. decryted result or unwraped result is plain text
public string Result { get; }

// Summary: Algorithm used.
[Ps1Xml(Target = ViewControl.List, Label = nameof(Algorithm), Position = 2)]
public string Algorithm { get; }

public PSKeyOperationResult(WrapResult wrapResult)
{
this.KeyId = wrapResult.KeyId;
this.RawResult = wrapResult.EncryptedKey;
this.Result = System.Convert.ToBase64String(wrapResult.EncryptedKey);
this.Algorithm = wrapResult.Algorithm.ToString();
}

public PSKeyOperationResult(UnwrapResult unwrapResult)
{
this.KeyId = unwrapResult.KeyId;
this.RawResult = unwrapResult.Key;
this.Result = System.Text.Encoding.UTF8.GetString(unwrapResult.Key);
this.Algorithm = unwrapResult.Algorithm.ToString();
}

public PSKeyOperationResult(EncryptResult encryptResult)
{
this.KeyId = encryptResult.KeyId;
this.RawResult = encryptResult.Ciphertext;
this.Result = System.Convert.ToBase64String(encryptResult.Ciphertext);
this.Algorithm = encryptResult.Algorithm.ToString();
}

public PSKeyOperationResult(DecryptResult decryptResult)
{
this.KeyId = decryptResult.KeyId;
this.RawResult = decryptResult.Plaintext;
this.Result = System.Text.Encoding.UTF8.GetString(decryptResult.Plaintext);
this.Algorithm = decryptResult.Algorithm.ToString();
}
Expand Down
Loading