internal/classes/crypto/ECDsaKey.ps1
<# abstract #> class ECDsaKeyBase : KeyBase { hidden [System.Security.Cryptography.ECDsa] $ECDsa; hidden [string] $CurveName ECDsaKeyBase([int] $hashSize) : base($hashSize) { if ($this.GetType() -eq [ECDsaKeyBase]) { throw [System.InvalidOperationException]::new("Class must be inherited"); } $this.CurveName = "P-$hashSize"; $curve = [ECDsaKeyBase]::GetCurve($hashSize); $this.ECDsa = [System.Security.Cryptography.ECDsa]::Create($curve); } ECDsaKeyBase([int] $hashSize,[System.Security.Cryptography.ECParameters] $keyParameters) :base($hashSize) { if ($this.GetType() -eq [ECDsaKeyBase]) { throw [System.InvalidOperationException]::new("Class must be inherited"); } $this.CurveName = "P-$hashSize"; $this.ECDsa = [System.Security.Cryptography.ECDsa]::Create($keyParameters); } static [System.Security.Cryptography.ECCurve] GetCurve($hashSize) { switch ($hashSize) { 256 { return [System.Security.Cryptography.ECCurve+NamedCurves]::nistP256; } 384 { return [System.Security.Cryptography.ECCurve+NamedCurves]::nistP384; } 512 { return [System.Security.Cryptography.ECCurve+NamedCurves]::nistP521; } Default { Write-Error [System.ArgumentOutOfRangeException]::new("Cannot use hash size to create curve."); } } return $null; } [object] ExportKey() { $ecParams = $this.ECDsa.ExportParameters($true); $keyExport = [ECDsaKeyExport]::new(); $keyExport.D = $ecParams.D; $keyExport.X = $ecParams.Q.X; $keyExport.Y = $ecParams.Q.Y; $keyExport.HashSize = $this.HashSize; return $keyExport; } } class ECDsaAccountKey : ECDsaKeyBase, IAccountKey { ECDsaAccountKey([int] $hashSize) : base($hashSize) { } ECDsaAccountKey([int] $hashSize, [System.Security.Cryptography.ECParameters] $keyParameters) : base($hashSize, $keyParameters) { } [string] JwsAlgorithmName() { return "ES$($this.HashSize)" } [System.Collections.Specialized.OrderedDictionary] ExportPublicJwk() { $keyParams = $this.ECDsa.ExportParameters($false); <# As per RFC 7638 Section 3, these are the *required* elements of the JWK and are sorted in lexicographic order to produce a canonical form #> $publicJwk = [ordered]@{ "crv" = $this.CurveName; "kty" = "EC"; # https://tools.ietf.org/html/rfc7518#section-6.2 "x" = ConvertTo-UrlBase64 -InputBytes $keyParams.Q.X; "y" = ConvertTo-UrlBase64 -InputBytes $keyParams.Q.Y; } return $publicJwk; } [byte[]] Sign([byte[]] $inputBytes) { return $this.ECDsa.SignData($inputBytes, $this.HashName); } [byte[]] Sign([string] $inputString) { return $this.Sign([System.Text.Encoding]::UTF8.GetBytes($inputString)); } static [IAccountKey] Create([ECDsaKeyExport] $keyExport) { $keyParameters = [System.Security.Cryptography.ECParameters]::new(); $keyParameters.Curve = [ECDsaKeyBase]::GetCurve($keyExport.HashSize); $keyParameters.D = $keyExport.D; $keyParameters.Q.X = $keyExport.QX; $keyParameters.Q.Y = $keyExport.QY; return [ECDsaAccountKey]::new($keyExport.HashSize, $keyParameters); } } class ECDsaCertificateKey : ECDsaAccountKey, ICertificateKey { ECDsaCertificateKey([int] $hashSize) : base($hashSize) { } ECDsaCertificateKey([int] $hashSize, [System.Security.Cryptography.ECParameters] $keyParameters) : base($hashSize, $keyParameters) { } [byte[]] ExportPfx([byte[]] $acmeCertificate, [SecureString] $password) { return [Certificate]::ExportPfx($acmeCertificate, $this.ECDsa, $password); } [byte[]] GenerateCsr([string[]] $dnsNames) { return [Certificate]::GenerateCsr($dnsNames, $this.ECDsa, $this.HashName); } static [ICertificateKey] Create([ECDsaKeyExport] $keyExport) { $keyParameters = [System.Security.Cryptography.ECParameters]::new(); $keyParameters.Curve = [ECDsaKeyBase]::GetCurve($keyExport.HashSize); $keyParameters.D = $keyExport.D; $keyParameters.Q.X = $keyExport.QX; $keyParameters.Q.Y = $keyExport.QY; return [ECDsaCertificateKey]::new($keyExport.HashSize, $keyParameters); } } |