Earlier our Application-A was in C++ and a message was signed before sending it to Application-B using crypto API functions in C++ , exactly similar to the example described in http://msdn.microsoft.com/en-us/library/windows/desktop/aa382372%28v=vs.85%29.aspx.
This message was again verified by Application-B using Crypto API functions in C++ (the above example again talks about how to verify an already signed message).
Now we are in the process of converting/migrating the old C++ Application-A to C#.
I already found a way to sign the message using P-Invoke in C# and when the signed message was verified by Application-B (using C++ CryptVerifySignatureMessage) everything is working fine.
Example is available in - http://blogs.msdn.com/b/alejacma/archive/2008/02/21/how-to-sign-a-message-and-verify-a-message-signature-c.aspx .
As #CodeInChaos has mentioned in his comments i want the leave the interop work to the framework (without using P-Invoke or other 3rd party implementation like BountyCastle)
So would like to know whether .net offers any API to sign a message (as a learning perspective too) , if so how can i achieve it.
NOTE:
I already tried crypto wrapper API RSACryptoServiceProvider offered by .Net.
private byte[] SignData(byte[] data, string certThumbPrint)
{
X509Certificate2 cert = GetCertificate(); // finds the certificate with thumbprint
RSACryptoServiceProvider rsaCryptoServiceProvider = (RSACryptoServiceProvider)cert.PrivateKey;
return rsaCryptoServiceProvider.SignData(data, new SHA1CryptoServiceProvider());
}
But found a major difference with the return value (byte array) of CryptSignMessage from C++ and RSACryptoServiceProvider.SignData() method from C#.
• CryptSignMessage: The CryptSignMessage function creates a hash of the specified content, signs the hash, and then encodes both the original message content and the signed hash.
• RSA.SignData: Computes the hash value of the specified byte array using the specified hash algorithm, and signs the resulting hash value.
Because of this difference , the Application-B when it verifies the message it throws error saying 'invalid signing' .
So i cant use this RSACryptoServiceProvider type offered by .net.
Is there any other way to achieve the same using any .NET API's ? (when using .net API the output byte array should be similar to that of output when using PInvoke example as mentioned above) so that Application-B can work without any issues.
Any help is appreciated.
After some long research i found a way to do it . If someone else is looking for how to sign a message using PKCS7 format using a certificate in C# then here it is,
public byte[] SignMsg(
Byte[] msg,
X509Certificate2 signerCert)
{
// Place message in a ContentInfo object.
// This is required to build a SignedCms object.
ContentInfo contentInfo = new ContentInfo(msg);
// Instantiate SignedCms object with the ContentInfo above.
// Has default SubjectIdentifierType IssuerAndSerialNumber.
// Has default Detached property value false, so message is
// included in the encoded SignedCms.
SignedCms signedCms = new SignedCms(contentInfo);
// Formulate a CmsSigner object, which has all the needed
// characteristics of the signer.
CmsSigner cmsSigner = new CmsSigner(signerCert);
// Sign the PKCS #7 message.
Console.Write("Computing signature with signer subject " +
"name {0} ... ", signerCert.SubjectName.Name);
signedCms.ComputeSignature(cmsSigner);
Console.WriteLine("Done.");
// Encode the PKCS #7 message.
return signedCms.Encode();
}
Found the information from the link http://msdn.microsoft.com/en-us/library/ms180961%28v=vs.85%29.aspx .
Related
I've been going in circles trying to get a simple ed25519 signature verification working. Had success with libsodium third party library but then ran into issues with it and am back to the drawing board. I see system.security.cryptography.ecdsa but it's not clear to me if it's possible to get that to work with a ed25519 signature. I'm kind of surprised there aren't code examples of doing this sig verification in .Net because I thought ed25519 was a reasonably common algorithm?
Is there a Microsoft library for ed25519 signature verification? Or can anyone provide an example of how to successfully do this in .Net?
You can use BouncyCastle for this purpose. Below is the code example of how I am doing it. For using this code make sure the publicKey and signature are hex strings.
public Task<bool> VerifySignature(string publicKey, string dataToVerify, string signature)
{
var publicKeyParam = new Ed25519PublicKeyParameters(Hex.DecodeStrict(publicKey));
var dataToVerifyBytes = Encoding.UTF8.GetBytes(dataToVerify);
var signatureBytes = Convert.FromHexString(signature);
var verifier = new Ed25519Signer();
verifier.Init(false, publicKeyParam);
verifier.BlockUpdate(dataToVerifyBytes, 0, dataToVerifyBytes.Length);
var isVerified = verifier.VerifySignature(signatureBytes);
return Task.FromResult(isVerified);
}
I am writing a Java Card 3.0.2 application on a NXP J3D081 card. I have it both signing and verifying a signature using ALG_ECDSA_SHA_256. The keys have been written to the card by my test app. If I sign 32 bytes of data and pass the signature back to the card the Verify code successfully verifies the signature. If I sign 32 bytes in Bouncy Castle with the Private key and pass to the Verify on the Card it successfully verifies the signature. The bouncy castle Verify Code successfully verifies signatures created from the bouncy castle signing routine.
BUT if I take the returned signature from the Java Card and pass it to the C# bouncy castle code it FAILS to verify the signature. I have checked all input values and they are correct. My code is here (note I pass Public keys as 64 bytes and prepend them with 0x04)
public bool HashAndVerifyDSA(byte[] pb, byte[] inData, byte[] sig)
{
byte[] pub = new byte[65];
pub[0] = 0x4;
Array.Copy(pb, 0, pub, 1, 64);
ECCurve curve = parameters.Curve;
ECPoint q = curve.DecodePoint(pub);
ICipherParameters Public = new ECPublicKeyParameters(algorithm, q, parameters);
ISigner bSigner = SignerUtilities.GetSigner("SHA-256withECDSA");
bSigner.Init(false, Public);
bSigner.BlockUpdate(inData, 0, inData.Length);
return (bSigner.VerifySignature(sig));
}
I should note that the parameters specify the P-256 curve and are used successfully in the encrypted communication to the card. The Public key is successfully created.
I seem to have less hair now then I did two days ago. Any pointers would be welcome.
Apart from steps you have performed to debug the thing, you can check the following also: -
Verify the signature using some online available tool. Do not forget to use same curve parameters and public key generated from javacard.
Verify the same using bouncy castle java library. I perform the same steps in one of my tools and it was matched successfully.
I'm trying to generate a self-signed certificate on the fly (programmatically) in a C# assembly (targeting .NET 4.0), to serve as a root CA to generate other certificates. The certificate doesn't need to be persisted in the Windows certificate store, I'll export it as a file.
Reading through this question (and in particular, #dthorpe's answer), I decided to give a try to CLR Security.
The CLR Security library put an extension method on CngKey class to generate a self-signed certificate, but I couldn't succeed in creating an instance of CngKey with:
var key = CngKey.Create(CngAlgorithm.Sha1); //same with Sha256, Sha512 and MD5
//or
var key = CngKey.Create(CngAlgorithm.Sha1, null, new CngKeyCreationParameters()
{
ExportPolicy = CngExportPolicies.AllowExport,
KeyUsage = CngKeyUsages.AllUsages,
KeyCreationOptions = CngKeyCreationOptions.MachineKey,
});
Any of these lines raises the exception:
System.Security.Cryptography.CryptographicException was unhandled
HResult=-2146893783
Message=The requested operation is not supported.
Source=System.Core
StackTrace:
at System.Security.Cryptography.NCryptNative.CreatePersistedKey(SafeNCryptProviderHandle provider, String algorithm, String name, CngKeyCreationOptions options)
at System.Security.Cryptography.CngKey.Create(CngAlgorithm algorithm, String keyName, CngKeyCreationParameters creationParameters)
at System.Security.Cryptography.CngKey.Create(CngAlgorithm algorithm)
at Tests.Program.Main(String[] args) at Program.cs:line 51
Searching through SO and the internet, I've checked the following:
I'm running a Windows 7 box (so it supports RPC as per MSDN)
Tried on a Windows Server 2012 box, same error
The process is running as admin (so it have access to all cert storages, anyway)
The services CNG Key Isolation and Remote Procedure Call (RPC) are running
Any help would be appreciated.
Small off-topic: during google search for this question found a site with HRESULT descriptions and handy search tool on SO and MSDN (I simply googled for your HRESULT code -2146893783)
I found a topic on MSDN which contains code failing with similar HRESULT, and the author provides a link to MSDN article about CNG:
NCRYPT_ALGORITHM_GROUP_PROPERTY
L"Algorithm Group"
A null-terminated Unicode string that contains the name of the object's algorithm group. This property only applies to keys. The following identifiers are returned by the Microsoft key storage provider:
NCRYPT_RSA_ALGORITHM_GROUP
"RSA", The RSA algorithm group.
NCRYPT_DH_ALGORITHM_GROUP
"DH", The Diffie-Hellman algorithm group.
NCRYPT_DSA_ALGORITHM_GROUP
"DSA", The DSA algorithm group.
NCRYPT_ECDSA_ALGORITHM_GROUP
"ECDSA", The elliptic curve DSA algorithm group.
NCRYPT_ECDH_ALGORITHM_GROUP
"ECDH", The elliptic curve Diffie-Hellman algorithm group.
Also I found an article on MSDN about CNG Key Storage Providers, which contains similar list of the algorithms:
Diffie-Hellman (DH)
Secret agreement and key exchange, 512 to 4096 in 64-bit increments
Digital Signature Algorithm (DSA)
Signatures, 512 to 1024 in 64-bit increments
Elliptic Curve Diffie-Hellman (ECDH)
Secret agreement and key exchange, P256, P384, P521
Elliptic Curve Digital Signature Algorithm (ECDSA)
Signatures, P256, P384, P521
RSA
Asymmetric encryption and signing, 512 to 16384 in 64-bit increments
So, as you've said that you've tried only Sha1, Sha256, Sha512 and MD5, maybe you simply use another algorithm from list available? You can find there ones mentioned above:
RSA
ECDsa
P256
P384
P521
ECDiffieHellman
P256
P384
P521
Here other developers successfully created one of them and was able to export it:
var cngKey = CngKey.Create(CngAlgorithm.ECDiffieHellmanP256, null,
new CngKeyCreationParameters { ExportPolicy = CngExportPolicies.AllowPlaintextExport });
I have a requirement to use a public RSA key that a winrt app retrieves from a service.
var decodedKey = CryptographicBuffer.DecodeFromBase64String(serverKey.Value);
So the service delivers my app a base 64 encoded string which is a public rsa key. The key is created using RSA PKCS1 padding.
Reference this post from awhile back:
Windows 8 Metro RSA Encryption: AsymmetricKeyAlgorithmProvider ImportPublicKey Fails
That is exactly what I am trying to do. While it is true that changing the blob type to something other than Pkcs1 like BCryptPublicKey or Capi1PublicKey will allow the server public key to be imported this is only a hack and not a solution.
var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
var decodedKey = CryptographicBuffer.DecodeFromBase64String(serverKey.Value);
var publicKey = provider.ImportPublicKey(decodedKey, CryptographicPublicKeyBlobType.Capi1PublicKey);
When I get to the next step which looks like:
var encryptedBuffer = CryptographicEngine.Encrypt(publicKey, data, null);
Where data is an IBuffer. I received another exception almost certainly due to the fact that the public key was imported as a format that it was not in (Pkcs1 versus Capi1/BCrypt). The exception is an ArgumentException with message "Value does not fall within the expected range.". I did try giving this method some arbirtraru iv buffer instead of null, and that had no effect.
How do you get a .Net 4.5 generated ket to interop with WinRt?
I am trying to implement a SCEP service, my experience with cryptography++ is quite limited so this has been an uphill battle. Currently I am accepting a certificate request from a client, and I am working de interpret the request. The certificate request should be in the form of a CMS/PKCS#7, however I am having great difficulties interpreting it:
When using the ASN.1 edtor at http://lipingshare.com/Asn1Editor/ I just get "Failed to read data".
When using 'openssl asn1parse -inform DER < bytes' on Linux I get something which seems quite sensible. The application should run on Windows .NET so the detr into linux was mainly one of despair.
Trying to decode in .NET fails:
byte[] data = Convert.FromBase64String( input_message );
SignedCms signerInfo = new SignedCms();
EnvelopedCms contentInfo = new EnvelopedCms();
signerInfo.decode(data);
contentInfo.Decode( signerInfo.ContentInfo.Content );
contentInfo.Decrypt();[*]
[*]: This fails with a CryptographicException and message: "Cannot find object or property".
Trying to decode with BouncyCastle .NET classes fails:
byte[] data = Convert.FromBase64String( input_message );
Org.BouncyCastle.Cms.CmsSignedData signedData = new CmsDignedData( data );
Org.BouncyCastle.Cms.CmsEnvelopedData ed = new CmsEnvelopedData( signedD.ContentInfo);[*]
[*] This fails with "ArgumentException" and message: "unknown object in factor: BerTaggedObject".
I realize this does not satisfy StackOverflows requirements of a clear and concise question; but I guess that just reflects the lack of clearness on my side :-( Basically I would be very grateful for any tips on how to to interpret a SCEP message (CMS/PKCS#7) in .NET, using either standard Windows classes or the BouncyCastle API; but to conclude with some concrete questions:
Can I infer something from the fact that asn1parse on Linux seems to handle my message, whereas the Lipingshare Asn.1 editor fails?
The SCEP standards says that the CMS message should be BER encoded; whereas the asn1parse programs takes a '-inform DER' switch (and still works...), and the BouncyCastle class seems to complain about a BERTaggedObject.
Grateful for any ideas, thoughts or suggestions.
Joakim