System.Security.Cryptography.X509Certificates.X509Certificate2.GetECDsaPublicKey NotImplemented - c#

We have created a signature in a .Net Core web api, using X509Certificate2.GetECDsaPrivateKey on a .pfx certificate file, and need to verify this signature in our Xamarin Android app, using the public key (.crt). I can run the code on a normal Windows .Net Framework 4.6.1 app and it works. If I change the Framework version to anything lower, my app doesn't compile, as the GetECDsaPublicKey method was only implemented in 4.6.1. In my Xamarin app, I can compile the app and it runs, but as soon as I reach the line that executes the GetECDsaPublicKey method, I get a NotImplemented exception. There is literally no information on this on the internet, apart from the Microsoft documentation, which doesn't give much in any case. Can anyone shed any light onto why this error occurs? Here are the few lines of code to load the certificate and verify the signature (I've taken out some unnecessary error checking code):
string FileName = "public_key.crt";
string certPath = System.IO.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), FileName);
System.Security.Cryptography.X509Certificates.X509Certificate2 certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(certPath);
System.Security.Cryptography.ECDsa eCDsa = certificate.GetECDsaPublicKey(); // This line causes the exception
Even just executing this line, gives the same error:
System.Security.Cryptography.ECDsa eCDsa = System.Security.Cryptography.ECDsa.Create();

So if anyone comes across this also struggling with it, there is a post that answers this question - Are ECDSA and ECDH available for mono?
Sadly, we will have to either use a different encryption/signing algorithm or use something like BouncyCastle...

Related

DirectoryEntry.Exists runs as CLI but not in WebAPI (dotnet c# activedirectory)

I'm writing an API to check if an OU exists in ActiveDirectory or not.
To perform this check, in C#, I run:
string ouName = "MyOrg";
bool ouExists = DirectoryEntry.Exists ($"LDAP://OU={ouName},DC=test,DC=local");
When I create a new CLI project and run these lines, they work fine (the app is running on the DC itself).
But when called by a Controller in a WebAPI project, they throw a runtime COMException (80004005), with the details being "Unspecified error".
I figure this has to do with how Kestrel runs the code. It should authenticate automatically as the current loggedonuser (i.e. I can't use the username, password optional parameters).
How do I do that? And is this the right way to go about it?
Exception details:
System.Runtime.InteropServices.COMException (0x80004005): Unspecified error
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Exists(String path)
at OUCheck.Helpers.ActiveDirectoryHelper.OUExists(String ouDN) in /Projects/OUCheck/Helpers/ActiveDirectoryHelper.cs:line 14
System.Runtime.InteropServices.COMException
The format of the paths for the DirectoryEntry are wrong.
I can't find a supporting document, but the following is the difference:
I was making the queries like this: LDAP://{DN}
LDAP://OU=MyOrg,DC=test,DC=local
While it seems the correct way to do it is: LDAP://{domain}/{DN}
LDAP://test.local/OU=MyOrg,DC=test,DC=local
CLI apps work even with the former, perhaps assuming things about the domain.
The following transcript helped me realize, also thanks to Gabriel for some direction!
https://chat.stackoverflow.com/transcript/12432/2012/6/12
Also might be useful: Get all users from Active Directory?

.net standard x509 operating system differences

I have a DLL which creates a signature based off a JSON. The signing is used with X509 self signed certificate with a public \ private keys (.crt and .pfx files), the DLL is using the private key (pfx file) to sign the data.
This DLL is used twice: once in my actual project, which runs on a linux container, and once in my local tests project, which runs on my windows machine.
There is a second DLL uses the public key to verify the signature (crt file).
Here's the thing: the signature created in my test project matches the signature created in my verifier project, both are windows machines. The project on the linux machine signs differently.
What is going on here?? I have several directions:
Different newlines between linux and windows: I have changed the signing DLL so that it takes the JSON string, deserializes into Newtonsoft.JSON object, serializes again with flag Formatting.None, and then deserializes for the final time. This did not help.
Different invisible characters \ encoding: my code is calling UTF8.GetBytes internally on the string, so don't think it's that.
Additionaly, I took the literall byte array from the linux machine into the windows machine, and got different signatures.
Which leads me to think, is the library System.Security.Cryptography.Xml(5.0.0) behaves differently between the OSs? this page says yes, but does not say how:
Cryptographic operations in .NET Core and .NET 5 are done by operating system (OS) libraries. This dependency has advantages
Any ideas as to why this is happening, and maybe a solution?
My signer code:
...
JToken data = JToken.Parse("{}") //obviously a different string
var certificate = new X509Certificate2(...);
var rsaCSP = new RSACryptoServiceProvider();
rsaCSP.FromXmlString(certificate.PrivateKey.ToXmlString(true));
var signatureBytes = rsaCSP.SignData(Encoding.UTF8.GetBytes(data.ToString(), CryptoConfig.MapNameToIOD(...));

Encryption method is failing on one PC but works on others

I am having an issue where a file containing usernames and passwords is able to be decrypted on some machines but is failing on another.
The machine that it fails on is a brand new installation of Windows 7 embedded. All that has been installed is my application and .net service pack 4.6.2
I did not write this code originally but I need to get it working on the Win 7 embedded machines.
The error I am seeing is:
UserManager error: Error reading C:\CutterBuild\Data\Config\users.xml :System.Security.Cryptography.CryptographicException: Key not valid for use in specified state.
The relevant code is:
try
{
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load(inputFilePath);
System.Security.Cryptography.CspParameters cspParams = new System.Security.Cryptography.CspParameters();
cspParams.KeyContainerName = KEY_CONTAINER_NAME;
// Next line is Where the code fails and throws exception!!!!.
System.Security.Cryptography.RSACryptoServiceProvider rsaKey = new System.Security.Cryptography.RSACryptoServiceProvider(cspParams);
EncryptionHelper.Decrypt(xmlDoc, rsaKey, KEY_NAME);
reader = new XmlNodeReader(xmlDoc);
collection = Read(reader, out errorMessage);
}
I did some debugging and everything looks good up to the rsa key point. The Microsoft documentation on the error is no help.
I did some reading on this and found it confusing, It states in the documentation that you need to create a security certificate, but I can't find any instructions on how to do this. And shouldn't it be created on one machine and copied to others? Where does it get copied to? I can't find anything about it on my PC, but the decrypt is working fine on my PC.
Can anyone point me in the right direction?

Unable to cast error using Box-created RSA key with Box C# SDK project

Our organization recently adopted Box to replace Windows shared folders. The small development group I'm a part of will need to upload and download files from at least one Box share and so we are just getting started with the API.
Our group currently uses Visual Studio 2013 to develop in C# with a preferred target of .NET 4.0. The current version of the SDK (2.15.6) isn't compatible with our platform but looking at prior versions it appears we should be able to leverage version 2.12.1 with our existing platform. The SDK includes a solution with C# methods to access the API calls and a solution with sample code.
Presently I'm trying to get the sample code to consume my credentials and authenticate to the server.
Within the Box developer tools I have created an application and used the built-in Box configuration option to generate a Public/Private keypair which is presented as a JSON file.
Where I'm getting hung up is when I try to use the keypair with the Box.V2.Samples.JWTAuth project. I copied the private key out of the JSON file, replaced the \n's with actual carriage returns, and pasted it into the private_key.pem file:
Private Key
I placed the other values in app.config and started the console app, which produces an Unable to cast error:
Error message
How can I get from a BouncyCastle RsaPrivateCrtKeyParamaters object to a BouncyCastle AsymmetricCipherKeyPair object?
Edit
I was able to track down the problematic code block. From SDK\Box.V2.JWTAuth\BoxJWTAuth.cs:
var pwf = new PEMPasswordFinder(this.boxConfig.JWTPrivateKeyPassword);
AsymmetricCipherKeyPair key;
using (var reader = new StringReader(this.boxConfig.JWTPrivateKey))
{
key = (AsymmetricCipherKeyPair)new PemReader(reader, pwf).ReadObject();
}
var rsa = DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)key.Private);
this.credentials = new SigningCredentials(new RsaSecurityKey(rsa), SecurityAlgorithms.RsaSha256Signature, SecurityAlgorithms.Sha256Digest);
From my reading it seems like the code is anticipating having to extract the Private key from a Public/Private pair which isn't what Box is supplying (at least, not currently) and what I'm supplying appears to already be of the RsaPrivateCrtKeyParameters type so this cast may (no longer be) necessary.
It's not clear from your question whether you are trying to write code to do this, or trying to configure a tool, but programmatically, it would be:
RSAPrivateCrtKeyParameters priv = ...;
RSAKeyParameters pub = new RSAKeyParameters(false, priv.getModulus(), priv.getPublicExponent());
AsymmetricCipherKeyPair kp = new AsymmetricCipherKeyPair(pub, priv);

C# PInvoke CryptImportKey Fails with "Invalid type specified"

I'm trying to use the CryptImportKey function to import a PFX into a Gemalto .NET IDPrime smart cart, but I'm getting a "Invalid Type Specified" (2148073482) error. I suspect that the RSACryptoServiceProvider.ExportCspBlob(true) call is returning the keys in the wrong format. I'm using sample code from http://www.idrix.fr/Root/Samples/PfxImporter.cs. NOTE: I've already set the AllowPrivateExchangeKeyImport & AllowPrivateSignatureKeyImport to 0x1 for the Microsoft Base Smart Card Crypto Provider, but still no change. I'm running Windows Server 2012, but don't think that is the issue.
Can someone please tell me what is wrong with this code sample?
Your issue is certainly caused by the fact that your application is 32-bit running on a 64-bit Windows and you didn't change the Microsoft Base CSP 32-bit registry key located under Wow6432Node.
To solve your issue, change AllowPrivateExchangeKeyImport & AllowPrivateSignatureKeyImport also under "HKLM\SOFTWARE\Wow6432Node\Microsoft\Cryptography\Defaults\Provider\Microsoft Base Smart Card Crypto Provider".
I have update the comment in PfxImporter.cs header to include this remark.

Categories

Resources