Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
SecureStringCommands.cs390 linesDownload Raw Back to security
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