static Stream Encrypt (PgpEncryptedDataGenerator encrypter, Stream content) { var memory = new MemoryBlockStream (); using (var armored = new ArmoredOutputStream (memory)) { using (var compressed = Compress (content)) { using (var encrypted = encrypter.Open (armored, compressed.Length)) { compressed.CopyTo (encrypted, 4096); encrypted.Flush (); } } armored.Flush (); } memory.Position = 0; return memory; }
/// <summary> /// Exports the specified public keys. /// </summary> /// <remarks> /// Exports the specified public keys. /// </remarks> /// <returns>A new <see cref="MimeKit.MimePart"/> instance containing the exported public keys.</returns> /// <param name="keys">The keys.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="keys"/> is <c>null</c>. /// </exception> public MimePart Export (PgpPublicKeyRingBundle keys) { if (keys == null) throw new ArgumentNullException ("keys"); var content = new MemoryBlockStream (); using (var armored = new ArmoredOutputStream (content)) { keys.Encode (armored); armored.Flush (); } content.Position = 0; return new MimePart ("application", "pgp-keys") { ContentDisposition = new ContentDisposition ("attachment"), ContentObject = new ContentObject (content) }; }
/// <summary> /// Cryptographically signs the content. /// </summary> /// <remarks> /// Cryptographically signs the content using the specified signer and digest algorithm. /// </remarks> /// <returns>A new <see cref="MimeKit.MimePart"/> instance /// containing the detached signature data.</returns> /// <param name="signer">The signer.</param> /// <param name="digestAlgo">The digest algorithm to use for signing.</param> /// <param name="content">The content.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="signer"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="content"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentException"> /// <paramref name="signer"/> cannot be used for signing. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// The <paramref name="digestAlgo"/> was out of range. /// </exception> /// <exception cref="System.NotSupportedException"> /// The <paramref name="digestAlgo"/> is not supported. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The user chose to cancel the password prompt. /// </exception> /// <exception cref="System.UnauthorizedAccessException"> /// 3 bad attempts were made to unlock the secret key. /// </exception> public ApplicationPgpSignature Sign (PgpSecretKey signer, DigestAlgorithm digestAlgo, Stream content) { if (signer == null) throw new ArgumentNullException ("signer"); if (!signer.IsSigningKey) throw new ArgumentException ("The specified secret key cannot be used for signing.", "signer"); if (content == null) throw new ArgumentNullException ("content"); var hashAlgorithm = GetHashAlgorithm (digestAlgo); var memory = new MemoryBlockStream (); using (var armored = new ArmoredOutputStream (memory)) { var compresser = new PgpCompressedDataGenerator (CompressionAlgorithmTag.ZLib); using (var compressed = compresser.Open (armored)) { var signatureGenerator = new PgpSignatureGenerator (signer.PublicKey.Algorithm, hashAlgorithm); var buf = new byte[4096]; int nread; signatureGenerator.InitSign (PgpSignature.CanonicalTextDocument, GetPrivateKey (signer)); while ((nread = content.Read (buf, 0, buf.Length)) > 0) signatureGenerator.Update (buf, 0, nread); var signature = signatureGenerator.Generate (); signature.Encode (compressed); compressed.Flush (); } armored.Flush (); } memory.Position = 0; return new ApplicationPgpSignature (memory); }
/// <summary> /// Cryptographically signs and encrypts the specified content for the specified recipients. /// </summary> /// <remarks> /// Cryptographically signs and encrypts the specified content for the specified recipients. /// </remarks> /// <returns>A new <see cref="MimeKit.MimePart"/> instance /// containing the encrypted data.</returns> /// <param name="signer">The signer.</param> /// <param name="digestAlgo">The digest algorithm to use for signing.</param> /// <param name="cipherAlgo">The encryption algorithm.</param> /// <param name="recipients">The recipients.</param> /// <param name="content">The content.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="signer"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="recipients"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="content"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentException"> /// <para><paramref name="signer"/> cannot be used for signing.</para> /// <para>-or-</para> /// <para>One or more of the recipient keys cannot be used for encrypting.</para> /// <para>-or-</para> /// <para>No recipients were specified.</para> /// </exception> /// <exception cref="System.NotSupportedException"> /// The specified encryption algorithm is not supported. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The user chose to cancel the password prompt. /// </exception> /// <exception cref="System.UnauthorizedAccessException"> /// 3 bad attempts were made to unlock the secret key. /// </exception> public MimePart SignAndEncrypt (PgpSecretKey signer, DigestAlgorithm digestAlgo, EncryptionAlgorithm cipherAlgo, IEnumerable<PgpPublicKey> recipients, Stream content) { // TODO: document the exceptions that can be thrown by BouncyCastle if (signer == null) throw new ArgumentNullException ("signer"); if (!signer.IsSigningKey) throw new ArgumentException ("The specified secret key cannot be used for signing.", "signer"); if (recipients == null) throw new ArgumentNullException ("recipients"); if (content == null) throw new ArgumentNullException ("content"); var encrypter = new PgpEncryptedDataGenerator (GetSymmetricKeyAlgorithm (cipherAlgo), true); var hashAlgorithm = GetHashAlgorithm (digestAlgo); int count = 0; foreach (var recipient in recipients) { if (!recipient.IsEncryptionKey) throw new ArgumentException ("One or more of the recipient keys cannot be used for encrypting.", "recipients"); encrypter.AddMethod (recipient); count++; } if (count == 0) throw new ArgumentException ("No recipients specified.", "recipients"); var compresser = new PgpCompressedDataGenerator (CompressionAlgorithmTag.ZLib); using (var compressed = new MemoryBlockStream ()) { using (var signed = compresser.Open (compressed)) { var signatureGenerator = new PgpSignatureGenerator (signer.PublicKey.Algorithm, hashAlgorithm); signatureGenerator.InitSign (PgpSignature.CanonicalTextDocument, GetPrivateKey (signer)); var subpacket = new PgpSignatureSubpacketGenerator (); foreach (string userId in signer.PublicKey.GetUserIds ()) { subpacket.SetSignerUserId (false, userId); break; } signatureGenerator.SetHashedSubpackets (subpacket.Generate ()); var onepass = signatureGenerator.GenerateOnePassVersion (false); onepass.Encode (signed); var literalGenerator = new PgpLiteralDataGenerator (); using (var literal = literalGenerator.Open (signed, 't', "mime.txt", content.Length, DateTime.Now)) { var buf = new byte[4096]; int nread; while ((nread = content.Read (buf, 0, buf.Length)) > 0) { signatureGenerator.Update (buf, 0, nread); literal.Write (buf, 0, nread); } literal.Flush (); } var signature = signatureGenerator.Generate (); signature.Encode (signed); signed.Flush (); } compressed.Position = 0; var memory = new MemoryBlockStream (); using (var armored = new ArmoredOutputStream (memory)) { using (var encrypted = encrypter.Open (armored, compressed.Length)) { compressed.CopyTo (encrypted, 4096); encrypted.Flush (); } armored.Flush (); } memory.Position = 0; return new MimePart ("application", "octet-stream") { ContentDisposition = new ContentDisposition ("attachment"), ContentObject = new ContentObject (memory) }; } }