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
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 want to create web of trust support in my application, allowing my users to use their private keys, to sign other user's public keys - Using C# and Bouncy Castle.
I've got most things figured out, such as creating PGP keys, submitting them to key servers using HTTP REST, encrypting MIME messages and cryptographically signing them (using MimeKit) - But the one remaining hurdle, is to figure out some piece of code that can use my private key, to sign for another person's public key, using Bouncy Castle.
Since the documentation for BC is horrendous, figuring out these parts, have previously proven close to impossible ...
For the record, I'm using GnuPG as my storage for keys.
If anybody wants to look at my code so far for what I have done, feel free to check it out here.
I am probably not supposed to ask this here, but I'd also love it if some BC gurus out there could have a general look at my code so far, and check if I've made a fool of myself with the stuff I've done so far ...
Found the answer after a lot of trial and error, here it is ...
private static byte[] SignPublicKey(
PgpSecretKey secretKey,
string password,
PgpPublicKey keyToBeSigned,
bool isCertain)
{
// Extracting private key, and getting ready to create a signature.
PgpPrivateKey pgpPrivKey = secretKey.ExtractPrivateKey (password.ToCharArray());
PgpSignatureGenerator sGen = new PgpSignatureGenerator (secretKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
sGen.InitSign (isCertain ? PgpSignature.PositiveCertification : PgpSignature.CasualCertification, pgpPrivKey);
// Creating a stream to wrap the results of operation.
Stream os = new MemoryStream();
BcpgOutputStream bOut = new BcpgOutputStream (os);
sGen.GenerateOnePassVersion (false).Encode (bOut);
// Creating a generator.
PgpSignatureSubpacketGenerator spGen = new PgpSignatureSubpacketGenerator();
PgpSignatureSubpacketVector packetVector = spGen.Generate();
sGen.SetHashedSubpackets (packetVector);
bOut.Flush();
// Returning the signed public key.
return PgpPublicKey.AddCertification (keyToBeSigned, sGen.Generate()).GetEncoded();
}
I am developing a tool, that encrypts emails with S/MIME in bulk within Outlook 2013. It works so far, but when I am trying to encrypt a REALLY BIG email (in the test case it was about 60MB raw). I get a COMException stating unsufficient ressources.
I can go around this, by working direktly with EWS and MimeKit (which works like a charm! Thank you #jstedfast), but I'd like to find a way to work in Outlook, for network traffic considerations. I know these changes will be synched to Exchange eventually, but during the process itself, it is independent of bandwidth.
I am also looking at MapiEx, but if there is an easier solution, than having yet another dependency (and with MFC too), I'd be happy! Maybe there are some settings, I'd have to make before.
A bit of code. The Exception it caught somewhere else.
public void String SetEncryption(MailItem mailItem)
{
PropertyAccessor pa = null;
try
{
pa = mailItem.PropertyAccessor;
Int32 prop = (int)pa.GetProperty(_PR_SECURITY_FLAGS);
Int32 newprop = prop | 1;
pa.SetProperty(_PR_SECURITY_FLAGS, newprop);
}
finally
{
Marshal.FinalReleaseComObject(pa);
pa = null;
}
}
Edit: The Exception is not coming, when the encryption is set, but when the result is saved, after the encryption is set.
SetEncryption(mailItem);
mailItem.Save();
I solved it myself.
Since I had the problems in Outlook itself, I was trying MAPIEx to access the raw S/MIME Attachment in the email and de-/encrypt it using MimeKit/BouncyCastle.
The same problem occoured, but with a different error message, which lead me to the following site: ASN.1 value too large.
To sum it up: The Crypto API has two signatures. One which takes a byte array and one, which takes a stream. The first one has an arbitrary imposed (!!!) limit of 100 Million Bytes. Since the enveloped CMS has double base64 the ratio of this 100 MB is 9/16, which is round about 56 MB.
I assume, that Outlook uses the same API-Call and therefore has this limit.
I know it is not a fact, but the evidence strongly supports this theory. :)
Check if KB 2480994 is installed: http://support.microsoft.com/kb/2480994
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 .
I have a large amount of data encrypted with the CAPICOM library through our legacy VB6 applications.
I need to access this data from a .Net 3.5 app but am getting the error: "ASN1 bad tag value met" when I call the Decrypt method. Google has been little help in tracking down decent code samples or explanations as to what this error means.
The following code is almost exactly a replication of what was happening in the VB6 code:
static string DecryptEncryptedText(string encryptedText, string secretKey)
{
var encryptedDataObj = new CAPICOM.EncryptedData();
encryptedDataObj.SetSecret(secretKey, CAPICOM_SECRET_TYPE.CAPICOM_SECRET_PASSWORD);
encryptedDataObj.Decrypt(encryptedText);
return encryptedDataObj.Content;
}
When I get this error it has been because I used the wrong key to decrypt. Have you checked the encoding of your secretKey? I suspect the data was encrypted with an ANSI string in VB6 and you are using a Unicode string in your new code.