internal/classes/crypto/RSAKey.ps1
<# abstract #> class RSAKeyBase : KeyBase { hidden [System.Security.Cryptography.RSA] $RSA; RSAKeyBase([int] $hashSize, [int] $keySize) : base($hashSize) { if ($this.GetType() -eq [RSAKeyBase]) { throw [System.InvalidOperationException]::new("Class must be inherited"); } $this.RSA = [System.Security.Cryptography.RSA]::Create($keySize); } RSAKeyBase([int] $hashSize, [System.Security.Cryptography.RSAParameters] $keyParameters) :base($hashSize) { if ($this.GetType() -eq [RSAKeyBase]) { throw [System.InvalidOperationException]::new("Class must be inherited"); } $this.RSA = [System.Security.Cryptography.RSA]::Create($keyParameters); } [object] ExportKey() { $rsaParams = $this.RSA.ExportParameters($true); $keyExport = [RSAKeyExport]::new(); $keyExport.D = $rsaParams.D; $keyExport.DP = $rsaParams.DP; $keyExport.DQ = $rsaParams.DQ; $keyExport.Exponent = $rsaParams.Exponent; $keyExport.InverseQ = $rsaParams.InverseQ; $keyExport.Modulus = $rsaParams.Modulus; $keyExport.P = $rsaParams.P; $keyExport.Q = $rsaParams.Q; $keyExport.HashSize = $this.HashSize; return $keyExport; } } class RSAAccountKey : RSAKeyBase, IAccountKey { RSAAccountKey([int] $hashSize, [int] $keySize) : base($hashSize, $keySize) { } RSAAccountKey([int] $hashSize, [System.Security.Cryptography.RSAParameters] $keyParameters) : base($hashSize, $keyParameters) { } [string] JwsAlgorithmName() { return "RS$($this.HashSize)" } [System.Collections.Specialized.OrderedDictionary] ExportPublicJwk() { $keyParams = $this.RSA.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]@{ "e" = ConvertTo-UrlBase64 -InputBytes $keyParams.Exponent; "kty" = "RSA"; # https://tools.ietf.org/html/rfc7518#section-6.3 "n" = ConvertTo-UrlBase64 -InputBytes $keyParams.Modulus; } return $publicJwk; } [byte[]] Sign([byte[]] $inputBytes) { return $this.RSA.SignData($inputBytes, $this.HashName, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1); } [byte[]] Sign([string] $inputString) { return $this.Sign([System.Text.Encoding]::UTF8.GetBytes($inputString)); } static [IAccountKey] Create([RSAKeyExport] $keyExport) { $keyParameters = [System.Security.Cryptography.RSAParameters]::new(); $keyParameters.D = $keyExport.D; $keyParameters.DP = $keyExport.DP; $keyParameters.DQ = $keyExport.DQ; $keyParameters.Exponent = $keyExport.Exponent; $keyParameters.InverseQ = $keyExport.InverseQ; $keyParameters.Modulus = $keyExport.Modulus; $keyParameters.P = $keyExport.P; $keyParameters.Q = $keyExport.Q; return [RSAAccountKey]::new($keyExport.HashSize, $keyParameters); } } class RSACertificateKey : RSAAccountKey, ICertificateKey { RSACertificateKey([int] $hashSize, [int] $keySize) : base($hashSize, $keySize) { } RSACertificateKey([int] $hashSize, [System.Security.Cryptography.RSAParameters] $keyParameters) : base($hashSize, $keyParameters) { } [byte[]] ExportPfx([byte[]] $acmeCertificate, [SecureString] $password) { return [Certificate]::ExportPfx($acmeCertificate, $this.RSA, $password); } [byte[]] GenerateCsr([string[]] $dnsNames) { return [Certificate]::GenerateCsr($dnsNames, $this.RSA, $this.HashName); } static [ICertificateKey] Create([RSAKeyExport] $keyExport) { $keyParameters = [System.Security.Cryptography.RSAParameters]::new(); $keyParameters.D = $keyExport.D; $keyParameters.DP = $keyExport.DP; $keyParameters.DQ = $keyExport.DQ; $keyParameters.Exponent = $keyExport.Exponent; $keyParameters.InverseQ = $keyExport.InverseQ; $keyParameters.Modulus = $keyExport.Modulus; $keyParameters.P = $keyExport.P; $keyParameters.Q = $keyExport.Q; return [RSACertificateKey]::new($keyExport.HashSize, $keyParameters); } } |