forked from loafle/openapi-generator-original
[powershell-experimental] : http signature authentication implementation (#6176)
* ValidatePattern having double quote(") throws exception on running Build.ps1 * fix tab with space * [powershell-experimental] : http signature auth * fix the tab issue Co-authored-by: Ghufran Zahidi <gzahidi@cisco.com>
This commit is contained in:
parent
5f2270a0e8
commit
13f329eafe
@ -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("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("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("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
|
// en-US
|
||||||
supportingFiles.add(new SupportingFile("about_Org.OpenAPITools.help.txt.mustache", infrastructureFolder + File.separator + "en-US" + File.separator + "about_" + packageName + ".help.txt"));
|
supportingFiles.add(new SupportingFile("about_Org.OpenAPITools.help.txt.mustache", infrastructureFolder + File.separator + "en-US" + File.separator + "about_" + packageName + ".help.txt"));
|
||||||
@ -626,7 +629,7 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen
|
|||||||
@SuppressWarnings("static-method")
|
@SuppressWarnings("static-method")
|
||||||
@Override
|
@Override
|
||||||
public String escapeText(String input) {
|
public String escapeText(String input) {
|
||||||
|
|
||||||
if (input == null) {
|
if (input == null) {
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
@ -643,6 +646,7 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen
|
|||||||
.replaceAll("[\\t\\n\\r]", " ")
|
.replaceAll("[\\t\\n\\r]", " ")
|
||||||
.replace("\\", "\\\\")
|
.replace("\\", "\\\\")
|
||||||
.replace("\"", "\"\""));
|
.replace("\"", "\"\""));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -89,6 +89,21 @@ function Invoke-{{{apiNamePrefix}}}ApiClient {
|
|||||||
$RequestBody = $Body
|
$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) {
|
if ($SkipCertificateCheck -eq $true) {
|
||||||
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
|
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
|
||||||
-Method $Method `
|
-Method $Method `
|
||||||
|
162
modules/openapi-generator/src/main/resources/powershell-experimental/http_signature_auth.mustache
vendored
Normal file
162
modules/openapi-generator/src/main/resources/powershell-experimental/http_signature_auth.mustache
vendored
Normal file
@ -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))
|
||||||
|
}
|
377
modules/openapi-generator/src/main/resources/powershell-experimental/rsa_provider.mustache
vendored
Normal file
377
modules/openapi-generator/src/main/resources/powershell-experimental/rsa_provider.mustache
vendored
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user