MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Management.Automation;6using System.Runtime.InteropServices;7using System.Security;8using System.Security.Cryptography;9 10using Dbg = System.Management.Automation;11 12namespace Microsoft.PowerShell.Commands13{14 /// <summary>15 /// Defines the base class from which all SecureString commands16 /// are derived.17 /// </summary>18 public abstract class SecureStringCommandBase : PSCmdlet19 {20 private SecureString _ss;21 22 /// <summary>23 /// Gets or sets the secure string to be used by the get- and set-24 /// commands.25 /// </summary>26 protected SecureString SecureStringData27 {28 get { return _ss; }29 30 set { _ss = value; }31 }32 33 //34 // name of this command35 //36 private readonly string _commandName;37 38 /// <summary>39 /// Initializes a new instance of the SecureStringCommandBase40 /// class.41 /// </summary>42 /// <param name="name">43 /// The command name deriving from this class44 /// </param>45 protected SecureStringCommandBase(string name) : base()46 {47 _commandName = name;48 }49 50 private SecureStringCommandBase() : base() { }51 }52 53 /// <summary>54 /// Defines the base class from which all SecureString import and55 /// export commands are derived.56 /// </summary>57 public abstract class ConvertFromToSecureStringCommandBase : SecureStringCommandBase58 {59 /// <summary>60 /// Initializes a new instance of the ConvertFromToSecureStringCommandBase61 /// class.62 /// </summary>63 protected ConvertFromToSecureStringCommandBase(string name) : base(name) { }64 65 private SecureString _secureKey = null;66 private byte[] _key;67 68 /// <summary>69 /// Gets or sets the SecureString version of the encryption70 /// key used by the SecureString cmdlets.71 /// </summary>72 [Parameter(Position = 1, ParameterSetName = "Secure")]73 public SecureString SecureKey74 {75 get76 {77 return _secureKey;78 }79 80 set81 {82 _secureKey = value;83 }84 }85 86 /// <summary>87 /// Gets or sets the byte version of the encryption88 /// key used by the SecureString cmdlets.89 /// </summary>90 [Parameter(ParameterSetName = "Open")]91 public byte[] Key92 {93 get94 {95 return _key;96 }97 98 set99 {100 _key = value;101 }102 }103 }104 105 /// <summary>106 /// Defines the implementation of the 'ConvertFrom-SecureString' cmdlet.107 /// This cmdlet exports a new SecureString -- one that represents108 /// text that should be kept confidential. The text is encrypted109 /// for privacy when being used, and deleted from computer memory110 /// when no longer needed. When no key is specified, the command111 /// uses the DPAPI to encrypt the string. When a key is specified, the112 /// command uses the AES algorithm to encrypt the string.113 /// </summary>114 [Cmdlet(VerbsData.ConvertFrom, "SecureString", DefaultParameterSetName = "Secure", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096497")]115 [OutputType(typeof(string))]116 public sealed class ConvertFromSecureStringCommand : ConvertFromToSecureStringCommandBase117 {118 /// <summary>119 /// Initializes a new instance of the ExportSecureStringCommand class.120 /// </summary>121 public ConvertFromSecureStringCommand() : base("ConvertFrom-SecureString") { }122 123 /// <summary>124 /// Gets or sets the secure string to be exported.125 /// </summary>126 [Parameter(Position = 0, ValueFromPipeline = true, Mandatory = true)]127 public SecureString SecureString128 {129 get130 {131 return SecureStringData;132 }133 134 set135 {136 SecureStringData = value;137 }138 }139 140 /// <summary>141 /// Gets or sets a switch to get the secure string as plain text.142 /// </summary>143 [Parameter(ParameterSetName = "AsPlainText")]144 public SwitchParameter AsPlainText { get; set; }145 146 /// <summary>147 /// Processes records from the input pipeline.148 /// For each input object, the command encrypts149 /// and exports the object.150 /// </summary>151 protected override void ProcessRecord()152 {153 string exportedString = null;154 EncryptionResult encryptionResult = null;155 156 const string argumentName = "SecureString";157 Utils.CheckSecureStringArg(SecureStringData, argumentName);158 if (SecureStringData.Length == 0)159 {160 throw PSTraceSource.NewArgumentException(argumentName);161 }162 163 if (SecureKey != null)164 {165 Dbg.Diagnostics.Assert(Key == null, "Only one encryption key should be specified");166 encryptionResult = SecureStringHelper.Encrypt(SecureString, SecureKey);167 }168 else if (Key != null)169 {170 encryptionResult = SecureStringHelper.Encrypt(SecureString, Key);171 }172 else if (AsPlainText)173 {174 IntPtr valuePtr = IntPtr.Zero;175 try176 {177 valuePtr = Marshal.SecureStringToGlobalAllocUnicode(SecureString);178 exportedString = Marshal.PtrToStringUni(valuePtr);179 }180 finally181 {182 Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);183 }184 }185 else186 {187 exportedString = SecureStringHelper.Protect(SecureString);188 }189 190 if (encryptionResult != null)191 {192 // The formatted string is Algorithm Version,193 // Initialization Vector, Encrypted Data194 string dataPackage = string.Format(195 System.Globalization.CultureInfo.InvariantCulture,196 "{0}|{1}|{2}",197 2,198 encryptionResult.IV,199 encryptionResult.EncryptedData);200 201 // encode the package, and output it.202 // We also include a recognizable prefix so that203 // we can use the old decryption mechanism if we204 // don't see it. While the old decryption205 // generated invalid data for the first bit of the206 // SecureString, it at least didn't generate an207 // exception.208 byte[] outputBytes = System.Text.Encoding.Unicode.GetBytes(dataPackage);209 string encodedString = Convert.ToBase64String(outputBytes);210 WriteObject(SecureStringHelper.SecureStringExportHeader + encodedString);211 }212 else if (exportedString != null)213 {214 WriteObject(exportedString);215 }216 }217 }218 219 /// <summary>220 /// Defines the implementation of the 'ConvertTo-SecureString' cmdlet.221 /// This cmdlet imports a new SecureString from encrypted data --222 /// one that represents text that should be kept confidential.223 /// The text is encrypted for privacy when being used, and deleted224 /// from computer memory when no longer needed. When no key is225 /// specified, the command uses the DPAPI to decrypt the data.226 /// When a key is specified, the command uses the AES algorithm227 /// to decrypt the data.228 /// </summary>229 [Cmdlet(VerbsData.ConvertTo, "SecureString", DefaultParameterSetName = "Secure", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096916")]230 [OutputType(typeof(SecureString))]231 public sealed class ConvertToSecureStringCommand : ConvertFromToSecureStringCommandBase232 {233 /// <summary>234 /// Initializes a new instance of the ImportSecureStringCommand class.235 /// </summary>236 public ConvertToSecureStringCommand() : base("ConvertTo-SecureString") { }237 238 /// <summary>239 /// Gets or sets the unsecured string to be imported.240 /// </summary>241 [Parameter(Position = 0, ValueFromPipeline = true, Mandatory = true)]242 public string String243 {244 get245 {246 return _s;247 }248 249 set250 {251 _s = value;252 }253 }254 255 private string _s;256 257 /// <summary>258 /// Gets or sets the flag that marks the unsecured string as a plain259 /// text string.260 /// </summary>261 [Parameter(Position = 1, ParameterSetName = "PlainText")]262 public SwitchParameter AsPlainText263 {264 get265 {266 return _asPlainText;267 }268 269 set270 {271 _asPlainText = value;272 }273 }274 275 private bool _asPlainText;276 277 /// <summary>278 /// Gets or sets the flag that will force the import of a plaintext279 /// unsecured string.280 /// </summary>281 [Parameter(Position = 2, ParameterSetName = "PlainText")]282 public SwitchParameter Force283 {284 get285 {286 return _force;287 }288 289 set290 {291 _force = value;292 }293 }294 295 private bool _force;296 297 /// <summary>298 /// Processes records from the input pipeline.299 /// For each input object, the command decrypts the data,300 /// then exports a new SecureString created from the object.301 /// </summary>302 protected override void ProcessRecord()303 {304 SecureString importedString = null;305 306 Utils.CheckArgForNullOrEmpty(_s, "String");307 308 try309 {310 string encryptedContent = String;311 byte[] iv = null;312 313 // If this is a V2 package314 if (String.StartsWith(SecureStringHelper.SecureStringExportHeader, StringComparison.OrdinalIgnoreCase))315 {316 try317 {318 // Trim out the header, and retrieve the319 // rest of the string320 string remainingData = this.String.Substring(321 SecureStringHelper.SecureStringExportHeader.Length,322 String.Length - SecureStringHelper.SecureStringExportHeader.Length);323 324 // Unpack it from Base64, get the string325 // representation, then parse it into its components.326 byte[] inputBytes = Convert.FromBase64String(remainingData);327 string dataPackage = System.Text.Encoding.Unicode.GetString(inputBytes);328 string[] dataElements = dataPackage.Split('|');329 330 if (dataElements.Length == 3)331 {332 encryptedContent = dataElements[2];333 iv = Convert.FromBase64String(dataElements[1]);334 }335 }336 catch (FormatException)337 {338 // Will be raised if we can't convert the339 // input from a Base64 string. This means340 // it's not really a V2 package.341 encryptedContent = String;342 iv = null;343 }344 }345 346 if (SecureKey != null)347 {348 Dbg.Diagnostics.Assert(Key == null, "Only one encryption key should be specified");349 importedString = SecureStringHelper.Decrypt(encryptedContent, SecureKey, iv);350 }351 else if (Key != null)352 {353 importedString = SecureStringHelper.Decrypt(encryptedContent, Key, iv);354 }355 else if (!AsPlainText)356 {357 importedString = SecureStringHelper.Unprotect(String);358 }359 else360 {361 importedString = SecureStringHelper.FromPlainTextString(String);362 }363 }364 catch (ArgumentException e)365 {366 ErrorRecord er =367 SecurityUtils.CreateInvalidArgumentErrorRecord(368 e,369 "ImportSecureString_InvalidArgument"370 );371 WriteError(er);372 }373 catch (CryptographicException e)374 {375 ErrorRecord er =376 SecurityUtils.CreateInvalidArgumentErrorRecord(377 e,378 "ImportSecureString_InvalidArgument_CryptographicError"379 );380 WriteError(er);381 }382 383 if (importedString != null)384 {385 WriteObject(importedString);386 }387 }388 }389}390 