Skip to content

Commit 98ee44d

Browse files
committed
Added ability to export keys to PEM format
1 parent 4a705b2 commit 98ee44d

File tree

5 files changed

+171
-1
lines changed

5 files changed

+171
-1
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
function EncodeIntegerBigEndian {
2+
[CmdletBinding()]
3+
param (
4+
[Parameter(Mandatory = $true, Position = 0 )]
5+
[System.IO.BinaryWriter]$stream,
6+
[Parameter(Mandatory = $true, Position = 1 )]
7+
[byte[]]$value,
8+
[Parameter(Mandatory = $false, Position = 2 )]
9+
[bool]$forceUnsigned = $true
10+
)
11+
12+
process {
13+
$stream.Write([byte]0x02); # INTEGER
14+
$prefixZeros = 0;
15+
for ($i = 0; $i -lt $value.Length; $i++) {
16+
if ($value[$i] -ne 0) {
17+
break
18+
}
19+
$prefixZeros++;
20+
}
21+
if ($value.Length - $prefixZeros -eq 0) {
22+
EncodeLength $stream 1
23+
$stream.Write([byte]0);
24+
}
25+
else {
26+
if ($forceUnsigned -and $value[$prefixZeros] -gt 0x7f) {
27+
# Add a prefix zero to force unsigned if the MSB is 1
28+
EncodeLength $stream ($value.Length - $prefixZeros + 1)
29+
$stream.Write([byte]0);
30+
}
31+
else {
32+
EncodeLength $stream ($value.Length - $prefixZeros)
33+
}
34+
for ($i = $prefixZeros; $i -lt $value.Length; $i++) {
35+
$stream.Write($value[$i]);
36+
}
37+
}
38+
}
39+
}

Crypto.RSA/Private/EncodeLength.ps1

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
function EncodeLength {
2+
[CmdletBinding()]
3+
param (
4+
[Parameter(Mandatory = $true, Position = 0 )]
5+
[System.IO.BinaryWriter]$stream,
6+
[Parameter(Mandatory = $true, Position = 1 )]
7+
[int]$length
8+
)
9+
10+
process {
11+
if ($length -lt 0) {
12+
throw [System.ArgumentOutOfRangeException]::new("$length", "Length must be non-negative")
13+
}
14+
if ($length -lt 0x80) {
15+
# Short form
16+
$stream.Write([byte]$length)
17+
}
18+
else {
19+
# Long form
20+
$temp = $length;
21+
$bytesRequired = 0;
22+
while ($temp -gt 0) {
23+
$temp = $temp -shr 8;
24+
$bytesRequired++;
25+
}
26+
$stream.Write([byte]($bytesRequired -bor 0x80));
27+
for ($i = $bytesRequired - 1; $i -ge 0; $i--) {
28+
$stream.Write([byte]($length -shr (8 * $i) -band 0xff));
29+
}
30+
}
31+
}
32+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# src: https://gist.github.com/therightstuff/aa65356e95f8d0aae888e9f61aa29414
2+
function Export-PrivateKey {
3+
param (
4+
[Parameter(Mandatory = $true, Position = 0 )]
5+
[System.Security.Cryptography.RSACryptoServiceProvider]$csp
6+
)
7+
8+
$outputStream = [System.IO.StringWriter]::new()
9+
if ($csp.PublicOnly) {
10+
throw [System.ArgumentException]::new("CSP does not contain a private key", "csp")
11+
}
12+
$parameters = $csp.ExportParameters($true);
13+
14+
15+
Use ($stream = [System.IO.MemoryStream]::new()) {
16+
$writer = [System.IO.BinaryWriter]::new($stream);
17+
$writer.Write([byte]0x30); # SEQUENCE
18+
Use ($innerStream = [System.IO.MemoryStream]::new()) {
19+
$innerWriter = [System.IO.BinaryWriter]::new($innerStream);
20+
EncodeIntegerBigEndian $innerWriter @([byte]0x00)
21+
EncodeIntegerBigEndian $innerWriter $parameters.Modulus
22+
EncodeIntegerBigEndian $innerWriter $parameters.Exponent
23+
EncodeIntegerBigEndian $innerWriter $parameters.D
24+
EncodeIntegerBigEndian $innerWriter $parameters.P
25+
EncodeIntegerBigEndian $innerWriter $parameters.Q
26+
EncodeIntegerBigEndian $innerWriter $parameters.DP
27+
EncodeIntegerBigEndian $innerWriter $parameters.DQ
28+
EncodeIntegerBigEndian $innerWriter $parameters.InverseQ
29+
[int]$length = $innerStream.Length;
30+
EncodeLength $writer $length
31+
$writer.Write($innerStream.GetBuffer(), 0, $length);
32+
}
33+
34+
$base64 = [System.Convert]::ToBase64String($stream.GetBuffer(), 0, [int]$stream.Length).ToCharArray();
35+
$outputStream.Write("-----BEGIN RSA PRIVATE KEY-----`n");
36+
for ($i = 0; $i -lt $base64.Length; $i += 64) {
37+
$outputStream.Write($base64, $i, [System.Math]::Min(64, $base64.Length - $i));
38+
$outputStream.Write("`n");
39+
}
40+
$outputStream.Write("-----END RSA PRIVATE KEY-----");
41+
}
42+
43+
return $outputStream.ToString();
44+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# src: https://gist.github.com/therightstuff/aa65356e95f8d0aae888e9f61aa29414
2+
function Export-PublicKey {
3+
param (
4+
[Parameter(Mandatory = $true, Position = 0 )]
5+
[System.Security.Cryptography.RSACryptoServiceProvider]$csp
6+
)
7+
8+
$outputStream = [System.IO.StringWriter]::new()
9+
$parameters = $csp.ExportParameters($false);
10+
Use ( $stream = [System.IO.MemoryStream]::new()) {
11+
$writer = [System.IO.BinaryWriter]::new($stream);
12+
$writer.Write([byte]0x30); # SEQUENCE
13+
Use ($innerStream = [System.IO.MemoryStream]::new()) {
14+
$innerWriter = [System.IO.BinaryWriter]::new($innerStream);
15+
$innerWriter.Write([byte]0x30); # SEQUENCE
16+
EncodeLength $innerWriter 13
17+
$innerWriter.Write([byte]0x06); # OBJECT IDENTIFIER
18+
$rsaEncryptionOid = @(0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 )
19+
EncodeLength $innerWriter $rsaEncryptionOid.Length
20+
$innerWriter.Write($rsaEncryptionOid);
21+
$innerWriter.Write([byte]0x05); # NULL
22+
EncodeLength $innerWriter 0
23+
$innerWriter.Write([byte]0x03); # BIT STRING
24+
Use ($bitStringStream = [System.IO.MemoryStream]::new()) {
25+
$bitStringWriter = [System.IO.BinaryWriter]::new($bitStringStream);
26+
$bitStringWriter.Write([byte]0x00); # # of unused bits
27+
$bitStringWriter.Write([byte]0x30); # SEQUENCE
28+
Use ($paramsStream = [System.IO.MemoryStream]::new()) {
29+
$paramsWriter = [System.IO.BinaryWriter]::new($paramsStream);
30+
EncodeIntegerBigEndian $paramsWriter $parameters.Modulus # Modulus
31+
EncodeIntegerBigEndian $paramsWriter $parameters.Exponent # Exponent
32+
[int]$paramsLength = $paramsStream.Length;
33+
EncodeLength $bitStringWriter $paramsLength
34+
$bitStringWriter.Write($paramsStream.GetBuffer(), 0, $paramsLength);
35+
}
36+
[int]$bitStringLength = $bitStringStream.Length;
37+
EncodeLength $innerWriter $bitStringLength
38+
$innerWriter.Write($bitStringStream.GetBuffer(), 0, $bitStringLength);
39+
}
40+
[int]$length = $innerStream.Length;
41+
EncodeLength $writer $length
42+
$writer.Write($innerStream.GetBuffer(), 0, $length);
43+
}
44+
45+
$base64 = [System.Convert]::ToBase64String($stream.GetBuffer(), 0, [int]$stream.Length).ToCharArray();
46+
$outputStream.Write("-----BEGIN PUBLIC KEY-----`n");
47+
for ($i = 0; $i -lt $base64.Length; $i += 64) {
48+
$outputStream.Write($base64, $i, [System.Math]::Min(64, $base64.Length - $i));
49+
$outputStream.Write("`n");
50+
}
51+
$outputStream.Write("-----END PUBLIC KEY-----");
52+
}
53+
54+
return $outputStream.ToString();
55+
}

Crypto.RSA/Public/Get-KeyString.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ function Get-KeyString {
22
[CmdletBinding()]
33
param (
44
[Parameter(Mandatory = $true, Position = 0 )]
5-
[System.Security.Cryptography.RSAParameters]$publicKey
5+
[System.Security.Cryptography.RSAParameters]$publicKey
66
)
77

88
begin {

0 commit comments

Comments
 (0)