Using PowerShell to Create Self-Signed Certificate of 2048 bits length - powershell

I use the function bellow to generate self-signed certificate for using it into IIS.
My question is how to generate the certificate with the public key of length 2048 bits?
I have changed $key.Length to 2048 but when I generate the certificate, public key is only 1024 bits.
function Add-SelfSignedCertificate
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$True, ValueFromPipelineByPropertyName=$True)]
[Alias('cn')]
[string]$CommonName
)
$name = new-object -com "X509Enrollment.CX500DistinguishedName.1"
$name.Encode("CN=$CommonName", 0)
$key = new-object -com "X509Enrollment.CX509PrivateKey.1"
$key.ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
$key.KeySpec = 1
$key.Length = 2048
$key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
$key.MachineContext = 1
$key.Create()
$serverauthoid = new-object -com "X509Enrollment.CObjectId.1"
$serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
$ekuoids = new-object -com "X509Enrollment.CObjectIds.1"
$ekuoids.add($serverauthoid)
$ekuext = new-object -com "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
$ekuext.InitializeEncode($ekuoids)
$cert = new-object -com "X509Enrollment.CX509CertificateRequestCertificate.1"
$cert.InitializeFromPrivateKey(2, $key, "")
$cert.Subject = $name
$cert.Issuer = $cert.Subject
$cert.NotBefore = get-date
$cert.NotAfter = $cert.NotBefore.AddYears(5)
$cert.X509Extensions.Add($ekuext)
$cert.Encode()
$enrollment = new-object -com "X509Enrollment.CX509Enrollment.1"
$enrollment.InitializeFromRequest($cert)
$enrollment.CertificateFriendlyName = $CommonName
$certdata = $enrollment.CreateRequest(0)
$enrollment.InstallResponse(2, $certdata, 0, "")
}

Why don't you generate a 2048 first and then add it like :
New-SelfSignedCertificate -Type Custom -Subject "E=a.b#test.com,CN=user" -TextExtension #("2.5.29.37={text}1.3.6.1.5.5.7.3.4","2.5.29.17={text}email=a.b#test.com&upn=ab#test.com") -KeyUsage DataEncipherment -KeyAlgorithm RSA -KeyLength 2048 -SmimeCapabilities -CertStoreLocation "Cert:\CurrentUser\My"
Then after this you can add it.
Hope it helps.

After restarting the machine the problem was solved, I ran the script and it worked fine.

Related

Getting private keys to work on windows 7 powershell version 2

Firstly, I know that very similar questions have been asked, but having read through the solutions and modifying my own workflow has not produced the correct results.
I am hoping that by showing the code I am using, someone may be able to point out where I am going wrong. I am trying to import a priate key from my windows 10 machine to my legacy windows 7 with powershell version 2 installed.
The error I am facing is that $cert.hasprivatekey returns true but $cert.privatekey always returns null. However this happens on the windows 10 machine as well so it seems to be a problem generating a key but every guide I have found uses the same syntax!
Here is the code to create the key:
$store = "cert:\CurrentUser\My"
$params = #{
CertStoreLocation = $store
Subject = "CN=Test1"
KeyLength = 2048
KeyAlgorithm = "RSA"
KeyUsage = "DataEncipherment"
Type = "DocumentEncryptionCert"
KeyExportPolicy = 'Exportable'
}
# generate new certificate and add it to certificate store
$cert = New-SelfSignedCertificate #params
Get-ChildItem -path $store
$pwd = ("P#ssword" | ConvertTo-SecureString -AsPlainText -Force)
$privateKey = "$home\Documents\Test1.pfx"
$publicKey = "$home\Documents\Test1.cer"
# Export private key as PFX certificate, to use those Keys on different machine/user
Export-PfxCertificate -FilePath $privateKey -Cert $cert -Password $pwd
# Export Public key, to share with other users
Export-Certificate -FilePath $publicKey -Cert $cert
I have aso tried this to no avail:
$TestCertificate = New-SelfSignedCertificate -Subject 'TestCertificate' -KeyExportPolicy 'Exportable'
Export-PfxCertificate -Cert $TestCertificate -FilePath .\TestCertificate.pfx -Password (ConvertTo-SecureString 'TestPassword' -AsPlainText -Force)
I am then trying to import the private pfx certificate on windows 7 using the following:
$PfxFilePath = "C:\Users\user\Desktop\Test1.pfx"
$pwd = ("P#ssword" | ConvertTo-SecureString -AsPlainText -Force)
$Password = $pwd
$absolutePfxFilePath = Resolve-Path -Path $PfxFilePath
Write-Output "Importing store certificate '$absolutePfxFilePath'..."
Add-Type -AssemblyName System.Security
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cert.Import($absolutePfxFilePath, $Password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet")
$Store = New-Object System.Security.Cryptography.X509Certificates.X509Store(
[System.Security.Cryptography.X509Certificates.StoreName]::My,
[System.Security.Cryptography.X509Certificates.StoreLocation]::LocalMachine)
$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::"ReadWrite")
$store.Add($cert)
$store.Close()
All ideas welcome!
The key is stored in Key Storage Provider which is not supported by PrivateKey property which is completely obsolete. Instead you need to use newer syntax to obtain private key:
$key = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)

How to remove Enhanced Key Usage using New-SelfSignedCertificate

After running the following command, the Extended Key Usage / Enhanced Key Usage is showing both client and server authorization, how do I remove this option for Root CAs and Intermediate CAs, as CAs should not have these options. What other parameters should be added into the New-SelfSignedCertificate to remove the option below?
Client Authentication (1.3.6.1.5.5.7.3.2)
Server Authentication (1.3.6.1.5.5.7.3.1)
Windows 10
Power Shell v5
openssl 1.1.1
$RootCA = New-SelfSignedCertificate -Subject 'CN=KeyCARootCN,O=Test Organisation, OU=Test RootCA,C=AU' -KeyLength 2048 -KeyAlgorithm 'RSA' -HashAlgorithm 'SHA256' -KeyExportPolicy Exportable -KeyUsage KeyEncipherment,DataEncipherment,CertSign,DigitalSignature,CRLSign -Provider 'Microsoft Enhanced RSA and AES Cryptographic Provider' -NotAfter (Get-Date).AddYears(40) -KeyUsageProperty All -TextExtension #(“2.5.29.19 ={critical} {text}ca=1&pathlength=5”) -CertStoreLocation Cert:\LocalMachine\My
$RootCA
$RootCAthumbprint = $RootCA.Thumbprint
$CertRootCAPassword = ConvertTo-SecureString -String “Test123” -Force –AsPlainText
$CertRootCAFilePFX = Export-PfxCertificate -Cert cert:\LocalMachine\My\$RootCAthumbprint -FilePath C:\Users\KeyCARoot.pfx -Password $CertRootCAPassword
$CertRootCAFileCER = Export-Certificate -Cert $RootCA -FilePath C:\Users\KeyCARoot.cer
$CertRootCAFileCER
$CertRootCAPath = 'C:\Users\KeyCARoot.cer'
Give this a try:
Import-Module PKI
$params = #{
Type = [Microsoft.CertificateServices.Commands.CertificateType]::Custom
Subject = 'CN=KeyCARootCN,O=Test Organisation, OU=Test RootCA,C=AU'
KeyLength = 2048
KeyAlgorithm = 'RSA'
HashAlgorithm = [System.Security.Cryptography.HashAlgorithmName]::SHA256
KeyExportPolicy = [Microsoft.CertificateServices.Commands.KeyExportPolicy]::Exportable
KeySpec = [Microsoft.CertificateServices.Commands.KeySpec]::Signature
KeyUsage = #([Microsoft.CertificateServices.Commands.KeyUsage]::CertSign,
[Microsoft.CertificateServices.Commands.KeyUsage]::DigitalSignature,
[Microsoft.CertificateServices.Commands.KeyUsage]::CRLSign)
KeyUsageProperty = [Microsoft.CertificateServices.Commands.KeyUsageProperty]::All
TextExtension = #('2.5.29.19={critical}{text}ca=1&pathlength=5')
NotAfter = (Get-Date).AddYears(40)
Provider = 'Microsoft Enhanced Cryptographic Provider v1.0'
CertStoreLocation = 'Cert:\LocalMachine\My'
}
$RootCA = New-SelfSignedCertificate #params
In general, you may have over-specified some options that aren't necessary. As you can see from above, I simply added a Custom certificate type, removed the KeyEncipherment and DataEncipherment Key Usage options, and swapped-out the CSP provider. Retaining all the signing options for Key Usage should suffice for Root and Intermediate CA certs.
Optionally, you could add ,'2.5.29.37={text}2.5.29.37.0' to your TextExtension list if you wanted your Enhanced Key Usage to be "Any Purpose".

Generate HMAC SHA256 signature Powershell

For 3commas I tried to generate a HMAC SHA256 signature in Powershell with the example parameters from the documentation:
$secret = 'NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j'
$message = '/public/api/ver1/accounts/new?type=binance&name=binance_account&api_key=XXXXXX&secret=YYYYYY'
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
$signature = [Convert]::ToBase64String($signature)
$signature
It generates "MPZ4oVcjApDgBHXP/8y8kq42WdlMFFosDp0Poo9BwRo="
As described in the documentation it should generate "30f678a157230290e00475cfffccbc92ae3659d94c145a2c0e9d0fa28f41c11a"
[linux]$ echo -n "/public/api/ver1/accounts/new?type=binance&name=binance_account&api_key=XXXXXX&secret=YYYYYY" | openssl dgst -sha256 -hmac "NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j"
(stdin)= 30f678a157230290e00475cfffccbc92ae3659d94c145a2c0e9d0fa28f41c11a
Can anyone help me out?
Use the BitConverter class.
$secret = 'NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j'
$message = '/public/api/ver1/accounts/new?type=binance&name=binance_account&api_key=XXXXXX&secret=YYYYYY'
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
$signature1 = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
#$signature2 = [Convert]::ToBase64String($signature1)
[System.BitConverter]::ToString($signature1) -replace '-', ''

PowerShell Import CA and User Certificate from pfx

I am trying to import a .p12 file using a PowerShell script. However I am not able to import the CA as it only installs the user cert and private key. I am using the following code.
function Import-PfxCertificate ([String]$certPath,[String]$certificateStoreLocation = "CurrentUser",[String]$certificateStoreName = "My",$pfxPassword = $null)
{
$pfx = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
$pfx.Import($certPath, $pfxPassword, "Exportable,PersistKeySet")
$store = new-object System.Security.Cryptography.X509Certificates.X509Store($certificateStoreName,$certificateStoreLocation)
$store.open("MaxAllowed")
$store.add($pfx)
$store.close()
return $pfx
}
Any help would be greatly appricated.

Why does my private key not work to decrypt a key encrypted by the public key?

I'm trying to turn this MSDN page example code into a Powershell script.
The objective is to create files encrypted by a public key for transport into an environment with access to the private key so they can be decrypted.
I'm using New-SelfSignedCertificate to create the certificates because I don't need anyone to trust these certs, and I'm using the full certificate with public and private keys directly out of the Windows Key Store because I'm still just testing the code.
My problem is that when I encrypt, everything seems to work fine, but when decrypting I get the error message:
ERROR: Exception calling "Decrypt" with "2" argument(s): "The data to
be decrypted exceeds the maximum for this modulus of 128 bytes."
It looks like New-SelfSignedCertificate is creating public keys of 2048 bits, and even though in the certs mmc snapin I can see that the cert has a private key, I am unable to see any of it's properties, either through UI or via code.
For instance the following code:
$cert = Get-Item 'Cert:\LocalMachine\AddressBook\<ThumbPrint>'
$cert.HasPrivateKey
$cert.PrivateKey
results in
True
and NULL
Here is the code
function ConvertTo-EncryptedFile
{
[outputType([System.IO.FileInfo])]
param
(
[parameter(Mandatory = $true)]
[string]$path,
[string]$client
)
$cert = Get-ClientCert -client $client
if(Test-Path $path)
{
$file = Get-Item $path
$folder = $file.DirectoryName
$Name = $file.Name
$destination = Join-Path $folder -ChildPath "$Name.encrypted"
$serviceProvider = [System.Security.Cryptography.RSACryptoServiceProvider]$cert.PublicKey.Key
$aesManaged = New-Object System.Security.Cryptography.AesManaged
$aesManaged.KeySize = 256
$aesManaged.BlockSize = 128
$aesManaged.Mode = 'CBC'
$transform = $aesManaged.CreateEncryptor()
$keyformatter = New-Object System.Security.Cryptography.RSAPKCS1KeyExchangeformatter $serviceProvider
[byte[]]$keyEncrypted = $keyformatter.CreateKeyExchange($aesManaged.Key, $aesManaged.GetType())
[byte[]]$lenK = New-Object byte[] 4
[byte[]]$lenIV = New-Object byte[] 4
[int]$lKey = $keyEncrypted.Length
$lenK = [System.BitConverter]::GetBytes($lKey)
[int]$lIV = $aesManaged.IV.Length
$lenIV = [System.BitConverter]::GetBytes($lIV)
$outFS = New-Object System.IO.FileStream #($destination, [System.IO.FileMode]::Create)
$outFS.Write($lenK, 0, 4)
$outFS.Write($lenIV, 0, 4)
$outFS.Write($keyEncrypted, 0, $lKey)
$outFS.Write($aesManaged.IV, 0, $lIV)
$outStreamEncrypted = New-Object System.Security.Cryptography.CryptoStream #($outFS, $transform, [System.Security.Cryptography.CryptoStreamMode]::Write)
$count = 0
$offset = 0
$blockSizeBytes = $aesManaged.BlockSize / 8
$data = New-Object byte[] $blockSizeBytes
$bytesRead = 0
$inFS = New-Object System.IO.FileStream #($path, [System.IO.FileMode]::Open)
do
{
$count = $inFS.Read($data, 0, $blockSizeBytes)
$offset += $count
$outStreamEncrypted.Write($data, 0, $count)
$bytesRead += $blockSizeBytes
}
while ($count -gt 0)
$inFS.Close()
$outStreamEncrypted.FlushFinalBlock()
$outStreamEncrypted.Close()
$outFS.Close()
$inFS.Dispose()
$outStreamEncrypted.Dispose()
$outFS.Dispose()
Remove-Variable transform
$aesManaged.Dispose()
Write-Output (Get-Item $destination)
}
else
{
throw "File to encrypt not found at path: $path"
}
}
function ConvertFrom-EncryptedFile
{
param
(
[parameter(Mandatory = $true)]
[string]$path,
[string]$client
)
$cert = Get-ClientCert -client $client
if (Test-Path $path)
{
$destination = $path.Substring(0, $path.LastIndexOf('.'))
}
else
{
throw "File to decrypt not found at $path"
}
if ($cert.HasPrivateKey)
{
$rsaPrivateKey = New-Object System.Security.Cryptography.RSACryptoServiceProvider ($cert.PrivateKey)
}
$aesManaged = New-Object System.Security.Cryptography.AesManaged
$aesManaged.KeySize = 256
$aesManaged.BlockSize = 128
$aesManaged.Mode = 'CBC'
[byte[]]$lenK = New-Object System.Byte[] 4
[byte[]]$lenIV = New-Object System.Byte[] 4
[System.IO.FileStream]$inFs = New-Object System.IO.FileStream #($path, [System.IO.FileMode]::Open)
$inFs.Seek(0, 'Begin')
$inFs.Seek(0, 'Begin')
$inFs.Read($lenK, 0, 3)
$infs.Seek(4, 'Begin')
$infs.Read($lenIV, 0, 3)
[int]$lenK = [System.BitConverter]::ToInt32($lenK, 0)
[int]$lenIV = [System.BitConverter]::ToInt32($lenIV, 0)
[int]$startC = $lenK + $lenIV + 8
[int]$lenC = [int]$inFs.Length - $startC
[byte[]]$keyEncrypted = New-Object System.Byte[] $lenK
[byte[]]$iv = New-Object System.Byte[] $lenIV
$inFs.Seek(8, 'Begin')
$inFs.Read($keyEncrypted, 0, $lenK)
$inFs.Seek(8 + $lenK, 'Begin')
$inFs.Read($iv, 0, $lenIV)
[byte[]]$keyDecrypted = $rsaPrivateKey.Decrypt($keyEncrypted, $false)
}
It stops at decrypting the AES key because I haven't been able to get passed that hurdle yet.
I've tried reducing the AES key size from 256 to 128, but that didn't seem to work, and I don't really want to use a smaller key size anyway, I would rather figure out what's wrong with this code.
Thanks for any help!
Bill
It seems, the problems is that New-SelfSignedCertificate in PowerShell v4 choose provider, which is not appropriate to use with RSACryptoServiceProvider class, and does not have -Provider parameter, that allow specify provider explicitly.
One option to solve this would be to update to PowerShell v5. In PowerShell v5 New-SelfSignedCertificate cmdlet have -Provider parameter, so that you can specify desired provider:
PS> $Cert=New-SelfSignedCertificate -DnsName Test -CertStoreLocation Cert:\CurrentUser\My -Provider 'Microsoft Enhanced RSA and AES Cryptographic Provider'
PS> $Cert.PrivateKey
PublicOnly : False
CspKeyContainerInfo : System.Security.Cryptography.CspKeyContainerInfo
KeySize : 2048
KeyExchangeAlgorithm : RSA-PKCS1-KeyEx
SignatureAlgorithm : http://www.w3.org/2000/09/xmldsig#rsa-sha1
PersistKeyInCsp : True
LegalKeySizes : {System.Security.Cryptography.KeySizes}
To list installed providers you can use following commands:
PS> $Providers=New-Object -ComObject X509Enrollment.CCspInformations
PS> $Providers.AddAvailableCsps()
PS> $Providers|Format-Table Name,Type
Name Type
---- ----
Microsoft Software Key Storage Provider 0
Microsoft Passport Key Storage Provider 0
Microsoft Smart Card Key Storage Provider 0
Microsoft Base Cryptographic Provider v1.0 1
Microsoft Base DSS and Diffie-Hellman Cryptographic Provider 13
Microsoft Base DSS Cryptographic Provider 3
Microsoft Base Smart Card Crypto Provider 1
Microsoft DH SChannel Cryptographic Provider 18
Microsoft Enhanced Cryptographic Provider v1.0 1
Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider 13
Microsoft Enhanced RSA and AES Cryptographic Provider 24
Microsoft RSA SChannel Cryptographic Provider 12
Microsoft Strong Cryptographic Provider 1
As you need an RSA capable provider, then you need to choose provider with type 1, 12 or 24.