From ad24d348d28835edfc90385a33357d6d51eef02d Mon Sep 17 00:00:00 2001
From: Ghufran Zahidi <gzahidi@cisco.com>
Date: Thu, 16 Apr 2020 16:39:53 +0530
Subject: [PATCH 1/4] ValidatePattern having double quote(") throws exception
 on running Build.ps1

---
 .../PowerShellExperimentalClientCodegen.java  | 24 +++++++++++++++++++
 .../resources/3_0/powershell/petstore.yaml    |  1 +
 .../src/PSPetstore/Model/User.ps1             |  1 +
 3 files changed, 26 insertions(+)

diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
index 2b5ae61765c..149cfa03b1e 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
@@ -19,6 +19,7 @@ package org.openapitools.codegen.languages;
 import io.swagger.v3.oas.models.media.ArraySchema;
 import io.swagger.v3.oas.models.media.Schema;
 import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang3.StringEscapeUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.openapitools.codegen.*;
 import org.openapitools.codegen.meta.GeneratorMetadata;
@@ -622,6 +623,29 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen
         supportingFiles.add(new SupportingFile("appveyor.mustache", "", "appveyor.yml"));
     }
 
+    @SuppressWarnings("static-method")
+    @Override
+    public String escapeText(String input) {
+    	
+    	if (input == null) {
+            return input;
+        }
+
+        // remove \t, \n, \r
+        // replace \ with \\
+        // replace " with \"
+        // outter unescape to retain the original multi-byte characters
+        // finally escalate characters avoiding code injection
+        return escapeUnsafeCharacters(
+                StringEscapeUtils.unescapeJava(
+                        StringEscapeUtils.escapeJava(input)
+                                .replace("\\/", "/"))
+                        .replaceAll("[\\t\\n\\r]", " ")
+                        .replace("\\", "\\\\")
+                        .replace("\"", "\"\""));
+    	
+    }
+    
     @Override
     public String escapeUnsafeCharacters(String input) {
         return input.replace("#>", "#_>").replace("<#", "<_#");
diff --git a/modules/openapi-generator/src/test/resources/3_0/powershell/petstore.yaml b/modules/openapi-generator/src/test/resources/3_0/powershell/petstore.yaml
index a2e1dbaefa6..11ed2854ba5 100644
--- a/modules/openapi-generator/src/test/resources/3_0/powershell/petstore.yaml
+++ b/modules/openapi-generator/src/test/resources/3_0/powershell/petstore.yaml
@@ -689,6 +689,7 @@ components:
           type: string
         password:
           type: string
+          pattern: '["A-Z]+-[0-9][0-9]'
         phone:
           type: string
         userStatus:
diff --git a/samples/client/petstore/powershell-experimental/src/PSPetstore/Model/User.ps1 b/samples/client/petstore/powershell-experimental/src/PSPetstore/Model/User.ps1
index a0147c19298..7e99caf62fb 100644
--- a/samples/client/petstore/powershell-experimental/src/PSPetstore/Model/User.ps1
+++ b/samples/client/petstore/powershell-experimental/src/PSPetstore/Model/User.ps1
@@ -62,6 +62,7 @@ function Initialize-PSUser {
         [String]
         ${Email},
         [Parameter(Position = 5, ValueFromPipelineByPropertyName = $true)]
+        [ValidatePattern("[""A-Z]+-[0-9][0-9]")]
         [String]
         ${Password},
         [Parameter(Position = 6, ValueFromPipelineByPropertyName = $true)]
-- 
GitLab


From ff0094804ab7c885251b31ad3a60a058c24006c0 Mon Sep 17 00:00:00 2001
From: Ghufran Zahidi <gzahidi@cisco.com>
Date: Fri, 17 Apr 2020 13:20:52 +0530
Subject: [PATCH 2/4] fix tab with space

---
 .../languages/PowerShellExperimentalClientCodegen.java       | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
index 149cfa03b1e..5896ee99efe 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
@@ -626,8 +626,8 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen
     @SuppressWarnings("static-method")
     @Override
     public String escapeText(String input) {
-    	
-    	if (input == null) {
+    
+        if (input == null) {
             return input;
         }
 
@@ -643,7 +643,6 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen
                         .replaceAll("[\\t\\n\\r]", " ")
                         .replace("\\", "\\\\")
                         .replace("\"", "\"\""));
-    	
     }
     
     @Override
-- 
GitLab


From 1d0d4e14ecb102e453559d04b65c9dc4377bb0d7 Mon Sep 17 00:00:00 2001
From: Ghufran Zahidi <gzahidi@cisco.com>
Date: Tue, 5 May 2020 16:17:45 +0530
Subject: [PATCH 3/4] [powershell-experimental] : http signature auth

---
 .../PowerShellExperimentalClientCodegen.java  |   8 +-
 .../api_client.mustache                       |  15 +
 .../http_signature_auth.mustache              | 162 ++++++++
 .../rsa_provider.mustache                     | 377 ++++++++++++++++++
 4 files changed, 560 insertions(+), 2 deletions(-)
 create mode 100644 modules/openapi-generator/src/main/resources/powershell-experimental/http_signature_auth.mustache
 create mode 100644 modules/openapi-generator/src/main/resources/powershell-experimental/rsa_provider.mustache

diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
index 5896ee99efe..e4704963cf5 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
@@ -615,6 +615,9 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen
         supportingFiles.add(new SupportingFile("api_client.mustache", infrastructureFolder + "Private", apiNamePrefix + "ApiClient.ps1"));
         supportingFiles.add(new SupportingFile("Get-CommonParameters.mustache", infrastructureFolder + File.separator + "Private" + File.separator, "Get-CommonParameters.ps1"));
         supportingFiles.add(new SupportingFile("Out-DebugParameter.mustache", infrastructureFolder + File.separator + "Private" + File.separator, "Out-DebugParameter.ps1"));
+        supportingFiles.add(new SupportingFile("http_signature_auth.mustache", infrastructureFolder + "Private", apiNamePrefix + "HttpSignatureAuth.ps1"));
+        supportingFiles.add(new SupportingFile("rsa_provider.mustache", infrastructureFolder + "Private", apiNamePrefix + "RSAEncryptionProvider.cs"));
+        
 
         // en-US
         supportingFiles.add(new SupportingFile("about_Org.OpenAPITools.help.txt.mustache", infrastructureFolder + File.separator + "en-US" + File.separator + "about_" + packageName + ".help.txt"));
@@ -626,8 +629,8 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen
     @SuppressWarnings("static-method")
     @Override
     public String escapeText(String input) {
-    
-        if (input == null) {
+    	
+    	if (input == null) {
             return input;
         }
 
@@ -643,6 +646,7 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen
                         .replaceAll("[\\t\\n\\r]", " ")
                         .replace("\\", "\\\\")
                         .replace("\"", "\"\""));
+    	
     }
     
     @Override
diff --git a/modules/openapi-generator/src/main/resources/powershell-experimental/api_client.mustache b/modules/openapi-generator/src/main/resources/powershell-experimental/api_client.mustache
index 2d785b840d1..c6a456c481e 100644
--- a/modules/openapi-generator/src/main/resources/powershell-experimental/api_client.mustache
+++ b/modules/openapi-generator/src/main/resources/powershell-experimental/api_client.mustache
@@ -89,6 +89,21 @@ function Invoke-{{{apiNamePrefix}}}ApiClient {
         $RequestBody = $Body
     }
 
+# http signature authentication
+    if ($null -ne $Configuration['ApiKey'] -and $Configuration['ApiKey'].Count -gt 0) {
+        $httpSignHeaderArgument = @{
+            Method     = $Method
+            UriBuilder = $UriBuilder
+            Body       = $Body
+        }
+        $signedHeader = Get-{{{apiNamePrefix}}}HttpSignedHeader @httpSignHeaderArgument
+        if($null -ne $signedHeader -and $signedHeader.Count -gt 0){
+            foreach($item in $signedHeader.GetEnumerator()){
+                $HeaderParameters[$item.Name] = $item.Value
+            }
+        }
+    }
+
     if ($SkipCertificateCheck -eq $true) {
         $Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
                                   -Method $Method `
diff --git a/modules/openapi-generator/src/main/resources/powershell-experimental/http_signature_auth.mustache b/modules/openapi-generator/src/main/resources/powershell-experimental/http_signature_auth.mustache
new file mode 100644
index 00000000000..aeb74be678d
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/powershell-experimental/http_signature_auth.mustache
@@ -0,0 +1,162 @@
+{{>partial_header}}
+<#
+.SYNOPSIS
+Get the API key Id and API key file path.
+
+.DESCRIPTION
+Get the API key Id and API key file path. If no api prefix is provided then it use default api key prefix 'Signature'
+.OUTPUTS
+PSCustomObject : This contains APIKeyId, APIKeyFilePath, APIKeyPrefix
+#>
+function Get-{{{apiNamePrefix}}}APIKeyInfo {
+    $ApiKeysList = $Script:Configuration['ApiKey']
+    $ApiKeyPrefixList = $Script:Configuration['ApiKeyPrefix']
+    $apiPrefix = "Signature"
+
+    if ($null -eq $ApiKeysList -or $ApiKeysList.Count -eq 0) {
+        throw "Unable to reterieve the api key details"
+    }
+
+    if ($null -eq $ApiKeyPrefixList -or $ApiKeyPrefixList.Count -eq 0) {
+        Write-Verbose "Unable to reterieve the api key prefix details,setting it to default ""Signature"""
+    }
+
+    foreach ($item in $ApiKeysList.GetEnumerator()) {
+        if (![string]::IsNullOrEmpty($item.Name)) {
+            if (Test-Path -Path $item.Value) {
+                $apiKey = $item.Value
+                $apikeyId = $item.Name
+                break;
+            }
+            else {
+                throw "API key file path does not exist."
+            }
+        }
+    }
+
+    if ($ApiKeyPrefixList.ContainsKey($apikeyId)) {
+        $apiPrefix = ApiKeyPrefixList[$apikeyId]
+    }
+
+    if ($apikeyId -and $apiKey -and $apiPrefix) {
+        $result = New-Object -Type PSCustomObject -Property @{ 
+            ApiKeyId       = $apikeyId;
+            ApiKeyFilePath = $apiKey
+            ApiKeyPrefix   = $apiPrefix
+        }
+    }
+    else {
+        return $null
+    }
+    return $result
+}
+
+<#
+.SYNOPSIS
+    Gets the headers for http signed auth.
+
+.DESCRIPTION
+    Gets the headers for the http signed auth. It use (targetpath), date, host and body digest to create authorization header.
+.PARAMETER Method
+    Http method
+.PARAMETER UriBuilder
+    UriBuilder for url and query parameter
+.PARAMETER Body
+    Request body
+.OUTPUTS
+    Hashtable
+#>
+function Get-{{{apiNamePrefix}}}HttpSignedHeader {
+    param(
+        [string]$Method,
+        [System.UriBuilder]$UriBuilder,
+        [string]$Body
+    )
+
+    #Hash table to store singed headers
+    $HttpSignedHeader = @{}
+    $TargetHost = $UriBuilder.Host
+
+    #Check for Authentication type
+    $apiKeyInfo = Get-{{{apiNamePrefix}}}APIKeyInfo
+    if ($null -eq $apiKeyInfo) {
+        throw "Unable to reterieve the api key info "
+    }
+
+    #get the body digest
+    $bodyHash = Get-{{{apiNamePrefix}}}StringHash -String $Body
+    $Digest = [String]::Format("SHA-256={0}", [Convert]::ToBase64String($bodyHash))
+
+    #get the date in UTC
+    $dateTime = Get-Date
+    $currentDate = $dateTime.ToUniversalTime().ToString("r")
+
+    $requestTargetPath = [string]::Format("{0} {1}{2}",$Method.ToLower(),$UriBuilder.Path.ToLower(),$UriBuilder.Query)
+    $h_requestTarget = [string]::Format("(request-target): {0}",$requestTargetPath)
+    $h_cdate = [string]::Format("date: {0}",$currentDate)
+    $h_digest = [string]::Format("digest: {0}",$Digest)
+    $h_targetHost = [string]::Format("host: {0}",$TargetHost)
+
+    $stringToSign = [String]::Format("{0}`n{1}`n{2}`n{3}",
+                                    $h_requestTarget,$h_cdate,
+                                    $h_targetHost,$h_digest)
+    
+    $hashedString = Get-{{{apiNamePrefix}}}StringHash -String $stringToSign
+    $signedHeader = Get-{{{apiNamePrefix}}}RSASHA256SignedString -APIKeyFilePath $apiKeyInfo.ApiKeyFilePath -DataToSign $hashedString
+    $authorizationHeader = [string]::Format("{0} keyId=""{1}"",algorithm=""rsa-sha256"",headers=""(request-target) date host digest"",signature=""{2}""", 
+        $apiKeyInfo.ApiKeyPrefix, $apiKeyInfo.ApiKeyId, $signedHeader)
+    
+    $HttpSignedHeader["Date"] = $currentDate
+    $HttpSignedHeader["Host"] = $TargetHost
+    $HttpSignedHeader["Content-Type"] = "application/json"
+    $HttpSignedHeader["Digest"] = $Digest
+    $HttpSignedHeader["Authorization"] = $authorizationHeader   
+    return $HttpSignedHeader
+}
+
+<#
+.SYNOPSIS
+    Gets the headers for http signed auth.
+
+.DESCRIPTION
+    Gets the headers for the http signed auth. It use (targetpath), date, host and body digest to create authorization header.
+.PARAMETER APIKeyFilePath
+    Specify the API key file path
+.PARAMETER DataToSign
+    Specify the data to sign
+.OUTPUTS
+    String
+#>
+function Get-{{{apiNamePrefix}}}RSASHA256SignedString {
+    Param(
+        [string]$APIKeyFilePath,
+        [byte[]]$DataToSign
+    )
+    try {
+        
+        $rsa_provider_path = Join-Path -Path $PSScriptRoot -ChildPath "{{{apiNamePrefix}}}RSAEncryptionProvider.cs"
+        $rsa_provider_sourceCode = Get-Content -Path $rsa_provider_path -Raw
+        Add-Type -TypeDefinition $rsa_provider_sourceCode
+        $signed_string = [RSAEncryption.RSAEncryptionProvider]::GetRSASignb64encode($APIKeyFilePath, $DataToSign)
+        if ($null -eq $signed_string) {
+            throw "Unable to sign the header using the API key"
+        }
+        return $signed_string
+    }
+    catch {
+        throw $_
+    }
+}
+<#
+.Synopsis
+    Gets the hash of string.
+.Description
+    Gets the hash of string
+.Outputs
+String 
+#>
+Function Get-{{{apiNamePrefix}}}StringHash([String] $String, $HashName = "SHA256") { 
+
+    $hashAlogrithm = [System.Security.Cryptography.HashAlgorithm]::Create($HashName)
+    $hashAlogrithm.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String)) 
+}
\ No newline at end of file
diff --git a/modules/openapi-generator/src/main/resources/powershell-experimental/rsa_provider.mustache b/modules/openapi-generator/src/main/resources/powershell-experimental/rsa_provider.mustache
new file mode 100644
index 00000000000..a23490b366e
--- /dev/null
+++ b/modules/openapi-generator/src/main/resources/powershell-experimental/rsa_provider.mustache
@@ -0,0 +1,377 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace RSAEncryption
+{
+    public class RSAEncryptionProvider
+    {
+
+        const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----";
+        const String pemprivfooter = "-----END RSA PRIVATE KEY-----";
+        const String pempubheader = "-----BEGIN PUBLIC KEY-----";
+        const String pempubfooter = "-----END PUBLIC KEY-----";
+        const String pemp8header = "-----BEGIN PRIVATE KEY-----";
+        const String pemp8footer = "-----END PRIVATE KEY-----";
+        const String pemp8encheader = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
+        const String pemp8encfooter = "-----END ENCRYPTED PRIVATE KEY-----";
+        public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
+        {
+            byte[] MODULUS, E, D, P, Q, DP, DQ, IQ;
+
+            // ---------  Set up stream to decode the asn.1 encoded RSA private key  ------
+            MemoryStream mem = new MemoryStream(privkey);
+            BinaryReader binr = new BinaryReader(mem);    //wrap Memory Stream with BinaryReader for easy reading
+            byte bt = 0;
+            ushort twobytes = 0;
+            int elems = 0;
+            try
+            {
+                twobytes = binr.ReadUInt16();
+                if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
+                    binr.ReadByte();    //advance 1 byte
+                else if (twobytes == 0x8230)
+                    binr.ReadInt16();   //advance 2 bytes
+                else
+                    return null;
+
+                twobytes = binr.ReadUInt16();
+                if (twobytes != 0x0102) //version number
+                    return null;
+                bt = binr.ReadByte();
+                if (bt != 0x00)
+                    return null;
+
+
+                //------  all private key components are Integer sequences ----
+                elems = GetIntegerSize(binr);
+                MODULUS = binr.ReadBytes(elems);
+
+                elems = GetIntegerSize(binr);
+                E = binr.ReadBytes(elems);
+
+                elems = GetIntegerSize(binr);
+                D = binr.ReadBytes(elems);
+
+                elems = GetIntegerSize(binr);
+                P = binr.ReadBytes(elems);
+
+                elems = GetIntegerSize(binr);
+                Q = binr.ReadBytes(elems);
+
+                elems = GetIntegerSize(binr);
+                DP = binr.ReadBytes(elems);
+
+                elems = GetIntegerSize(binr);
+                DQ = binr.ReadBytes(elems);
+
+                elems = GetIntegerSize(binr);
+                IQ = binr.ReadBytes(elems);
+
+                /*Console.WriteLine("showing components ..");
+                if (true)
+                {
+                    showBytes("\nModulus", MODULUS);
+                    showBytes("\nExponent", E);
+                    showBytes("\nD", D);
+                    showBytes("\nP", P);
+                    showBytes("\nQ", Q);
+                    showBytes("\nDP", DP);
+                    showBytes("\nDQ", DQ);
+                    showBytes("\nIQ", IQ);
+                }*/
+
+                // ------- create RSACryptoServiceProvider instance and initialize with public key -----
+                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
+                RSAParameters RSAparams = new RSAParameters();
+                RSAparams.Modulus = MODULUS;
+                RSAparams.Exponent = E;
+                RSAparams.D = D;
+                RSAparams.P = P;
+                RSAparams.Q = Q;
+                RSAparams.DP = DP;
+                RSAparams.DQ = DQ;
+                RSAparams.InverseQ = IQ;
+                RSA.ImportParameters(RSAparams);
+                return RSA;
+            }
+            catch (Exception)
+            {
+                return null;
+            }
+            finally { binr.Close(); }
+        }
+
+        private static int GetIntegerSize(BinaryReader binr)
+        {
+            byte bt = 0;
+            byte lowbyte = 0x00;
+            byte highbyte = 0x00;
+            int count = 0;
+            bt = binr.ReadByte();
+            if (bt != 0x02)     //expect integer
+                return 0;
+            bt = binr.ReadByte();
+
+            if (bt == 0x81)
+                count = binr.ReadByte();    // data size in next byte
+            else
+                if (bt == 0x82)
+            {
+                highbyte = binr.ReadByte(); // data size in next 2 bytes
+                lowbyte = binr.ReadByte();
+                byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
+                count = BitConverter.ToInt32(modint, 0);
+            }
+            else
+            {
+                count = bt;     // we already have the data size
+            }
+            while (binr.ReadByte() == 0x00)
+            {   //remove high order zeros in data
+                count -= 1;
+            }
+            binr.BaseStream.Seek(-1, SeekOrigin.Current);
+            //last ReadByte wasn't a removed zero, so back up a byte
+            return count;
+        }
+
+        static byte[] DecodeOpenSSLPrivateKey(String instr)
+        {
+            const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----";
+            const String pemprivfooter = "-----END RSA PRIVATE KEY-----";
+            String pemstr = instr.Trim();
+            byte[] binkey;
+            if (!pemstr.StartsWith(pemprivheader) || !pemstr.EndsWith(pemprivfooter))
+                return null;
+
+            StringBuilder sb = new StringBuilder(pemstr);
+            sb.Replace(pemprivheader, "");  //remove headers/footers, if present
+            sb.Replace(pemprivfooter, "");
+
+            String pvkstr = sb.ToString().Trim();   //get string after removing leading/trailing whitespace
+
+            try
+            {        // if there are no PEM encryption info lines, this is an UNencrypted PEM private key
+                binkey = Convert.FromBase64String(pvkstr);
+                return binkey;
+            }
+            catch (System.FormatException)
+            {       //if can't b64 decode, it must be an encrypted private key
+                    //Console.WriteLine("Not an unencrypted OpenSSL PEM private key");  
+            }
+
+            StringReader str = new StringReader(pvkstr);
+
+            //-------- read PEM encryption info. lines and extract salt -----
+            if (!str.ReadLine().StartsWith("Proc-Type: 4,ENCRYPTED"))
+                return null;
+            String saltline = str.ReadLine();
+            if (!saltline.StartsWith("DEK-Info: DES-EDE3-CBC,"))
+                return null;
+            String saltstr = saltline.Substring(saltline.IndexOf(",") + 1).Trim();
+            byte[] salt = new byte[saltstr.Length / 2];
+            for (int i = 0; i < salt.Length; i++)
+                salt[i] = Convert.ToByte(saltstr.Substring(i * 2, 2), 16);
+            if (!(str.ReadLine() == ""))
+                return null;
+
+            //------ remaining b64 data is encrypted RSA key ----
+            String encryptedstr = str.ReadToEnd();
+
+            try
+            {   //should have b64 encrypted RSA key now
+                binkey = Convert.FromBase64String(encryptedstr);
+            }
+            catch (System.FormatException)
+            {  // bad b64 data.
+                return null;
+            }
+
+            //------ Get the 3DES 24 byte key using PDK used by OpenSSL ----
+
+            SecureString despswd = GetSecPswd("Enter password to derive 3DES key==>");
+            //Console.Write("\nEnter password to derive 3DES key: ");
+            //String pswd = Console.ReadLine();
+            byte[] deskey = GetOpenSSL3deskey(salt, despswd, 1, 2);    // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes
+            if (deskey == null)
+                return null;
+            //showBytes("3DES key", deskey) ;
+
+            //------ Decrypt the encrypted 3des-encrypted RSA private key ------
+            byte[] rsakey = DecryptKey(binkey, deskey, salt); //OpenSSL uses salt value in PEM header also as 3DES IV
+            if (rsakey != null)
+                return rsakey;  //we have a decrypted RSA private key
+            else
+            {
+                Console.WriteLine("Failed to decrypt RSA private key; probably wrong password.");
+                return null;
+            }
+        }
+
+        static byte[] GetOpenSSL3deskey(byte[] salt, SecureString secpswd, int count, int miter)
+        {
+            IntPtr unmanagedPswd = IntPtr.Zero;
+            int HASHLENGTH = 16;    //MD5 bytes
+            byte[] keymaterial = new byte[HASHLENGTH * miter];     //to store contatenated Mi hashed results
+
+
+            byte[] psbytes = new byte[secpswd.Length];
+            unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi(secpswd);
+            Marshal.Copy(unmanagedPswd, psbytes, 0, psbytes.Length);
+            Marshal.ZeroFreeGlobalAllocAnsi(unmanagedPswd);
+
+            //UTF8Encoding utf8 = new UTF8Encoding();
+            //byte[] psbytes = utf8.GetBytes(pswd);
+
+            // --- contatenate salt and pswd bytes into fixed data array ---
+            byte[] data00 = new byte[psbytes.Length + salt.Length];
+            Array.Copy(psbytes, data00, psbytes.Length);      //copy the pswd bytes
+            Array.Copy(salt, 0, data00, psbytes.Length, salt.Length); //concatenate the salt bytes
+
+            // ---- do multi-hashing and contatenate results  D1, D2 ...  into keymaterial bytes ----
+            MD5 md5 = new MD5CryptoServiceProvider();
+            byte[] result = null;
+            byte[] hashtarget = new byte[HASHLENGTH + data00.Length];   //fixed length initial hashtarget
+
+            for (int j = 0; j < miter; j++)
+            {
+                // ----  Now hash consecutively for count times ------
+                if (j == 0)
+                    result = data00;    //initialize 
+                else
+                {
+                    Array.Copy(result, hashtarget, result.Length);
+                    Array.Copy(data00, 0, hashtarget, result.Length, data00.Length);
+                    result = hashtarget;
+                    //Console.WriteLine("Updated new initial hash target:") ;
+                    //showBytes(result) ;
+                }
+
+                for (int i = 0; i < count; i++)
+                    result = md5.ComputeHash(result);
+                Array.Copy(result, 0, keymaterial, j * HASHLENGTH, result.Length);  //contatenate to keymaterial
+            }
+            //showBytes("Final key material", keymaterial);
+            byte[] deskey = new byte[24];
+            Array.Copy(keymaterial, deskey, deskey.Length);
+
+            Array.Clear(psbytes, 0, psbytes.Length);
+            Array.Clear(data00, 0, data00.Length);
+            Array.Clear(result, 0, result.Length);
+            Array.Clear(hashtarget, 0, hashtarget.Length);
+            Array.Clear(keymaterial, 0, keymaterial.Length);
+
+            return deskey;
+        }
+
+        public static string GetRSASignb64encode(string private_key_path, byte[] digest)
+        {
+            RSACryptoServiceProvider cipher = new RSACryptoServiceProvider();
+            cipher = GetRSAProviderFromPemFile(private_key_path);
+            RSAPKCS1SignatureFormatter RSAFormatter = new RSAPKCS1SignatureFormatter(cipher);
+            RSAFormatter.SetHashAlgorithm("SHA256");
+            byte[] signedHash = RSAFormatter.CreateSignature(digest);
+            return Convert.ToBase64String(signedHash);
+        }
+
+        public static RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile)
+        {
+            bool isPrivateKeyFile = true;
+            if (!File.Exists(pemfile))
+            {
+                throw new Exception("pemfile does not exist.");
+            }
+            string pemstr = File.ReadAllText(pemfile).Trim();
+            if (pemstr.StartsWith(pempubheader) && pemstr.EndsWith(pempubfooter))
+                isPrivateKeyFile = false;
+
+            byte[] pemkey = null;
+            if (isPrivateKeyFile)
+                pemkey = DecodeOpenSSLPrivateKey(pemstr);
+
+
+            if (pemkey == null)
+                return null;
+
+            if (isPrivateKeyFile)
+            {
+                return DecodeRSAPrivateKey(pemkey);
+            }
+            return null;
+        }
+
+        static byte[] DecryptKey(byte[] cipherData, byte[] desKey, byte[] IV)
+        {
+            MemoryStream memst = new MemoryStream();
+            TripleDES alg = TripleDES.Create();
+            alg.Key = desKey;
+            alg.IV = IV;
+            try
+            {
+                CryptoStream cs = new CryptoStream(memst, alg.CreateDecryptor(), CryptoStreamMode.Write);
+                cs.Write(cipherData, 0, cipherData.Length);
+                cs.Close();
+            }
+            catch (Exception exc)
+            {
+                Console.WriteLine(exc.Message);
+                return null;
+            }
+            byte[] decryptedData = memst.ToArray();
+            return decryptedData;
+        }
+
+        static SecureString GetSecPswd(String prompt)
+        {
+            SecureString password = new SecureString();
+
+            Console.ForegroundColor = ConsoleColor.Gray;
+            Console.ForegroundColor = ConsoleColor.Magenta;
+
+            while (true)
+            {
+                ConsoleKeyInfo cki = Console.ReadKey(true);
+                if (cki.Key == ConsoleKey.Enter)
+                {
+                    Console.ForegroundColor = ConsoleColor.Gray;
+                    return password;
+                }
+                else if (cki.Key == ConsoleKey.Backspace)
+                {
+                    // remove the last asterisk from the screen...
+                    if (password.Length > 0)
+                    {
+                        Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
+                        Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
+                        password.RemoveAt(password.Length - 1);
+                    }
+                }
+                else if (cki.Key == ConsoleKey.Escape)
+                {
+                    Console.ForegroundColor = ConsoleColor.Gray;
+                    return password;
+                }
+                else if (Char.IsLetterOrDigit(cki.KeyChar) || Char.IsSymbol(cki.KeyChar))
+                {
+                    if (password.Length < 20)
+                    {
+                        password.AppendChar(cki.KeyChar);
+                    }
+                    else
+                    {
+                        Console.Beep();
+                    }
+                }
+                else
+                {
+                    Console.Beep();
+                }
+            }
+        }
+    }
+}
-- 
GitLab


From 5372b5ae8adb29e532afb3d45f51571b6a171127 Mon Sep 17 00:00:00 2001
From: Ghufran Zahidi <gzahidi@cisco.com>
Date: Tue, 5 May 2020 16:55:19 +0530
Subject: [PATCH 4/4] fix the tab issue

---
 .../languages/PowerShellExperimentalClientCodegen.java      | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
index e4704963cf5..3151617e438 100644
--- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
+++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java
@@ -629,8 +629,8 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen
     @SuppressWarnings("static-method")
     @Override
     public String escapeText(String input) {
-    	
-    	if (input == null) {
+        
+        if (input == null) {
             return input;
         }
 
@@ -646,7 +646,7 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen
                         .replaceAll("[\\t\\n\\r]", " ")
                         .replace("\\", "\\\\")
                         .replace("\"", "\"\""));
-    	
+        
     }
     
     @Override
-- 
GitLab