Private/New-PAKey.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
function New-PAKey {
    [CmdletBinding(DefaultParameterSetName='Generate')]
    [OutputType('System.Security.Cryptography.AsymmetricAlgorithm')]
    param(
        [Parameter(ParameterSetName='Generate',Position=0)]
        [ValidateScript({Test-ValidKeyLength $_ -ThrowOnFail})]
        [string]$KeyLength='2048',
        [Parameter(ParameterSetName='FromPem',Mandatory)]
        [string]$KeyFile,
        [Parameter(ParameterSetName='FromPem',Mandatory)]
        [ref]$ParsedLength
    )

    if ('Generate' -eq $PSCmdlet.ParameterSetName) {

        # KeyLength should have already been validated which means it should be a parseable
        # [int] that may have an "ec-" prefix
        if ($KeyLength -like 'ec-*') {
            $KeyType = 'EC'
            $KeySize = [int]::Parse($KeyLength.Substring(3))
            Write-Debug "Creating new $KeyType $KeySize key"

            # Get the appropriate curve based on the key size
            # https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.eccurve.namedcurves
            $Curve = switch ($KeySize) {
                256 { [Security.Cryptography.ECCurve+NamedCurves]::nistP256; break }
                384 { [Security.Cryptography.ECCurve+NamedCurves]::nistP384; break }
                521 { [Security.Cryptography.ECCurve+NamedCurves]::nistP521; break }
                default { throw "Unsupported EC KeySize. Try 256, 384, or 521." }
            }

            # return the new key
            return [Security.Cryptography.ECDsa]::Create($Curve)

        } else {
            $KeyType = 'RSA'
            $KeySize = [int]::Parse($KeyLength)
            Write-Debug "Creating new $KeyType $KeySize key"

            # return the new key
            return [Security.Cryptography.RSACryptoServiceProvider]::new($KeySize)
        }

    } else {

        # make sure the file exists
        if (-not (Test-Path $KeyFile -PathType Leaf)) {
            throw "KeyFile $KeyFile not found"
        }

        Write-Verbose "Attempting to import private key $KeyFile"
        try {
            $newKey = Import-Pem -InputFile $KeyFile | ConvertFrom-BCKey
        } catch {
            throw "Error importing private key. $($_.Exception.Message)"
        }

        # determine the appropriate KeyLength value based on the imported
        # key's properties
        $kl = $newKey.KeySize.ToString()
        if ($newKey -is [Security.Cryptography.ECDsa]) {
            $kl = "ec-$kl"
        }
        Write-Debug "KeyLength parsed as $kl"

        try {
            Test-ValidKeyLength $kl -ThrowOnFail | Out-Null
            # set the [ref] value to pass back
            $ParsedLength.Value = $kl
        } catch {
            throw "Imported key length ($kl) is invalid. $($_.Exception.Message)"
        }

        # return the new key
        return $newKey
    }
}