forked from loafle/openapi-generator-original
[PowerShell] Add useOneOfDiscriminatorLookup option (#6516)
* add useOneOfDiscriminatorLookup option * update doc
This commit is contained in:
@@ -388,3 +388,140 @@ function Get-PSUrlFromHostSetting {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Sets the configuration for http signing.
|
||||
.DESCRIPTION
|
||||
|
||||
Sets the configuration for the HTTP signature security scheme.
|
||||
The HTTP signature security scheme is used to sign HTTP requests with a key
|
||||
which is in possession of the API client.
|
||||
An 'Authorization' header is calculated by creating a hash of select headers,
|
||||
and optionally the body of the HTTP request, then signing the hash value using
|
||||
a key. The 'Authorization' header is added to outbound HTTP requests.
|
||||
|
||||
Ref: https://openapi-generator.tech
|
||||
|
||||
.PARAMETER KeyId
|
||||
KeyId for HTTP signing
|
||||
|
||||
.PARAMETER KeyFilePath
|
||||
KeyFilePath for HTTP signing
|
||||
|
||||
.PARAMETER KeyPassPhrase
|
||||
KeyPassPhrase, if the HTTP signing key is protected
|
||||
|
||||
.PARAMETER HttpSigningHeader
|
||||
HttpSigningHeader list of HTTP headers used to calculate the signature. The two special signature headers '(request-target)' and '(created)'
|
||||
SHOULD be included.
|
||||
The '(created)' header expresses when the signature was created.
|
||||
The '(request-target)' header is a concatenation of the lowercased :method, an
|
||||
ASCII space, and the :path pseudo-headers.
|
||||
If no headers are specified then '(created)' sets as default.
|
||||
|
||||
.PARAMETER HashAlgorithm
|
||||
HashAlgrithm to calculate the hash, Supported values are "sha256" and "sha512"
|
||||
|
||||
.PARAMETER SigningAlgorithm
|
||||
SigningAlgorithm specifies the signature algorithm, supported values are "RSASSA-PKCS1-v1_5" and "RSASSA-PSS"
|
||||
RSA key : Supported values "RSASSA-PKCS1-v1_5" and "RSASSA-PSS", for ECDSA key this parameter is not applicable
|
||||
|
||||
.PARAMETER SignatureValidityPeriod
|
||||
SignatureValidityPeriod specifies the signature maximum validity time in seconds. It accepts integer value
|
||||
|
||||
.OUTPUTS
|
||||
|
||||
System.Collections.Hashtable
|
||||
#>
|
||||
function Set-PSConfigurationHttpSigning {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string]$KeyId,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$KeyFilePath,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[securestring]$KeyPassPhrase,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string[]] $HttpSigningHeader = @("(created)"),
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateSet("sha256", "sha512")]
|
||||
[string] $HashAlgorithm = "sha256",
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateSet("RSASSA-PKCS1-v1_5", "RSASSA-PSS")]
|
||||
[string]$SigningAlgorithm ,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[int]$SignatureValidityPeriod
|
||||
)
|
||||
|
||||
Process {
|
||||
$httpSignatureConfiguration = @{ }
|
||||
|
||||
if (Test-Path -Path $KeyFilePath) {
|
||||
$httpSignatureConfiguration["KeyId"] = $KeyId
|
||||
$httpSignatureConfiguration["KeyFilePath"] = $KeyFilePath
|
||||
}
|
||||
else {
|
||||
throw "Private key file path does not exist"
|
||||
}
|
||||
|
||||
$keyType = Get-PSKeyTypeFromFile -KeyFilePath $KeyFilePath
|
||||
if ([String]::IsNullOrEmpty($SigningAlgorithm)) {
|
||||
if ($keyType -eq "RSA") {
|
||||
$SigningAlgorithm = "RSASSA-PKCS1-v1_5"
|
||||
}
|
||||
}
|
||||
|
||||
if ($keyType -eq "RSA" -and
|
||||
($SigningAlgorithm -ne "RSASSA-PKCS1-v1_5" -and $SigningAlgorithm -ne "RSASSA-PSS" )) {
|
||||
throw "Provided Key and SigningAlgorithm : $SigningAlgorithm is not compatible."
|
||||
}
|
||||
|
||||
if ($HttpSigningHeader -contains "(expires)" -and $SignatureValidityPeriod -le 0) {
|
||||
throw "SignatureValidityPeriod must be greater than 0 seconds."
|
||||
}
|
||||
|
||||
if ($HttpSigningHeader -contains "(expires)") {
|
||||
$httpSignatureConfiguration["SignatureValidityPeriod"] = $SignatureValidityPeriod
|
||||
}
|
||||
if ($null -ne $HttpSigningHeader -and $HttpSigningHeader.Length -gt 0) {
|
||||
$httpSignatureConfiguration["HttpSigningHeader"] = $HttpSigningHeader
|
||||
}
|
||||
|
||||
if ($null -ne $HashAlgorithm ) {
|
||||
$httpSignatureConfiguration["HashAlgorithm"] = $HashAlgorithm
|
||||
}
|
||||
|
||||
if ($null -ne $SigningAlgorithm) {
|
||||
$httpSignatureConfiguration["SigningAlgorithm"] = $SigningAlgorithm
|
||||
}
|
||||
|
||||
if ($null -ne $KeyPassPhrase) {
|
||||
$httpSignatureConfiguration["KeyPassPhrase"] = $KeyPassPhrase
|
||||
}
|
||||
|
||||
$Script:Configuration["HttpSigning"] = New-Object -TypeName PSCustomObject -Property $httpSignatureConfiguration
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
|
||||
Get the configuration object 'PSConfigurationHttpSigning'.
|
||||
|
||||
.DESCRIPTION
|
||||
|
||||
Get the configuration object 'PSConfigurationHttpSigning'.
|
||||
|
||||
.OUTPUTS
|
||||
|
||||
[PSCustomObject]
|
||||
#>
|
||||
function Get-PSConfigurationHttpSigning{
|
||||
|
||||
$httpSignatureConfiguration = $Script:Configuration["HttpSigning"]
|
||||
return $httpSignatureConfiguration
|
||||
}
|
||||
|
||||
@@ -7,64 +7,11 @@
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get the API key Id and API key file path.
|
||||
|
||||
Gets the headers for HTTP signature.
|
||||
.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-PSAPIKeyInfo {
|
||||
$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.
|
||||
Gets the headers for the http sigature.
|
||||
.PARAMETER Method
|
||||
Http method
|
||||
HTTP method
|
||||
.PARAMETER UriBuilder
|
||||
UriBuilder for url and query parameter
|
||||
.PARAMETER Body
|
||||
@@ -76,93 +23,393 @@ function Get-PSHttpSignedHeader {
|
||||
param(
|
||||
[string]$Method,
|
||||
[System.UriBuilder]$UriBuilder,
|
||||
[string]$Body
|
||||
[string]$Body,
|
||||
[hashtable]$RequestHeader
|
||||
)
|
||||
|
||||
$HEADER_REQUEST_TARGET = '(request-target)'
|
||||
# The time when the HTTP signature was generated.
|
||||
$HEADER_CREATED = '(created)'
|
||||
# The time when the HTTP signature expires. The API server should reject HTTP requests
|
||||
# that have expired.
|
||||
$HEADER_EXPIRES = '(expires)'
|
||||
# The 'Host' header.
|
||||
$HEADER_HOST = 'Host'
|
||||
# The 'Date' header.
|
||||
$HEADER_DATE = 'Date'
|
||||
# When the 'Digest' header is included in the HTTP signature, the client automatically
|
||||
# computes the digest of the HTTP request body, per RFC 3230.
|
||||
$HEADER_DIGEST = 'Digest'
|
||||
# The 'Authorization' header is automatically generated by the client. It includes
|
||||
# the list of signed headers and a base64-encoded signature.
|
||||
$HEADER_AUTHORIZATION = 'Authorization'
|
||||
|
||||
#Hash table to store singed headers
|
||||
$HttpSignedHeader = @{}
|
||||
$HttpSignedRequestHeader = @{ }
|
||||
$HttpSignatureHeader = @{ }
|
||||
$TargetHost = $UriBuilder.Host
|
||||
|
||||
#Check for Authentication type
|
||||
$apiKeyInfo = Get-PSAPIKeyInfo
|
||||
if ($null -eq $apiKeyInfo) {
|
||||
throw "Unable to reterieve the api key info "
|
||||
}
|
||||
|
||||
$httpSigningConfiguration = Get-PSConfigurationHttpSigning
|
||||
$Digest = $null
|
||||
|
||||
#get the body digest
|
||||
$bodyHash = Get-PSStringHash -String $Body
|
||||
$Digest = [String]::Format("SHA-256={0}", [Convert]::ToBase64String($bodyHash))
|
||||
|
||||
#get the date in UTC
|
||||
$bodyHash = Get-PSStringHash -String $Body -HashName $httpSigningConfiguration.HashAlgorithm
|
||||
if ($httpSigningConfiguration.HashAlgorithm -eq "SHA256") {
|
||||
$Digest = [String]::Format("SHA-256={0}", [Convert]::ToBase64String($bodyHash))
|
||||
}
|
||||
elseif ($httpSigningConfiguration.HashAlgorithm -eq "SHA512") {
|
||||
$Digest = [String]::Format("SHA-512={0}", [Convert]::ToBase64String($bodyHash))
|
||||
}
|
||||
|
||||
$dateTime = Get-Date
|
||||
#get the date in UTC
|
||||
$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)
|
||||
foreach ($headerItem in $httpSigningConfiguration.HttpSigningHeader) {
|
||||
|
||||
if ($headerItem -eq $HEADER_REQUEST_TARGET) {
|
||||
$requestTargetPath = [string]::Format("{0} {1}{2}", $Method.ToLower(), $UriBuilder.Path, $UriBuilder.Query)
|
||||
$HttpSignatureHeader.Add($HEADER_REQUEST_TARGET, $requestTargetPath)
|
||||
}
|
||||
elseif ($headerItem -eq $HEADER_CREATED) {
|
||||
$created = Get-PSUnixTime -Date $dateTime -TotalTime TotalSeconds
|
||||
$HttpSignatureHeader.Add($HEADER_CREATED, $created)
|
||||
}
|
||||
elseif ($headerItem -eq $HEADER_EXPIRES) {
|
||||
$expire = $dateTime.AddSeconds($httpSigningConfiguration.SignatureValidityPeriod)
|
||||
$expireEpocTime = Get-PSUnixTime -Date $expire -TotalTime TotalSeconds
|
||||
$HttpSignatureHeader.Add($HEADER_EXPIRES, $expireEpocTime)
|
||||
}
|
||||
elseif ($headerItem -eq $HEADER_HOST) {
|
||||
$HttpSignedRequestHeader[$HEADER_HOST] = $TargetHost
|
||||
$HttpSignatureHeader.Add($HEADER_HOST.ToLower(), $TargetHost)
|
||||
}
|
||||
elseif ($headerItem -eq $HEADER_DATE) {
|
||||
$HttpSignedRequestHeader[$HEADER_DATE] = $currentDate
|
||||
$HttpSignatureHeader.Add($HEADER_DATE.ToLower(), $currentDate)
|
||||
}
|
||||
elseif ($headerItem -eq $HEADER_DIGEST) {
|
||||
$HttpSignedRequestHeader[$HEADER_DIGEST] = $Digest
|
||||
$HttpSignatureHeader.Add($HEADER_DIGEST.ToLower(), $Digest)
|
||||
}elseif($RequestHeader.ContainsKey($headerItem)){
|
||||
$HttpSignatureHeader.Add($headerItem.ToLower(), $RequestHeader[$headerItem])
|
||||
}else{
|
||||
throw "Cannot sign HTTP request. Request does not contain the $headerItem header."
|
||||
}
|
||||
}
|
||||
|
||||
$stringToSign = [String]::Format("{0}`n{1}`n{2}`n{3}",
|
||||
$h_requestTarget,$h_cdate,
|
||||
$h_targetHost,$h_digest)
|
||||
# header's name separated by space
|
||||
$headersKeysString = $HttpSignatureHeader.Keys -join " "
|
||||
$headerValuesList = @()
|
||||
foreach ($item in $HttpSignatureHeader.GetEnumerator()) {
|
||||
$headerValuesList += [string]::Format("{0}: {1}", $item.Name, $item.Value)
|
||||
}
|
||||
#Concatinate headers value separated by new line
|
||||
$headerValuesString = $headerValuesList -join "`n"
|
||||
|
||||
$hashedString = Get-PSStringHash -String $stringToSign
|
||||
$signedHeader = Get-PSRSASHA256SignedString -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)
|
||||
#Gets the hash of the headers value
|
||||
$signatureHashString = Get-PSStringHash -String $headerValuesString -HashName $httpSigningConfiguration.HashAlgorithm
|
||||
|
||||
#Gets the Key type to select the correct signing alogorithm
|
||||
$KeyType = Get-PSKeyTypeFromFile -KeyFilePath $httpSigningConfiguration.KeyFilePath
|
||||
|
||||
if ($keyType -eq "RSA") {
|
||||
$headerSignatureStr = Get-PSRSASignature -PrivateKeyFilePath $httpSigningConfiguration.KeyFilePath `
|
||||
-DataToSign $signatureHashString `
|
||||
-HashAlgorithmName $httpSigningConfiguration.HashAlgorithm `
|
||||
-KeyPassPhrase $httpSigningConfiguration.KeyPassPhrase `
|
||||
-SigningAlgorithm $httpSigningConfiguration.SigningAlgorithm
|
||||
}
|
||||
elseif ($KeyType -eq "EC") {
|
||||
$headerSignatureStr = Get-PSECDSASignature -ECKeyFilePath $httpSigningConfiguration.KeyFilePath `
|
||||
-DataToSign $signatureHashString `
|
||||
-HashAlgorithmName $httpSigningConfiguration.HashAlgorithm `
|
||||
-KeyPassPhrase $httpSigningConfiguration.KeyPassPhrase
|
||||
}
|
||||
#Depricated
|
||||
<#$cryptographicScheme = Get-PSCryptographicScheme -SigningAlgorithm $httpSigningConfiguration.SigningAlgorithm `
|
||||
-HashAlgorithm $httpSigningConfiguration.HashAlgorithm
|
||||
#>
|
||||
$cryptographicScheme = "hs2019"
|
||||
$authorizationHeaderValue = [string]::Format("Signature keyId=""{0}"",algorithm=""{1}""",
|
||||
$httpSigningConfiguration.KeyId, $cryptographicScheme)
|
||||
|
||||
if ($HttpSignatureHeader.ContainsKey($HEADER_CREATED)) {
|
||||
$authorizationHeaderValue += [string]::Format(",created={0}", $HttpSignatureHeader[$HEADER_CREATED])
|
||||
}
|
||||
|
||||
if ($HttpSignatureHeader.ContainsKey($HEADER_EXPIRES)) {
|
||||
$authorizationHeaderValue += [string]::Format(",expires={0}", $HttpSignatureHeader[$HEADER_EXPIRES])
|
||||
}
|
||||
|
||||
$HttpSignedHeader["Date"] = $currentDate
|
||||
$HttpSignedHeader["Host"] = $TargetHost
|
||||
$HttpSignedHeader["Content-Type"] = "application/json"
|
||||
$HttpSignedHeader["Digest"] = $Digest
|
||||
$HttpSignedHeader["Authorization"] = $authorizationHeader
|
||||
return $HttpSignedHeader
|
||||
$authorizationHeaderValue += [string]::Format(",headers=""{0}"",signature=""{1}""",
|
||||
$headersKeysString , $headerSignatureStr)
|
||||
|
||||
$HttpSignedRequestHeader[$HEADER_AUTHORIZATION] = $authorizationHeaderValue
|
||||
return $HttpSignedRequestHeader
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gets the headers for http signed auth.
|
||||
Gets the RSA signature
|
||||
|
||||
.DESCRIPTION
|
||||
Gets the headers for the http signed auth. It use (targetpath), date, host and body digest to create authorization header.
|
||||
.PARAMETER APIKeyFilePath
|
||||
Gets the RSA signature for the http signing
|
||||
.PARAMETER PrivateKeyFilePath
|
||||
Specify the API key file path
|
||||
.PARAMETER DataToSign
|
||||
Specify the data to sign
|
||||
.PARAMETER HashAlgorithmName
|
||||
HashAlgorithm to calculate the hash
|
||||
.PARAMETER KeyPassPhrase
|
||||
KeyPassPhrase for the encrypted key
|
||||
.OUTPUTS
|
||||
String
|
||||
Base64String
|
||||
#>
|
||||
function Get-PSRSASHA256SignedString {
|
||||
function Get-PSRSASignature {
|
||||
Param(
|
||||
[string]$APIKeyFilePath,
|
||||
[byte[]]$DataToSign
|
||||
[string]$PrivateKeyFilePath,
|
||||
[byte[]]$DataToSign,
|
||||
[string]$HashAlgorithmName,
|
||||
[string]$SigningAlgorithm,
|
||||
[securestring]$KeyPassPhrase
|
||||
)
|
||||
try {
|
||||
|
||||
$rsa_provider_path = Join-Path -Path $PSScriptRoot -ChildPath "PSRSAEncryptionProvider.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"
|
||||
if ($hashAlgorithmName -eq "sha256") {
|
||||
$hashAlgo = [System.Security.Cryptography.HashAlgorithmName]::SHA256
|
||||
}
|
||||
return $signed_string
|
||||
elseif ($hashAlgorithmName -eq "sha512") {
|
||||
$hashAlgo = [System.Security.Cryptography.HashAlgorithmName]::SHA512
|
||||
}
|
||||
|
||||
if ($PSVersionTable.PSVersion.Major -ge 7) {
|
||||
$ecKeyHeader = "-----BEGIN RSA PRIVATE KEY-----"
|
||||
$ecKeyFooter = "-----END RSA PRIVATE KEY-----"
|
||||
$keyStr = Get-Content -Path $PrivateKeyFilePath -Raw
|
||||
$ecKeyBase64String = $keyStr.Replace($ecKeyHeader, "").Replace($ecKeyFooter, "").Trim()
|
||||
$keyBytes = [System.Convert]::FromBase64String($ecKeyBase64String)
|
||||
$rsa = [System.Security.Cryptography.RSACng]::new()
|
||||
[int]$bytCount = 0
|
||||
$rsa.ImportRSAPrivateKey($keyBytes, [ref] $bytCount)
|
||||
|
||||
if ($SigningAlgorithm -eq "RSASSA-PSS") {
|
||||
$signedBytes = $rsa.SignHash($DataToSign, $hashAlgo, [System.Security.Cryptography.RSASignaturePadding]::Pss)
|
||||
}
|
||||
else {
|
||||
$signedBytes = $rsa.SignHash($DataToSign, $hashAlgo, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)
|
||||
}
|
||||
}
|
||||
else {
|
||||
$rsa_provider_path = Join-Path -Path $PSScriptRoot -ChildPath "PSRSAEncryptionProvider.cs"
|
||||
$rsa_provider_sourceCode = Get-Content -Path $rsa_provider_path -Raw
|
||||
Add-Type -TypeDefinition $rsa_provider_sourceCode
|
||||
|
||||
[System.Security.Cryptography.RSA]$rsa = [RSAEncryption.RSAEncryptionProvider]::GetRSAProviderFromPemFile($PrivateKeyFilePath, $KeyPassPhrase)
|
||||
|
||||
if ($SigningAlgorithm -eq "RSASSA-PSS") {
|
||||
throw "$SigningAlgorithm is not supported on $($PSVersionTable.PSVersion)"
|
||||
}
|
||||
else {
|
||||
$signedBytes = $rsa.SignHash($DataToSign, $hashAlgo, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$signedString = [Convert]::ToBase64String($signedBytes)
|
||||
return $signedString
|
||||
}
|
||||
catch {
|
||||
throw $_
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Gets the ECDSA signature
|
||||
|
||||
.DESCRIPTION
|
||||
Gets the ECDSA signature for the http signing
|
||||
.PARAMETER PrivateKeyFilePath
|
||||
Specify the API key file path
|
||||
.PARAMETER DataToSign
|
||||
Specify the data to sign
|
||||
.PARAMETER HashAlgorithmName
|
||||
HashAlgorithm to calculate the hash
|
||||
.PARAMETER KeyPassPhrase
|
||||
KeyPassPhrase for the encrypted key
|
||||
.OUTPUTS
|
||||
Base64String
|
||||
#>
|
||||
function Get-PSECDSASignature {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ECKeyFilePath,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[byte[]]$DataToSign,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[String]$HashAlgorithmName,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[securestring]$KeyPassPhrase
|
||||
)
|
||||
if (!(Test-Path -Path $ECKeyFilePath)) {
|
||||
throw "key file path does not exist."
|
||||
}
|
||||
|
||||
if($PSVersionTable.PSVersion.Major -lt 7){
|
||||
throw "ECDSA key is not supported on $($PSVersionTable.PSVersion), Use PSVersion 7.0 and above"
|
||||
}
|
||||
|
||||
$ecKeyHeader = "-----BEGIN EC PRIVATE KEY-----"
|
||||
$ecKeyFooter = "-----END EC PRIVATE KEY-----"
|
||||
$keyStr = Get-Content -Path $ECKeyFilePath -Raw
|
||||
$ecKeyBase64String = $keyStr.Replace($ecKeyHeader, "").Replace($ecKeyFooter, "").Trim()
|
||||
$keyBytes = [System.Convert]::FromBase64String($ecKeyBase64String)
|
||||
|
||||
#$cngKey = [System.Security.Cryptography.CngKey]::Import($keyBytes,[System.Security.Cryptography.CngKeyBlobFormat]::Pkcs8PrivateBlob)
|
||||
#$ecdsa = [System.Security.Cryptography.ECDsaCng]::New($cngKey)
|
||||
$ecdsa = [System.Security.Cryptography.ECDsaCng]::New()
|
||||
[int]$bytCount =0
|
||||
if(![string]::IsNullOrEmpty($KeyPassPhrase)){
|
||||
$ecdsa.ImportEncryptedPkcs8PrivateKey($KeyPassPhrase,$keyBytes,[ref]$bytCount)
|
||||
}
|
||||
else{
|
||||
$ecdsa.ImportPkcs8PrivateKey($keyBytes,[ref]$bytCount)
|
||||
}
|
||||
|
||||
if ($HashAlgorithmName -eq "sha512") {
|
||||
$ecdsa.HashAlgorithm = [System.Security.Cryptography.CngAlgorithm]::Sha512
|
||||
}
|
||||
else {
|
||||
$ecdsa.HashAlgorithm = [System.Security.Cryptography.CngAlgorithm]::Sha256
|
||||
}
|
||||
|
||||
$signedBytes = $ecdsa.SignHash($DataToSign)
|
||||
$signedString = [System.Convert]::ToBase64String($signedBytes)
|
||||
return $signedString
|
||||
|
||||
}
|
||||
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Gets the hash of string.
|
||||
.Description
|
||||
Gets the hash of string
|
||||
.Parameter String
|
||||
Specifies the string to calculate the hash
|
||||
.Parameter HashName
|
||||
Specifies the hash name to calculate the hash, Accepted values are "SHA1", "SHA256" and "SHA512"
|
||||
It is recommneded not to use "SHA1" to calculate the Hash
|
||||
.Outputs
|
||||
String
|
||||
#>
|
||||
Function Get-PSStringHash([String] $String, $HashName = "SHA256") {
|
||||
|
||||
Function Get-PSStringHash {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[AllowEmptyString()]
|
||||
[string]$String,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[ValidateSet("SHA1", "SHA256", "SHA512")]
|
||||
$HashName
|
||||
)
|
||||
$hashAlogrithm = [System.Security.Cryptography.HashAlgorithm]::Create($HashName)
|
||||
$hashAlogrithm.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($String))
|
||||
}
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Gets the Unix time.
|
||||
.Description
|
||||
Gets the Unix time
|
||||
.Parameter Date
|
||||
Specifies the date to calculate the unix time
|
||||
.Parameter ToTalTime
|
||||
Specifies the total time , Accepted values are "TotalDays", "TotalHours", "TotalMinutes", "TotalSeconds" and "TotalMilliseconds"
|
||||
.Outputs
|
||||
Integer
|
||||
#>
|
||||
function Get-PSUnixTime {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[DateTime]$Date,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateSet("TotalDays", "TotalHours", "TotalMinutes", "TotalSeconds", "TotalMilliseconds")]
|
||||
[string]$TotalTime = "TotalSeconds"
|
||||
)
|
||||
$date1 = Get-Date -Date "01/01/1970"
|
||||
$timespan = New-TimeSpan -Start $date1 -End $Date
|
||||
switch ($TotalTime) {
|
||||
"TotalDays" { [int]$timespan.TotalDays }
|
||||
"TotalHours" { [int]$timespan.TotalHours }
|
||||
"TotalMinutes" { [int]$timespan.TotalMinutes }
|
||||
"TotalSeconds" { [int]$timespan.TotalSeconds }
|
||||
"TotalMilliseconds" { [int]$timespan.TotalMilliseconds }
|
||||
}
|
||||
}
|
||||
|
||||
function Get-PSCryptographicScheme {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SigningAlgorithm,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$HashAlgorithm
|
||||
)
|
||||
$rsaSigntureType = @("RSASSA-PKCS1-v1_5", "RSASSA-PSS")
|
||||
$SigningAlgorithm = $null
|
||||
if ($rsaSigntureType -contains $SigningAlgorithm) {
|
||||
switch ($HashAlgorithm) {
|
||||
"sha256" { $SigningAlgorithm = "rsa-sha256" }
|
||||
"sha512" { $SigningAlgorithm = "rsa-sha512" }
|
||||
}
|
||||
}
|
||||
return $SigningAlgorithm
|
||||
}
|
||||
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Gets the key type from the pem file.
|
||||
.Description
|
||||
Gets the key type from the pem file.
|
||||
.Parameter KeyFilePath
|
||||
Specifies the key file path (pem file)
|
||||
.Outputs
|
||||
String
|
||||
#>
|
||||
function Get-PSKeyTypeFromFile {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$KeyFilePath
|
||||
)
|
||||
|
||||
if (-not(Test-Path -Path $KeyFilePath)) {
|
||||
throw "Key file path does not exist."
|
||||
}
|
||||
$ecPrivateKeyHeader = "BEGIN EC PRIVATE KEY"
|
||||
$ecPrivateKeyFooter = "END EC PRIVATE KEY"
|
||||
$rsaPrivateKeyHeader = "BEGIN RSA PRIVATE KEY"
|
||||
$rsaPrivateFooter = "END RSA PRIVATE KEY"
|
||||
$pkcs8Header = "BEGIN PRIVATE KEY"
|
||||
$pkcs8Footer = "END PRIVATE KEY"
|
||||
$keyType = $null
|
||||
$key = Get-Content -Path $KeyFilePath
|
||||
|
||||
if ($key[0] -match $rsaPrivateKeyHeader -and $key[$key.Length - 1] -match $rsaPrivateFooter) {
|
||||
$KeyType = "RSA"
|
||||
|
||||
}
|
||||
elseif ($key[0] -match $ecPrivateKeyHeader -and $key[$key.Length - 1] -match $ecPrivateKeyFooter) {
|
||||
$keyType = "EC"
|
||||
}
|
||||
elseif ($key[0] -match $ecPrivateKeyHeader -and $key[$key.Length - 1] -match $ecPrivateKeyFooter) {
|
||||
<#this type of key can hold many type different types of private key, but here due lack of pem header
|
||||
Considering this as EC key
|
||||
#>
|
||||
#TODO :- update the key based on oid
|
||||
$keyType = "EC"
|
||||
}
|
||||
else {
|
||||
throw "Either the key is invalid or key is not supported"
|
||||
}
|
||||
return $keyType
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Cryptography;
|
||||
@@ -10,15 +11,97 @@ namespace RSAEncryption
|
||||
{
|
||||
public class RSAEncryptionProvider
|
||||
{
|
||||
public static RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile,SecureString keyPassPharse = null)
|
||||
{
|
||||
const String pempubheader = "-----BEGIN PUBLIC KEY-----";
|
||||
const String pempubfooter = "-----END PUBLIC KEY-----";
|
||||
bool isPrivateKeyFile = true;
|
||||
byte[] pemkey = null;
|
||||
|
||||
if (!File.Exists(pemfile))
|
||||
{
|
||||
throw new Exception("private key file does not exist.");
|
||||
}
|
||||
string pemstr = File.ReadAllText(pemfile).Trim();
|
||||
|
||||
if (pemstr.StartsWith(pempubheader) && pemstr.EndsWith(pempubfooter))
|
||||
{
|
||||
isPrivateKeyFile = false;
|
||||
}
|
||||
|
||||
if (isPrivateKeyFile)
|
||||
{
|
||||
pemkey = ConvertPrivateKeyToBytes(pemstr,keyPassPharse);
|
||||
if (pemkey == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return DecodeRSAPrivateKey(pemkey);
|
||||
}
|
||||
return null ;
|
||||
}
|
||||
|
||||
static byte[] ConvertPrivateKeyToBytes(String instr, SecureString keyPassPharse = null)
|
||||
{
|
||||
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, "");
|
||||
sb.Replace(pemprivfooter, "");
|
||||
String pvkstr = sb.ToString().Trim();
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{ //data is not in base64 fromat
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] deskey = GetEncryptedKey(salt, keyPassPharse, 1, 2); // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes
|
||||
if (deskey == null)
|
||||
return null;
|
||||
|
||||
//------ 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
|
||||
return rsakey;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -46,7 +129,6 @@ namespace RSAEncryption
|
||||
if (bt != 0x00)
|
||||
return null;
|
||||
|
||||
|
||||
//------ all private key components are Integer sequences ----
|
||||
elems = GetIntegerSize(binr);
|
||||
MODULUS = binr.ReadBytes(elems);
|
||||
@@ -72,19 +154,6 @@ namespace RSAEncryption
|
||||
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();
|
||||
@@ -140,94 +209,17 @@ namespace RSAEncryption
|
||||
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)
|
||||
static byte[] GetEncryptedKey(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
|
||||
@@ -248,15 +240,12 @@ namespace RSAEncryption
|
||||
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);
|
||||
|
||||
@@ -265,46 +254,9 @@ namespace RSAEncryption
|
||||
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();
|
||||
@@ -317,61 +269,11 @@ namespace RSAEncryption
|
||||
cs.Write(cipherData, 0, cipherData.Length);
|
||||
cs.Close();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
Console.WriteLine(exc.Message);
|
||||
catch (Exception){
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user