Friday, April 19, 2024
HomePowershellGerando chaves SSH apenas com o Powershell

Gerando chaves SSH apenas com o Powershell


Olá pessoal,

Recentemente encontrei um projeto no github que usava apenas o C# e o .web para gerar uma chave SSH (publica e privada). O projeto se chama SshKeyGenerator e achei bem interessante a abordagem, e resolvi portar isso para powershell usando Courses e uma funcão (cmdlet) para encapsular a chamada. O objetivo dele é nos ajudar gerando chaves ssh de maneira que não tenha dependência de executáveis externos, que muitas vezes se torna um problema quando estamos em contextos de automação, por exemplo dentro de um container.

O projeto usa o RSACryptoServiceProvider para gerar a chave e converter para os valores adequados.

A função foi escrita de maneira que uma vez em memória, as chaves possam ser geradas com apenas uma linha:

Retrieve enter parameter default values for the 'path/to/workflow' workflow.
New-SSHRSAKey -KeySize 2048 -Remark 'guido.oliveira' -OutputType Base64

Retrieve enter parameter default values for the 'path/to/workflow' workflow.
New-SSHRSAKey -KeySize 2048 -Remark 'ssh.check' -OutputType File

Retrieve enter parameter default values for the 'path/to/workflow' workflow.
New-SSHRSAKey -KeySize 2048 -Remark 'ssh.check' -OutputType File -FilePath 'path/to/file'

Retrieve enter parameter default values for the 'path/to/workflow' workflow.
New-SSHRSAKey -KeySize 2048 -Remark 'guido.oliveira' -OutputType Base64

A classe em powershell ficou da seguinte maneira:

class SshKeyGenerator : System.IDisposable {
    hidden [System.Security.Cryptography.RSACryptoServiceProvider]$csp

    SshKeyGenerator([int] $keySize) {
        $this.csp =[System.Security.Cryptography.RSACryptoServiceProvider]::new($keySize)
    }
    # Returns the personal key in x509 format
    [string] ToPrivateKey() {
        if ($this.csp.PublicOnly) {
            #throw new ArgumentException("CSP doesn't comprise a personal key", nameof($this.csp));
        } 
        $parameters = $this.csp.ExportParameters($true);
        $stream = [System.IO.MemoryStream]::new()
        $author = [System.IO.BinaryWriter]::new($stream)
        $author.Write([byte]0x30)
        $innerStream = [System.IO.MemoryStream]::new()
                    
        $innerWriter = [System.IO.BinaryWriter]::new($innerStream)
        $this.EncodeIntegerBigEndian($innerWriter, [byte[]]::new(0x00), $true) # Model
        $this.EncodeIntegerBigEndian($innerWriter, $parameters.Modulus, $true)
        $this.EncodeIntegerBigEndian($innerWriter, $parameters.Exponent, $true)
        $this.EncodeIntegerBigEndian($innerWriter, $parameters.D, $true)
        $this.EncodeIntegerBigEndian($innerWriter, $parameters.P, $true)
        $this.EncodeIntegerBigEndian($innerWriter, $parameters.Q, $true)
        $this.EncodeIntegerBigEndian($innerWriter, $parameters.DP, $true)
        $this.EncodeIntegerBigEndian($innerWriter, $parameters.DQ, $true)
        $this.EncodeIntegerBigEndian($innerWriter, $parameters.InverseQ, $true)
        $size = [int]$innerStream.Size
        $this.EncodeLength($author, $size)
        $author.Write($innerStream.GetBuffer(), 0, $size)
        $innerStream.Dispose()    

        $base64 = [System.Convert]::ToBase64String($stream.GetBuffer(), 0, [int]$stream.Size).ToCharArray();
        $outputStream = [System.IO.StringWriter]::new()
            
        $outputStream.WriteLine("-----BEGIN RSA PRIVATE KEY-----")
        # Output as Base64 with strains chopped at 64 characters
        for ($i = 0; $i -lt $base64.Size; $i += 64) {
            $outputStream.WriteLine($base64, $i, [System.Math]::Min(64, $base64.Size - $i))
        }
        $outputStream.WriteLine("-----END RSA PRIVATE KEY-----")
        return $outputStream.ToString()
        $outputStream.Dispose()
        $stream.Dispose()
    }
    # Export blobs to save lots of or import immediately into one other CSP object
    [byte[]] ToBlobs([bool] $includePrivateKey) {
        return $this.csp.ExportCspBlob($includePrivateKey);
    }
    # Export blobs in base64 format to save lots of or import immediately into one other CSP object
    [string] ToB64Blob([bool] $includePrivateKey) {
        return [System.Convert]::ToBase64String($this.ToBlobs($includePrivateKey));
    }
    # Export Csp as XML string. This XML accommodates each personal key and public key (P and Q).
    [string] ToXml() {
        return $this.csp.ToXmlString($true);
    }
    # Returns the SSH public key in RFC4716 format
    [string] ToRfcPublicKey([string] $remark) {
        [byte[]] $sshrsaBytes = [System.Text.Encoding]::Default.GetBytes('ssh-rsa')
        [byte[]] $n = $this.csp.ExportParameters($false).Modulus;
        [byte[]] $e = $this.csp.ExportParameters($false).Exponent;
        [string] $buffer64 = ''
        [System.IO.MemoryStream] $ms = [System.IO.MemoryStream]::new()
        
        $ms.Write($this.ToBytes($sshrsaBytes.Size), 0, 4)
        $ms.Write($sshrsaBytes, 0, $sshrsaBytes.Size)
        $ms.Write($this.ToBytes($e.Size), 0, 4)
        $ms.Write($e, 0, $e.Size)
        $ms.Write($this.ToBytes($n.Size + 1), 0, 4) # Take away the +1 if not Emulating Putty Gen
        #$ms.Write(new byte[] {0}, 0, 1) # Add a 0 to Emulate PuttyGen
        $ms.Write( [byte[]]$(0, 0, 1) ) # Add a 0 to Emulate PuttyGen
        $ms.Write($n, 0, $n.Size)
        $ms.Flush()
        $buffer64 = [System.Convert]::ToBase64String($ms.ToArray())
        
        $ms.Dispose()
        return "ssh-rsa $buffer64 $remark"
    }
    # Returns the SSH public key in RFC4716 format
    [string] ToRfcPublicKey() { 
        return $this.ToRfcPublicKey("generated-key")
    }
    # Returns the SSH public key in x509 format
    [string] ToPublicKey() {
        $parameters = $this.csp.ExportParameters($false)
        $stream = [System.IO.MemoryStream]::new()
            
        $author =  [System.IO.BinaryWriter]::new($stream)
        $author.Write([byte]0x30) # SEQUENCE

        $innerStream = [System.IO.MemoryStream]::new()
                
        $innerWriter = [System.IO.BinaryWriter]::new($innerStream)
        $innerWriter.Write([byte]0x30) # SEQUENCE
        $this.EncodeLength($innerWriter, 13)
        $innerWriter.Write([byte]0x06) # OBJECT IDENTIFIER
        $rsaEncryptionOid = [byte[]]$(0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01)
        $this.EncodeLength($innerWriter, $rsaEncryptionOid.Size)
        $innerWriter.Write($rsaEncryptionOid)
        $innerWriter.Write([byte]0x05) # NULL
        $this.EncodeLength($innerWriter, 0)
        $innerWriter.Write([byte] 0x03) # BIT STRING

        $bitStringStream = [System.IO.MemoryStream]::new()
        $bitStringWriter = [System.IO.BinaryWriter]::new($bitStringStream)
        $bitStringWriter.Write([byte]0x00) # of unused bits
        $bitStringWriter.Write([byte]0x30) # SEQUENCE
        $paramsStream = [System.IO.MemoryStream]::new()
                
        $paramsWriter = [System.IO.BinaryWriter]::new($paramsStream)
        $this.EncodeIntegerBigEndian($paramsWriter, $parameters.Modulus, $true) # Modulus
        $this.EncodeIntegerBigEndian($paramsWriter, $parameters.Exponent, $true) # Exponent
        $paramsLength = [int]$paramsStream.Size
        $this.EncodeLength($bitStringWriter, $paramsLength)
        $bitStringWriter.Write($paramsStream.GetBuffer(), 0, $paramsLength)
        
        $paramsStream.Dispose()
        $bitStringLength = [int]$bitStringStream.Size
        $this.EncodeLength($innerWriter, $bitStringLength)
        $innerWriter.Write($bitStringStream.GetBuffer(), 0, $bitStringLength)
            
        $bitStringStream.Dispose()
        $size = [int]$innerStream.Size
        $this.EncodeLength($author, $size)
        $author.Write($innerStream.GetBuffer(), 0, $size);
        $innerStream.Dispose()

        $base64 = [System.Convert]::ToBase64String($stream.GetBuffer(), 0, [int]$stream.Size).ToCharArray()
        $outputStream = [System.IO.StringWriter]::new()
            
        $outputStream.WriteLine("-----BEGIN PUBLIC KEY-----")
        for ($i = 0; $i -lt $base64.Size; $i += 64) {
            $outputStream.WriteLine($base64, $i, [System.Math]::Min(64, $base64.Size - $i))
        }

        $outputStream.WriteLine("-----END PUBLIC KEY-----")

        return $outputStream.ToString()
            
        $outputStream.Dispose()
        $stream.Dispose()
    }
    hidden [void] EncodeLength([System.IO.BinaryWriter]$stream, [int]$size) {
        if ($size -lt 0) {
            #throw new ArgumentOutOfRangeException(nameof(size), "Size should be non-negative")
            throw [System.ArgumentOutOfRangeException]::new("Size should be non-negative")
        }
        if ($size -lt 0x80) {
            # Brief type
            $stream.Write([byte] $size)
        } else {
            # Lengthy type
            $temp = $size
            $bytesRequired = 0
            whereas ($temp > 0) {
                $temp -shr 8
                $bytesRequired++
            }
            $stream.Write([byte] ($bytesRequired -bor 0x80))
            for ($i = $bytesRequired - 1; $i -ge 0; $i--) {
                $stream.Write([byte] ($size -shr (8 * $i) -band 0xff))
            }
        }
    }
    hidden [void] EncodeIntegerBigEndian([System.IO.BinaryWriter] $stream, [byte[]] $worth, [bool] $forceUnsigned = $true) {
        $stream.Write([byte] 0x02) # INTEGER
        $prefixZeros = 0
        for ($i = 0; $i -lt $worth.Size; $i++) {
            if ($worth[$i] -ne 0) { break }
            $prefixZeros++
        }

        if ($worth.Size - $prefixZeros -eq 0) {
            $this.EncodeLength($stream, 1)
            $stream.Write([byte] 0)
        } else {
            if ($forceUnsigned -and $worth[$prefixZeros] -gt 0x7f) {
                # Add a prefix zero to pressure unsigned if the MSB is 1
                $this.EncodeLength($stream, $worth.Size - $prefixZeros + 1)
                $stream.Write([byte]0)
            } else {
                $this.EncodeLength($stream, $worth.Size - $prefixZeros)
            }

            for ($i = $prefixZeros; $i -lt $worth.Size; $i++) {
                $stream.Write($worth[$i])
            }
        }
    }
    hidden [byte[]] ToBytes([int] $i) {
        [byte[]] $bts = [System.BitConverter]::GetBytes($i)
        if ([System.BitConverter]::IsLittleEndian) {
            [Array]::Reverse($bts)
        }

        return $bts
    }
    [void] Dispose() {
        $this.Dispose($true);
        [System.GC]::SuppressFinalize($this)
    }
    hidden [void] Dispose([bool]$disposing) {
        if ($disposing) {
            $this.csp?.Dispose()
        }
    }
}

A funcão que escrevi para fazer as chamadas a classe ficou da seguinte forma:

perform New-SSHRSAKey {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, Position = 0, HelpMessage = "The size of the key to generate, 1024, 2048 or 4096")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [ValidateSet("1024", "2048", "4096")]
        [int]$KeySize,
        [Parameter(Mandatory = $false, Position = 1, HelpMessage = "The Comment to use for the public key, defaults to ssh-key")]
        [string]$Remark = 'ssh-key',
        [Parameter(Mandatory = $false, Position = 2, HelpMessage = "Output Type of the command, defaults to Object")]
        [ValidateSet('File', 'XML', 'Base64', 'Blob', 'Object')]
        [string]$OutputType = 'Object'
    )
    DynamicParam {
        if ($OutputType -eq 'File') {
            $SegmentAttribute = New-Object -TypeName System.Administration.Automation.ParameterAttribute -Property @{
                Place    = 3
                Necessary   = $false
                HelpMessage = ('The entire File Path with out extension to the file to , defaults to {0}.sshid_rsa - {1}' -f $HOME, $Remark)
            }
            #create an attributecollection object for the attribute we simply created.
            $attributeCollection = New-Object -TypeName System.Collections.ObjectModel.Assortment[System.Attribute]
 
            #add our customized attribute
            $attributeCollection.Add($SegmentAttribute)
 
            #add our paramater specifying the attribute assortment
            $SegmentParameter = New-Object System.Administration.Automation.RuntimeDefinedParameter('FilePath', [String], $attributeCollection)
 
            #expose the identify of our parameter
            $paramDictionary = New-Object System.Administration.Automation.RuntimeDefinedParameterDictionary
            $paramDictionary.Add('FilePath', $SegmentParameter)
            return $paramDictionary
        }
    }
    start {
        class SshKeyGenerator : System.IDisposable {
            hidden [System.Security.Cryptography.RSACryptoServiceProvider]$csp
        
            SshKeyGenerator([int] $keySize) {
                $this.csp =[System.Security.Cryptography.RSACryptoServiceProvider]::new($keySize)
            }
            # Returns the personal key in x509 format
            [string] ToPrivateKey() {
                if ($this.csp.PublicOnly) {
                    #throw new ArgumentException("CSP doesn't comprise a personal key", nameof($this.csp));
                } 
                $parameters = $this.csp.ExportParameters($true);
                $stream = [System.IO.MemoryStream]::new()
                $author = [System.IO.BinaryWriter]::new($stream)
                $author.Write([byte]0x30)
                $innerStream = [System.IO.MemoryStream]::new()
                            
                $innerWriter = [System.IO.BinaryWriter]::new($innerStream)
                $this.EncodeIntegerBigEndian($innerWriter, [byte[]]::new(0x00), $true) # Model
                $this.EncodeIntegerBigEndian($innerWriter, $parameters.Modulus, $true)
                $this.EncodeIntegerBigEndian($innerWriter, $parameters.Exponent, $true)
                $this.EncodeIntegerBigEndian($innerWriter, $parameters.D, $true)
                $this.EncodeIntegerBigEndian($innerWriter, $parameters.P, $true)
                $this.EncodeIntegerBigEndian($innerWriter, $parameters.Q, $true)
                $this.EncodeIntegerBigEndian($innerWriter, $parameters.DP, $true)
                $this.EncodeIntegerBigEndian($innerWriter, $parameters.DQ, $true)
                $this.EncodeIntegerBigEndian($innerWriter, $parameters.InverseQ, $true)
                $size = [int]$innerStream.Size
                $this.EncodeLength($author, $size)
                $author.Write($innerStream.GetBuffer(), 0, $size)
                $innerStream.Dispose()    
        
                $base64 = [System.Convert]::ToBase64String($stream.GetBuffer(), 0, [int]$stream.Size).ToCharArray();
                $outputStream = [System.IO.StringWriter]::new()
                    
                $outputStream.WriteLine("-----BEGIN RSA PRIVATE KEY-----")
                # Output as Base64 with strains chopped at 64 characters
                for ($i = 0; $i -lt $base64.Size; $i += 64) {
                    $outputStream.WriteLine($base64, $i, [System.Math]::Min(64, $base64.Size - $i))
                }
                $outputStream.WriteLine("-----END RSA PRIVATE KEY-----")
                return $outputStream.ToString()
                $outputStream.Dispose()
                $stream.Dispose()
            }
            # Export blobs to save lots of or import immediately into one other CSP object
            [byte[]] ToBlobs([bool] $includePrivateKey) {
                return $this.csp.ExportCspBlob($includePrivateKey);
            }
            # Export blobs in base64 format to save lots of or import immediately into one other CSP object
            [string] ToB64Blob([bool] $includePrivateKey) {
                return [System.Convert]::ToBase64String($this.ToBlobs($includePrivateKey));
            }
            # Export Csp as XML string. This XML accommodates each personal key and public key (P and Q).
            [string] ToXml() {
                return $this.csp.ToXmlString($true);
            }
            # Returns the SSH public key in RFC4716 format
            [string] ToRfcPublicKey([string] $remark) {
                [byte[]] $sshrsaBytes = [System.Text.Encoding]::Default.GetBytes('ssh-rsa')
                [byte[]] $n = $this.csp.ExportParameters($false).Modulus;
                [byte[]] $e = $this.csp.ExportParameters($false).Exponent;
                [string] $buffer64 = ''
                [System.IO.MemoryStream] $ms = [System.IO.MemoryStream]::new()
                
                $ms.Write($this.ToBytes($sshrsaBytes.Size), 0, 4)
                $ms.Write($sshrsaBytes, 0, $sshrsaBytes.Size)
                $ms.Write($this.ToBytes($e.Size), 0, 4)
                $ms.Write($e, 0, $e.Size)
                $ms.Write($this.ToBytes($n.Size + 1), 0, 4) # Take away the +1 if not Emulating Putty Gen
                #$ms.Write(new byte[] {0}, 0, 1) # Add a 0 to Emulate PuttyGen
                $ms.Write( [byte[]]$(0, 0, 1) ) # Add a 0 to Emulate PuttyGen
                $ms.Write($n, 0, $n.Size)
                $ms.Flush()
                $buffer64 = [System.Convert]::ToBase64String($ms.ToArray())
                
                $ms.Dispose()
                return "ssh-rsa $buffer64 $remark"
            }
            # Returns the SSH public key in RFC4716 format
            [string] ToRfcPublicKey() { 
                return $this.ToRfcPublicKey("generated-key")
            }
            # Returns the SSH public key in x509 format
            [string] ToPublicKey() {
                $parameters = $this.csp.ExportParameters($false)
                $stream = [System.IO.MemoryStream]::new()
                    
                $author =  [System.IO.BinaryWriter]::new($stream)
                $author.Write([byte]0x30) # SEQUENCE
        
                $innerStream = [System.IO.MemoryStream]::new()
                        
                $innerWriter = [System.IO.BinaryWriter]::new($innerStream)
                $innerWriter.Write([byte]0x30) # SEQUENCE
                $this.EncodeLength($innerWriter, 13)
                $innerWriter.Write([byte]0x06) # OBJECT IDENTIFIER
                $rsaEncryptionOid = [byte[]]$(0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01)
                $this.EncodeLength($innerWriter, $rsaEncryptionOid.Size)
                $innerWriter.Write($rsaEncryptionOid)
                $innerWriter.Write([byte]0x05) # NULL
                $this.EncodeLength($innerWriter, 0)
                $innerWriter.Write([byte] 0x03) # BIT STRING
        
                $bitStringStream = [System.IO.MemoryStream]::new()
                $bitStringWriter = [System.IO.BinaryWriter]::new($bitStringStream)
                $bitStringWriter.Write([byte]0x00) # of unused bits
                $bitStringWriter.Write([byte]0x30) # SEQUENCE
                $paramsStream = [System.IO.MemoryStream]::new()
                        
                $paramsWriter = [System.IO.BinaryWriter]::new($paramsStream)
                $this.EncodeIntegerBigEndian($paramsWriter, $parameters.Modulus, $true) # Modulus
                $this.EncodeIntegerBigEndian($paramsWriter, $parameters.Exponent, $true) # Exponent
                $paramsLength = [int]$paramsStream.Size
                $this.EncodeLength($bitStringWriter, $paramsLength)
                $bitStringWriter.Write($paramsStream.GetBuffer(), 0, $paramsLength)
                
                $paramsStream.Dispose()
                $bitStringLength = [int]$bitStringStream.Size
                $this.EncodeLength($innerWriter, $bitStringLength)
                $innerWriter.Write($bitStringStream.GetBuffer(), 0, $bitStringLength)
                    
                $bitStringStream.Dispose()
                $size = [int]$innerStream.Size
                $this.EncodeLength($author, $size)
                $author.Write($innerStream.GetBuffer(), 0, $size);
                $innerStream.Dispose()
        
                $base64 = [System.Convert]::ToBase64String($stream.GetBuffer(), 0, [int]$stream.Size).ToCharArray()
                $outputStream = [System.IO.StringWriter]::new()
                    
                $outputStream.WriteLine("-----BEGIN PUBLIC KEY-----")
                for ($i = 0; $i -lt $base64.Size; $i += 64) {
                    $outputStream.WriteLine($base64, $i, [System.Math]::Min(64, $base64.Size - $i))
                }
        
                $outputStream.WriteLine("-----END PUBLIC KEY-----")
        
                return $outputStream.ToString()
                    
                $outputStream.Dispose()
                $stream.Dispose()
            }
            hidden [void] EncodeLength([System.IO.BinaryWriter]$stream, [int]$size) {
                if ($size -lt 0) {
                    #throw new ArgumentOutOfRangeException(nameof(size), "Size should be non-negative")
                    throw [System.ArgumentOutOfRangeException]::new("Size should be non-negative")
                }
                if ($size -lt 0x80) {
                    # Brief type
                    $stream.Write([byte] $size)
                } else {
                    # Lengthy type
                    $temp = $size
                    $bytesRequired = 0
                    whereas ($temp > 0) {
                        $temp -shr 8
                        $bytesRequired++
                    }
                    $stream.Write([byte] ($bytesRequired -bor 0x80))
                    for ($i = $bytesRequired - 1; $i -ge 0; $i--) {
                        $stream.Write([byte] ($size -shr (8 * $i) -band 0xff))
                    }
                }
            }
            hidden [void] EncodeIntegerBigEndian([System.IO.BinaryWriter] $stream, [byte[]] $worth, [bool] $forceUnsigned = $true) {
                $stream.Write([byte] 0x02) # INTEGER
                $prefixZeros = 0
                for ($i = 0; $i -lt $worth.Size; $i++) {
                    if ($worth[$i] -ne 0) { break }
                    $prefixZeros++
                }
        
                if ($worth.Size - $prefixZeros -eq 0) {
                    $this.EncodeLength($stream, 1)
                    $stream.Write([byte] 0)
                } else {
                    if ($forceUnsigned -and $worth[$prefixZeros] -gt 0x7f) {
                        # Add a prefix zero to pressure unsigned if the MSB is 1
                        $this.EncodeLength($stream, $worth.Size - $prefixZeros + 1)
                        $stream.Write([byte]0)
                    } else {
                        $this.EncodeLength($stream, $worth.Size - $prefixZeros)
                    }
        
                    for ($i = $prefixZeros; $i -lt $worth.Size; $i++) {
                        $stream.Write($worth[$i])
                    }
                }
            }
            hidden [byte[]] ToBytes([int] $i) {
                [byte[]] $bts = [System.BitConverter]::GetBytes($i)
                if ([System.BitConverter]::IsLittleEndian) {
                    [Array]::Reverse($bts)
                }
        
                return $bts
            }
            [void] Dispose() {
                $this.Dispose($true);
                [System.GC]::SuppressFinalize($this)
            }
            hidden [void] Dispose([bool]$disposing) {
                if ($disposing) {
                    $this.csp?.Dispose()
                }
            }
        }
        $sshkey = [SshKeyGenerator]::new($KeySize)
    }
    course of {
        change ($OutputType) {
            'File' {
                if ($FilePath) {
                    [void](New-Merchandise -Path $FilePath -ItemType File -Worth $sshkey.ToPrivateKey())
                    [void](New-Merchandise -Path "$FilePath.pub" -ItemType File -Worth $sshkey.ToRfcPublicKey($Remark))
                } else {
                    [void](New-Merchandise -Path (Be a part of-Path -Path $HOME -ChildPath .ssh) -Title "id_rsa - $Remark" -ItemType File -Worth $sshkey.ToPrivateKey())
                    [void](New-Merchandise -Path (Be a part of-Path -Path $HOME -ChildPath .ssh) -Title "id_rsa - $Remark.pub" -ItemType File -Worth $sshkey.ToRfcPublicKey($Remark))
                }
                return $sshkey.ToRfcPublicKey($Remark)
            }
            'XML' {
                return $sshkey.ToXml()
            }
            'Base64' {
                return $sshkey.ToB64Blob($true)
            }
            'Blob' {
                return $sshkey.ToBlobs($true)
            }
            Default {
                $obj =         [pscustomobject][ordered]@{
                    PublicKey    = $sshkey.ToPublicKey()
                    RfcPublicKey = $sshkey.ToRfcPublicKey($Remark)
                    PrivateKey   = $sshkey.ToPrivateKey()
                    XML          = $sshkey.ToXml()
                    Base64       = $sshkey.ToB64Blob($true)
                    Blob         = $sshkey.ToBlobs($true)
                }
                return $obj
            }
        }
    }
    finish {
        $sshkey.Dispose()
    }
}

Como a classe suporta varios tipos de tentei dar essa flexibilidade ao comando de forma simplificada.

Dúvidas? Sugestões? Comente!

Até a próxima!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments