/// <summary> /// Decrypt the specified encryptedData. /// </summary> /// <returns>The decrypted <see cref="MimeKit.MimeEntity"/>.</returns> /// <param name="encryptedData">The encrypted data.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="encryptedData"/> is <c>null</c>. /// </exception> /// <exception cref="Org.BouncyCastle.Cms.CmsException"> /// An error occurred in the cryptographic message syntax subsystem. /// </exception> public override MimeEntity Decrypt(Stream encryptedData) { if (encryptedData == null) throw new ArgumentNullException ("encryptedData"); var parser = new CmsEnvelopedDataParser (encryptedData); var recipients = parser.GetRecipientInfos (); var algorithm = parser.EncryptionAlgorithmID; AsymmetricKeyParameter key; foreach (RecipientInformation recipient in recipients.GetRecipients ()) { if ((key = GetPrivateKey (recipient.RecipientID)) == null) continue; var content = recipient.GetContent (key); using (var memory = new MemoryStream (content, false)) { return MimeEntity.Load (memory); } } throw new CmsException ("A suitable private key could not be found for decrypting."); }
public void TestOriginatorInfo() { CmsEnvelopedDataParser env = new CmsEnvelopedDataParser(CmsSampleMessages.originatorMessage); env.GetRecipientInfos(); Assert.AreEqual(CmsEnvelopedDataGenerator.DesEde3Cbc, env.EncryptionAlgOid); }
public void TestWorkingData() { byte[] keyData = Base64.Decode( "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKrAz/SQKrcQ" + "nj9IxHIfKDbuXsMqUpI06s2gps6fp7RDNvtUDDMOciWGFhD45YSy8GO0mPx3" + "Nkc7vKBqX4TLcqLUz7kXGOHGOwiPZoNF+9jBMPNROe/B0My0PkWg9tuq+nxN" + "64oD47+JvDwrpNOS5wsYavXeAW8Anv9ZzHLU7KwZAgMBAAECgYA/fqdVt+5K" + "WKGfwr1Z+oAHvSf7xtchiw/tGtosZ24DOCNP3fcTXUHQ9kVqVkNyzt9ZFCT3" + "bJUAdBQ2SpfuV4DusVeQZVzcROKeA09nPkxBpTefWbSDQGhb+eZq9L8JDRSW" + "HyYqs+MBoUpLw7GKtZiJkZyY6CsYkAnQ+uYVWq/TIQJBAP5zafO4HUV/w4KD" + "VJi+ua+GYF1Sg1t/dYL1kXO9GP1p75YAmtm6LdnOCas7wj70/G1YlPGkOP0V" + "GFzeG5KAmAUCQQCryvKU9nwWA+kypcQT9Yr1P4vGS0APYoBThnZq7jEPc5Cm" + "ZI82yseSxSeea0+8KQbZ5mvh1p3qImDLEH/iNSQFAkAghS+tboKPN10NeSt+" + "uiGRRWNbiggv0YJ7Uldcq3ZeLQPp7/naiekCRUsHD4Qr97OrZf7jQ1HlRqTu" + "eZScjMLhAkBNUMZCQnhwFAyEzdPkQ7LpU1MdyEopYmRssuxijZao5JLqQAGw" + "YCzXokGFa7hz72b09F4DQurJL/WuDlvvu4jdAkEAxwT9lylvfSfEQw4/qQgZ" + "MFB26gqB6Gqs1pHIZCzdliKx5BO3VDeUGfXMI8yOkbXoWbYx5xPid/+N8R//" + "+sxLBw=="); byte[] envData = Base64.Decode( "MIAGCSqGSIb3DQEHA6CAMIACAQAxgcQwgcECAQAwKjAlMRYwFAYDVQQKEw1C" + "b3VuY3kgQ2FzdGxlMQswCQYDVQQGEwJBVQIBHjANBgkqhkiG9w0BAQEFAASB" + "gDmnaDZ0vDJNlaUSYyEXsgbaUH+itNTjCOgv77QTX2ImXj+kTctM19PQF2I1" + "0/NL0fjakvCgBTHKmk13a7jqB6cX3bysenHNrglHsgNGgeXQ7ggAq5fV/JQQ" + "T7rSxEtuwpbuHQnoVUZahOHVKy/a0uLr9iIh1A3y+yZTZaG505ZJMIAGCSqG" + "SIb3DQEHATAdBglghkgBZQMEAQIEENmkYNbDXiZxJWtq82qIRZKggAQgkOGr" + "1JcTsADStez1eY4+rO4DtyBIyUYQ3pilnbirfPkAAAAAAAAAAAAA"); CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(envData); RecipientInformationStore recipients = ep.GetRecipientInfos(); Assert.AreEqual(ep.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc); ICollection c = recipients.GetRecipients(); // PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyData); // KeyFactory keyFact = KeyFactory.GetInstance("RSA"); // Key priKey = keyFact.generatePrivate(keySpec); AsymmetricKeyParameter priKey = PrivateKeyFactory.CreateKey(keyData); byte[] data = Hex.Decode("57616c6c6157616c6c6157617368696e67746f6e"); foreach (RecipientInformation recipient in c) { Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id); CmsTypedStream recData = recipient.GetContentStream(priKey); byte[] compare = CmsTestUtil.StreamToByteArray(recData.ContentStream); Assert.IsTrue(Arrays.AreEqual(data, compare)); } }
public void TestTwoAesKek() { byte[] data = Encoding.Default.GetBytes("WallaWallaWashington"); KeyParameter kek1 = CmsTestUtil.MakeAes192Key(); KeyParameter kek2 = CmsTestUtil.MakeAes192Key(); CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator(); byte[] kekId1 = new byte[] { 1, 2, 3, 4, 5 }; byte[] kekId2 = new byte[] { 5, 4, 3, 2, 1 }; edGen.AddKekRecipient("AES192", kek1, kekId1); edGen.AddKekRecipient("AES192", kek2, kekId2); MemoryStream bOut = new MemoryStream(); Stream outStream = edGen.Open( bOut, CmsEnvelopedDataGenerator.DesEde3Cbc); outStream.Write(data, 0, data.Length); outStream.Close(); CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(bOut.ToArray()); RecipientInformationStore recipients = ep.GetRecipientInfos(); Assert.AreEqual(ep.EncryptionAlgOid, CmsEnvelopedDataGenerator.DesEde3Cbc); RecipientID recSel = new RecipientID(); recSel.KeyIdentifier = kekId2; RecipientInformation recipient = recipients.GetFirstRecipient(recSel); Assert.AreEqual(recipient.KeyEncryptionAlgOid, "2.16.840.1.101.3.4.1.25"); CmsTypedStream recData = recipient.GetContentStream(kek2); Assert.IsTrue(Arrays.AreEqual(data, CmsTestUtil.StreamToByteArray(recData.ContentStream))); ep.Close(); }
public void TestECKeyAgree() { byte[] data = Hex.Decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65"); CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator(); edGen.AddKeyAgreementRecipient( CmsEnvelopedDataGenerator.ECDHSha1Kdf, OrigECKP.Private, OrigECKP.Public, ReciECCert, CmsEnvelopedDataGenerator.Aes128Wrap); MemoryStream bOut = new MemoryStream(); Stream outStr = edGen.Open(bOut, CmsEnvelopedDataGenerator.Aes128Cbc); outStr.Write(data, 0, data.Length); outStr.Close(); CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(bOut.ToArray()); RecipientInformationStore recipients = ep.GetRecipientInfos(); Assert.AreEqual(ep.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc); RecipientID recSel = new RecipientID(); // recSel.SetIssuer(PrincipalUtilities.GetIssuerX509Principal(ReciECCert).GetEncoded()); recSel.Issuer = PrincipalUtilities.GetIssuerX509Principal(ReciECCert); recSel.SerialNumber = ReciECCert.SerialNumber; RecipientInformation recipient = recipients.GetFirstRecipient(recSel); CmsTypedStream recData = recipient.GetContentStream(ReciECKP.Private); Assert.IsTrue(Arrays.AreEqual(data, CmsTestUtil.StreamToByteArray(recData.ContentStream))); ep.Close(); }
public void TestAesKek() { byte[] data = Encoding.Default.GetBytes("WallaWallaWashington"); KeyParameter kek = CmsTestUtil.MakeAes192Key(); CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator(); byte[] kekId = new byte[] { 1, 2, 3, 4, 5 }; edGen.AddKekRecipient("AES192", kek, kekId); MemoryStream bOut = new MemoryStream(); Stream outStream = edGen.Open( bOut, CmsEnvelopedDataGenerator.DesEde3Cbc); outStream.Write(data, 0, data.Length); outStream.Close(); CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(bOut.ToArray()); RecipientInformationStore recipients = ep.GetRecipientInfos(); Assert.AreEqual(ep.EncryptionAlgOid, CmsEnvelopedDataGenerator.DesEde3Cbc); ICollection c = recipients.GetRecipients(); foreach (RecipientInformation recipient in c) { Assert.AreEqual(recipient.KeyEncryptionAlgOid, "2.16.840.1.101.3.4.1.25"); CmsTypedStream recData = recipient.GetContentStream(kek); Assert.IsTrue(Arrays.AreEqual(data, CmsTestUtil.StreamToByteArray(recData.ContentStream))); } ep.Close(); }
public void TestKeyTransAes128() { byte[] data = Encoding.Default.GetBytes("WallaWallaWashington"); CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator(); edGen.AddKeyTransRecipient(ReciCert); MemoryStream bOut = new MemoryStream(); Stream outStream = edGen.Open( bOut, CmsEnvelopedDataGenerator.Aes128Cbc); outStream.Write(data, 0, data.Length); outStream.Close(); CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(bOut.ToArray()); RecipientInformationStore recipients = ep.GetRecipientInfos(); Assert.AreEqual(ep.EncryptionAlgOid, CmsEnvelopedDataGenerator.Aes128Cbc); ICollection c = recipients.GetRecipients(); foreach (RecipientInformation recipient in c) { Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id); CmsTypedStream recData = recipient.GetContentStream(ReciKP.Private); Assert.IsTrue(Arrays.AreEqual(data, CmsTestUtil.StreamToByteArray(recData.ContentStream))); } ep.Close(); }
public void TestKeyTransAes128Throughput() { byte[] data = new byte[40001]; for (int i = 0; i != data.Length; i++) { data[i] = (byte)(i & 0xff); } // // buffered // CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator(); edGen.SetBufferSize(BufferSize); edGen.AddKeyTransRecipient(ReciCert); MemoryStream bOut = new MemoryStream(); Stream outStream = edGen.Open(bOut, CmsEnvelopedDataGenerator.Aes128Cbc); for (int i = 0; i != data.Length; i++) { outStream.WriteByte(data[i]); } outStream.Close(); CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(bOut.ToArray()); RecipientInformationStore recipients = ep.GetRecipientInfos(); ICollection c = recipients.GetRecipients(); IEnumerator e = c.GetEnumerator(); if (e.MoveNext()) { RecipientInformation recipient = (RecipientInformation) e.Current; Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id); CmsTypedStream recData = recipient.GetContentStream(ReciKP.Private); Stream dataStream = recData.ContentStream; MemoryStream dataOut = new MemoryStream(); int len; byte[] buf = new byte[BufferSize]; int count = 0; while (count != 10 && (len = dataStream.Read(buf, 0, buf.Length)) > 0) { Assert.AreEqual(buf.Length, len); dataOut.Write(buf, 0, buf.Length); count++; } len = dataStream.Read(buf, 0, buf.Length); dataOut.Write(buf, 0, len); Assert.IsTrue(Arrays.AreEqual(data, dataOut.ToArray())); } else { Assert.Fail("recipient not found."); } }
private void VerifyData( byte[] encodedBytes, string expectedOid, byte[] expectedData) { CmsEnvelopedDataParser ep = new CmsEnvelopedDataParser(encodedBytes); RecipientInformationStore recipients = ep.GetRecipientInfos(); Assert.AreEqual(ep.EncryptionAlgOid, expectedOid); ICollection c = recipients.GetRecipients(); foreach (RecipientInformation recipient in c) { Assert.AreEqual(recipient.KeyEncryptionAlgOid, PkcsObjectIdentifiers.RsaEncryption.Id); CmsTypedStream recData = recipient.GetContentStream(ReciKP.Private); Assert.IsTrue(Arrays.AreEqual(expectedData, CmsTestUtil.StreamToByteArray( recData.ContentStream))); } }
private SecurityInformation Decrypt(Stream clear, Stream cypher, SecretKey key, DateTime? sealedOn) { int i; bool found; StringBuilder algos; DateTime date = sealedOn == null ? DateTime.UtcNow : sealedOn.Value; trace.TraceEvent(TraceEventType.Information, 0, "Decrypting message for {0} recipient", key == null ? "known" : "unknown"); try { SecurityInformation result = new SecurityInformation(); CmsEnvelopedDataParser cypherData; try { cypherData = new CmsEnvelopedDataParser(cypher); trace.TraceEvent(TraceEventType.Verbose, 0, "Read the cms header"); } catch (Exception e) { trace.TraceEvent(TraceEventType.Error, 0, "The messages isn't encrypted"); throw new InvalidMessageException("The message isn't a triple wrapped message", e); } RecipientInformationStore recipientInfos = cypherData.GetRecipientInfos(); trace.TraceEvent(TraceEventType.Verbose, 0, "Got the recipient info of the encrypted message"); i = 0; found = false; algos = new StringBuilder(); string encryptionAlgOid = cypherData.EncryptionAlgOid; while (!found && i < EteeActiveConfig.Unseal.EncryptionAlgorithms.Count) { Oid algo = EteeActiveConfig.Unseal.EncryptionAlgorithms[i++]; algos.Append(algo.Value + " (" + algo.FriendlyName + ") "); found = algo.Value == encryptionAlgOid; } if (!found) { result.securityViolations.Add(SecurityViolation.NotAllowedEncryptionAlgorithm); trace.TraceEvent(TraceEventType.Warning, 0, "The encryption algorithm {0} isn't allowed, only {1} are", encryptionAlgOid, algos); } trace.TraceEvent(TraceEventType.Verbose, 0, "The encryption algorithm is verified: {0}", encryptionAlgOid); //Key size of the message should not be checked, size is determined by the algorithm //Get recipient, should be receiver. RecipientInformation recipientInfo; ICipherParameters recipientKey; if (key == null) { if (encCertStore != null) { //Find find a matching receiver ICollection recipients = recipientInfos.GetRecipients(); //recipients in the message IList<KeyValuePair<RecipientInformation, IList>> allMatches = new List<KeyValuePair<RecipientInformation, IList>>(); foreach (RecipientInformation recipient in recipients) { trace.TraceEvent(TraceEventType.Verbose, 0, "The message is addressed to {0} ({1})", recipient.RecipientID.SerialNumber, recipient.RecipientID.Issuer); if (recipient is KeyTransRecipientInformation) { IList matches = (IList) encCertStore.GetMatches(recipient.RecipientID); if (matches.Count > 0) { allMatches.Add(new KeyValuePair<RecipientInformation, IList>(recipient, matches)); } } } //Did we find a receiver? if (allMatches.Count == 0) { trace.TraceEvent(TraceEventType.Error, 0, "The recipients doe not contain any of your your encryption certificates"); throw new InvalidMessageException("The message isn't a message that is addressed to you. Or it is an unaddressed message or it is addressed to somebody else"); } //check with encryption cert matches where valid at creation time IList<KeyValuePair<RecipientInformation, IList>> validMatches = new List<KeyValuePair<RecipientInformation, IList>>(); foreach (KeyValuePair<RecipientInformation, IList> match in allMatches) { IList validCertificate = new List<X509Certificate2>(); foreach (X509Certificate2 cert in match.Value) { //Validate the description cert, providing minimal info to force minimal validation. CertificateSecurityInformation certVerRes = CertVerifier.VerifyEnc(DotNetUtilities.FromX509Certificate(cert), null, date, null, false); trace.TraceEvent(TraceEventType.Verbose, 0, "Validated potential decryption certificate ({0}) : Validation Status = {1}, Trust Status = {2}", cert.Subject, certVerRes.ValidationStatus, certVerRes.TrustStatus); if (certVerRes.SecurityViolations.Count == 0) { validCertificate.Add(cert); } } if (validCertificate.Count > 0) { validMatches.Add(new KeyValuePair<RecipientInformation, IList>(match.Key, validCertificate)); } } //If we have a valid encCert use that one, otherwise use an invalid one (at least we can read it, but should not use it) X509Certificate2 selectedCert; if (validMatches.Count > 0) { selectedCert = (X509Certificate2)validMatches[0].Value[0]; recipientInfo = validMatches[0].Key; trace.TraceEvent(TraceEventType.Information, 0, "Found valid decryption certificate ({0}) that matches one the the recipients", selectedCert.Subject); } else { selectedCert = (X509Certificate2)allMatches[0].Value[0]; recipientInfo = allMatches[0].Key; trace.TraceEvent(TraceEventType.Warning, 0, "Found *invalid* decryption certificate ({0}) that matches one the the recipients", selectedCert.Subject); } recipientKey = DotNetUtilities.GetKeyPair(selectedCert.PrivateKey).Private; //we validate the selected certificate again to inform the caller result.Subject = CertVerifier.VerifyEnc(DotNetUtilities.FromX509Certificate(selectedCert), null, date, null, false); } else { trace.TraceEvent(TraceEventType.Error, 0, "The unsealer does not have an decryption certificate and no symmetric key was provided"); throw new InvalidOperationException("There should be an receiver (=yourself) and/or a key provided"); } } else { trace.TraceEvent(TraceEventType.Verbose, 0, "Found symmetric key: {0}", key.IdString); RecipientID recipientId = new RecipientID(); recipientId.KeyIdentifier = key.Id; recipientInfo = recipientInfos.GetFirstRecipient(recipientId); if (recipientInfo == null) { trace.TraceEvent(TraceEventType.Error, 0, "The symmetric key was not found in this cms message"); throw new InvalidMessageException("The key isn't for this unaddressed message"); } trace.TraceEvent(TraceEventType.Verbose, 0, "Found symmetric key in recipients of the cms message"); //Get receivers key recipientKey = key.BCKey; //Validate the unaddressed key if ((((KeyParameter)recipientKey).GetKey().Length * 8) < EteeActiveConfig.Unseal.MinimumEncryptionKeySize.SymmetricRecipientKey) { result.securityViolations.Add(SecurityViolation.NotAllowedEncryptionKeySize); trace.TraceEvent(TraceEventType.Warning, 0, "The symmetric key was only {0} bits while it should be at least {0}", ((KeyParameter)recipientKey).GetKey().Length * 8, EteeActiveConfig.Unseal.MinimumEncryptionKeySize.SymmetricRecipientKey); } } //check if key encryption algorithm is allowed i = 0; found = false; algos = new StringBuilder(); while (!found && i < EteeActiveConfig.Unseal.KeyEncryptionAlgorithms.Count) { Oid algo = EteeActiveConfig.Unseal.KeyEncryptionAlgorithms[i++]; algos.Append(algo.Value + " (" + algo.FriendlyName + ") "); found = algo.Value == recipientInfo.KeyEncryptionAlgOid; } if (!found) { result.securityViolations.Add(SecurityViolation.NotAllowedKeyEncryptionAlgorithm); trace.TraceEvent(TraceEventType.Warning, 0, "Encryption algorithm is {0} while it should be one of the following {1}", recipientInfo.KeyEncryptionAlgOid, algos); } trace.TraceEvent(TraceEventType.Verbose, 0, "Finished verifying the encryption algorithm: {0}", recipientInfo.KeyEncryptionAlgOid); //Decrypt! CmsTypedStream clearStream = recipientInfo.GetContentStream(recipientKey); trace.TraceEvent(TraceEventType.Verbose, 0, "Accessed the encrypted content"); try { clearStream.ContentStream.CopyTo(clear); trace.TraceEvent(TraceEventType.Verbose, 0, "Decrypted the content"); } finally { clearStream.ContentStream.Close(); } return result; } catch (CmsException cmse) { trace.TraceEvent(TraceEventType.Error, 0, "The message isn't a CMS message"); throw new InvalidMessageException("The message isn't a triple wrapped message", cmse); } }