Skip to content

Commit

Permalink
!deploy v0.2.0 - Added New-RSAKeyPair (#4)
Browse files Browse the repository at this point in the history
## 0.2.0 - 2019-08-10

* Added `New-RSAKeyPair` to enable generation of RSA PEM and SSH keys directly from PowerShell
  * Supports password protection keys
  * Defaults to 4096 key length
  * Offers an Interactive mode using the `-Interactive` or `-i` switch to simulate `ssh-keygen` experience
* Updated README with command comparisons between `openssl`, `ssh-keygen` and `New-RSAKeyPair`
  • Loading branch information
scrthq authored Aug 10, 2019
2 parents 9590c79 + 905e4b0 commit ef8185d
Show file tree
Hide file tree
Showing 13 changed files with 489 additions and 28 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -353,4 +353,5 @@ MigrationBackup/

# Repo specific
BuildOutput
Testing
!/PEMEncrypt/bin
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
* [PEMEncrypt - ChangeLog](#PEMEncrypt---ChangeLog)
* [PEMEncrypt - ChangeLog](#pemencrypt---changelog)
* [0.2.0 - 2019-08-10](#020---2019-08-10)
* [0.1.1 - 2019-07-07](#011---2019-07-07)
* [0.1.0 - 2019-07-07](#010---2019-07-07)

***

# PEMEncrypt - ChangeLog

## 0.2.0 - 2019-08-10

* Added `New-RSAKeyPair` to enable generation of RSA PEM and SSH keys directly from PowerShell
* Supports password protection keys
* Defaults to 4096 key length
* Offers an Interactive mode using the `-Interactive` or `-i` switch to simulate `ssh-keygen` experience
* Updated README with command comparisons between `openssl`, `ssh-keygen` and `New-RSAKeyPair`

## 0.1.1 - 2019-07-07

* Added CHANGELOG, CODE_OF_CONDUCT, CONTRIBUTING docs
Expand Down
7 changes: 4 additions & 3 deletions PEMEncrypt/PEMEncrypt.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
RootModule = 'PEMEncrypt.psm1'

# Version number of this module.
ModuleVersion = '0.1.1'
ModuleVersion = '0.2.0'

# Supported PSEditions
CompatiblePSEditions = @('Desktop','Core')
Expand All @@ -35,6 +35,7 @@ Description = 'A cross-platform PowerShell module handling string encryption and
# Minimum version of the PowerShell engine required by this module
PowerShellVersion = '5.1.0'


# Name of the PowerShell host required by this module
# PowerShellHostName = ''

Expand Down Expand Up @@ -78,7 +79,7 @@ FunctionsToExport = '*'
# VariablesToExport = '*'

# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
# AliasesToExport = @()
AliasesToExport = @('genrsa','genssh','genkey')

# DSC resources to export from this module
# DscResourcesToExport = @()
Expand All @@ -96,7 +97,7 @@ PrivateData = @{

# Tags applied to this module. These help with module discovery in online galleries.
Tags = @('PSEdition_Desktop', 'PSEdition_Core', 'Windows', 'MacOS', 'Linux', 'RSA',
'Crypto', 'Encrypt', 'Decrypt', 'PEM', 'Security')
'Crypto', 'Encrypt', 'Decrypt', 'PEM', 'ssh-keygen', 'openssl', 'SSH', 'Security')

# A URL to the license for this module.
# LicenseUri = ''
Expand Down
5 changes: 4 additions & 1 deletion PEMEncrypt/PEMEncrypt.psm1
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
# Base module contents
New-Alias -Name 'genrsa' -Value 'New-RSAKeyPair'
New-Alias -Name 'genssh' -Value 'New-RSAKeyPair'
New-Alias -Name 'genkey' -Value 'New-RSAKeyPair'
Export-ModuleMember -Alias @('genrsa','genssh','genkey')
13 changes: 13 additions & 0 deletions PEMEncrypt/Private/Get-DefaultPath.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
function Get-DefaultPath {
[CmdletBinding()]
Param()
Process {
$homePath = if ($HOME) {
$HOME
}
elseif (Test-Path "~") {
(Resolve-Path "~").Path
}
[System.IO.Path]::Combine($homePath,".ssh","id_rsa")
}
}
15 changes: 15 additions & 0 deletions PEMEncrypt/Private/Unprotect-SecureString.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
function Unprotect-SecureString {
[CmdletBinding()]
Param(
[Parameter(Mandatory,Position = 0)]
[SecureString]
$SecureString
)
Process {
[Runtime.InteropServices.Marshal]::PtrToStringAuto(
[Runtime.InteropServices.Marshal]::SecureStringToBSTR(
$SecureString
)
)
}
}
219 changes: 219 additions & 0 deletions PEMEncrypt/Public/New-RSAKeyPair.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
function New-RSAKeyPair {
<#
.SYNOPSIS
Generates an RSA PEM key pair and corresponding public SSH key.
.DESCRIPTION
Generates an RSA PEM key pair and corresponding public SSH key.
.PARAMETER Length
Alias: [-l,-b]
The bit-length of the key to generate. Defaults to 4096.
.PARAMETER Password
Alias: -p
A SecureString or plain-text String containing the password to encrypt the private key with. Exclude to create the private key without a password. For security, SecureString is recommended, although plain-text strings are allowed for broader compatibility.
.PARAMETER Path
Alias: -out
The path to save the private key to. Defaults to ~/.ssh/id_rsa
.PARAMETER Interactive
Alias: -i
If $true, prompt the user for the options to create the key with. Similar to creating a key with ssh-keygen.
.PARAMETER NoFile
Alias: -nof
If $true, do not save any keys to file. Sets PassThru to $true and returns the generated RSAKey object containing the PublicPEM, PublicSSH, and PrivatePEM as string properties.
.PARAMETER NoSSH
Alias: -nos
If $true, do not save the SSH key to file. Use when only the RSA PEM key pair is needed.
.PARAMETER NoPEM
Alias: -nop
If $true, do not save the Public PEM key to file. Use when only the SSH key pair is needed.
.PARAMETER PassThru
Alias: -pt
Returns the generated RSAKey object containing the PublicPEM, PublicSSH, and PrivatePEM as string properties.
.PARAMETER Force
Alias: -f
If the keys at the file path already exist, overwrite them.
.EXAMPLE
New-RSAKeyPair -Interactive
Generating public/private RSA key pair...
Enter the path to save the key to (Default: C:\Users\nate\.ssh\id_rsa): .\Testing\id_pemencrypt
Enter desired key length (Default: 4096):
Enter passphrase (Default: No passphrase):
Saving private key to path : .\Testing\id_pemencrypt
Saving public SSH key to path : .\Testing\id_pemencrypt.pub
Saving public PEM key to path : .\Testing\id_pemencrypt.pem
.EXAMPLE
New-RSAKeyPair -NoFile
PublicPEM
---------
-----BEGIN PUBLIC KEY-----...
.EXAMPLE
New-RSAKeyPair -Length 1024 -NoFile | Select-Object -ExpandProperty PublicSSH
ssh-rsa AAAAB3NzaC1yc2EAAAABAwAAAIEAo2CDoZRSy7JDJbX3ygsj3L09rMxq+46lMkWv6K33Cng3y4DokqqyUc2KCzhspBViGzVl3mJ+Y4S9O+D4bktcSDRZbEmZ0cVsFZFEAI17iEKnZHZnaqMIoIzaK2TS0rnQbkYpSDfKUAZtwSNiWB0TfMFdnOY6UJdlfLGzPeFJWTU= PEMEncrypt@User@Computer
.EXAMPLE
New-RSAKeyPair
Key already exists at desired path: C:\Users\nate\.ssh\id_rsa. Use -Force to overwrite the existing key or choose a different path.
At E:\Git\PEMEncrypt\BuildOutput\PEMEncrypt\0.2.0\PEMEncrypt.psm1:177 char:21
+ ... throw "Key already exists at desired path: $Path. Use -Fo ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Key already exists \u2026e a different path.:String) [], RuntimeException
+ FullyQualifiedErrorId : Key already exists at desired path: C:\Users\nate\.ssh\id_rsa. Use -Force to overwrite the existing key or choose a different path.
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingPlainTextForPassword", "")]
[OutputType('SCRTHQ.PEMEncrypt.RSAKey')]
[CmdletBinding()]
Param(
[Parameter(Position = 0)]
[Alias('l','b')]
[Int]
$Length = 4096,
[parameter()]
[Alias('p')]
[Object]
$Password,
[parameter()]
[Alias('out')]
[String]
$Path = (Get-DefaultPath),
[Parameter()]
[Alias('i')]
[Switch]
$Interactive,
[Parameter()]
[Alias('nof')]
[Switch]
$NoFile,
[Parameter()]
[Alias('nos')]
[Switch]
$NoSSH,
[Parameter()]
[Alias('nop')]
[Switch]
$NoPEM,
[Parameter()]
[Alias('pt')]
[Switch]
$PassThru,
[Parameter()]
[Alias('f')]
[Switch]
$Force
)
Begin {
Import-Assemblies
if ($MyInvocation.InvocationName -eq 'genrsa') {
$NoPEM = $false
$NoSSH = $true
}
if ($MyInvocation.InvocationName -eq 'genssh') {
$NoSSH = $false
$NoPEM = $true
}
}
Process {
if ($Interactive) {
Write-Host "Generating public/private RSA key pair..."
if (-not $NoFile) {
$newPath = if ($choice = Read-Host -Prompt "Enter the path to save the key to (Default: $Path)") {
$choice
}
else {
$Path
}
if (-not $Force -and (Test-Path $newPath)) {
throw "Key already exists at desired path: $newPath. Use -Force to overwrite the existing key or choose a different path"
}
}
$Length = if ($choice = Read-Host -Prompt "Enter desired key bit length (Default: 4096)") {
$choice
}
else {
4096
}
$Password = Read-Host -AsSecureString -Prompt "Enter passphrase (Default: No passphrase)"
if (-not ([System.String]::IsNullOrEmpty((Unprotect-SecureString -SecureString $Password)))) {
$confirmed = Read-Host -AsSecureString -Prompt "Enter the same passphrase to confirm"
if ((Unprotect-SecureString -SecureString $confirmed) -ne (Unprotect-SecureString -SecureString $Password)) {
Write-Warning "Passphrases provided do not match! Exiting"
throw
}
$keys = [SCRTHQ.PEMEncrypt.RSA]::Generate(
$Length,
(Unprotect-SecureString -SecureString $Password)
)
}
else {
$keys = [SCRTHQ.PEMEncrypt.RSA]::Generate(
$Length
)
}
if (-not $NoFile) {
Write-Host "Saving private key to path : $newPath"
$keys.PrivatePEM | Set-Content -Path $newPath -Force
if (-not $NoSSH) {
$sshPath = "{0}.pub" -f $newPath
Write-Host "Saving public SSH key to path : $sshPath"
$keys.PublicSSH | Set-Content -Path $sshPath -Force
}
if (-not $NoPEM) {
$pemPath = "{0}.pem" -f $newPath
Write-Host "Saving public PEM key to path : $pemPath"
$keys.PublicPEM | Set-Content -Path $pemPath -Force
}
}
if ($PassThru -or $NoFile) {
$keys
}
}
else {
$keys = if ($PSBoundParameters.ContainsKey('Password')) {
[SCRTHQ.PEMEncrypt.RSA]::Generate(
$Length,
$(if($Password -is [SecureString]){(Unprotect-SecureString -SecureString $Password)}else{"$Password"})
)
}
else {
[SCRTHQ.PEMEncrypt.RSA]::Generate(
$Length
)
}
if (-not $NoFile) {
if (-not $Force -and (Test-Path $Path)) {
throw "Key already exists at desired path: $Path. Use -Force to overwrite the existing key or choose a different path."
}
else {
Write-Host "Saving private key to path : $Path"
$keys.PrivatePEM | Set-Content -Path $Path -Force
if (-not $NoSSH) {
$sshPath = "{0}.pub" -f $Path
Write-Host "Saving public SSH key to path : $sshPath"
$keys.PublicSSH | Set-Content -Path $sshPath -Force
}
if (-not $NoPEM) {
$pemPath = "{0}.pem" -f $Path
Write-Host "Saving public PEM key to path : $pemPath"
$keys.PublicPEM | Set-Content -Path $pemPath -Force
}
}
}
if ($PassThru -or $NoFile) {
$keys
}
}
}
}
2 changes: 1 addition & 1 deletion PEMEncrypt/Public/Unprotect-PEMString.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function Unprotect-PEMString {
[SCRTHQ.PEMEncrypt.Crypto]::Decrypt(
$string,
$PrivateKey,
(New-Object PSCredential 'user',$Password).GetNetworkCredential().Password
(Unprotect-SecureString -SecureString $Password)
)
}
else {
Expand Down
Loading

0 comments on commit ef8185d

Please sign in to comment.