public static bool ReadAndVerifyFile(Stream inputStream, Stream keyIn, out Stream cleartextOut) { // Count any exception as BouncyCastle failing to parse something, because of corruption maybe? try { // Disposing this will close the underlying stream, which we don't want to do var armouredInputStream = new ArmoredInputStream(inputStream); // This stream is returned, so is not disposed var cleartextStream = new MemoryStream(); int chr; while ((chr = armouredInputStream.ReadByte()) >= 0 && armouredInputStream.IsClearText()) { cleartextStream.WriteByte((byte)chr); } // Strip the trailing newline if set... cleartextStream.Position = Math.Max(0, cleartextStream.Position - 2); int count = 0; if (cleartextStream.ReadByte() == '\r') count++; if (cleartextStream.ReadByte() == '\n') count++; cleartextStream.SetLength(cleartextStream.Length - count); cleartextStream.Position = 0; // This will either return inputStream, or a new ArmouredStream(inputStream) // Either way, disposing it will close the underlying stream, which we don't want to do var decoderStream = PgpUtilities.GetDecoderStream(inputStream); var pgpObjectFactory = new PgpObjectFactory(decoderStream); var signatureList = (PgpSignatureList)pgpObjectFactory.NextPgpObject(); var signature = signatureList[0]; var publicKeyRing = new PgpPublicKeyRingBundle(PgpUtilities.GetDecoderStream(keyIn)); var publicKey = publicKeyRing.GetPublicKey(signature.KeyId); signature.InitVerify(publicKey); while ((chr = cleartextStream.ReadByte()) > 0) { signature.Update((byte)chr); } cleartextStream.Position = 0; cleartextOut = cleartextStream; return signature.Verify(); } catch { cleartextOut = null; return false; } }
/// <summary> /// Decrypt and verify signature of data. /// </summary> /// <param name="data">Data to decrypt and verify</param> /// <returns>Returns decrypted data if signature verifies.</returns> public byte[] DecryptAndVerify(byte[] data, bool ignoreIntegrityCheck = false) { Context = new CryptoContext(Context); var isArmored = ASCIIEncoding.ASCII.GetString(data).IndexOf("-----BEGIN PGP MESSAGE-----") > -1; using (var dataIn = new MemoryStream(data)) { if (isArmored) { using (var armoredIn = new ArmoredInputStream(dataIn)) { var factory = new PgpObjectFactory(armoredIn); while (true) { var obj = factory.NextPgpObject(); if (obj is PgpMarker) continue; var ret = DecryptHandlePgpObject(obj); if (Context.FailedIntegrityCheck && !ignoreIntegrityCheck) throw new VerifyException("Data not integrity protected."); return ret; } } } else { var factory = new PgpObjectFactory(dataIn); while (true) { var obj = factory.NextPgpObject(); if (obj is PgpMarker) continue; var ret = DecryptHandlePgpObject(obj); if (Context.FailedIntegrityCheck && !ignoreIntegrityCheck) throw new VerifyException("Data not integrity protected."); return ret; } } } }
/// <summary> /// Decrypt and verify signature of data. /// </summary> /// <param name="data">Data to decrypt and verify</param> /// <returns>Returns decrypted data if signature verifies.</returns> public byte[] DecryptAndVerify(byte[] data) { Context = new CryptoContext(Context); var isArmored = ASCIIEncoding.ASCII.GetString(data).IndexOf("-----BEGIN PGP MESSAGE-----") > -1; using (var dataIn = new MemoryStream(data)) { if (isArmored) { using (var armoredIn = new ArmoredInputStream(dataIn)) { var factory = new PgpObjectFactory(armoredIn); while (true) { var obj = factory.NextPgpObject(); if (obj is PgpMarker) continue; var ret = DecryptHandlePgpObject(obj); return ret; } } } else { var factory = new PgpObjectFactory(dataIn); while (true) { var obj = factory.NextPgpObject(); if (obj is PgpMarker) continue; var ret = DecryptHandlePgpObject(obj); return ret; } } } }
/// <summary> /// Verifies the specified content using the detached signatureData. /// </summary> /// <remarks> /// Verifies the specified content using the detached signatureData. /// </remarks> /// <returns>A list of digital signatures.</returns> /// <param name="content">The content.</param> /// <param name="signatureData">The signature data.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="content"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="signatureData"/> is <c>null</c>.</para> /// </exception> public override DigitalSignatureCollection Verify (Stream content, Stream signatureData) { if (content == null) throw new ArgumentNullException ("content"); if (signatureData == null) throw new ArgumentNullException ("signatureData"); using (var armored = new ArmoredInputStream (signatureData)) { var factory = new PgpObjectFactory (armored); var data = factory.NextPgpObject (); PgpSignatureList signatureList; var compressed = data as PgpCompressedData; if (compressed != null) { factory = new PgpObjectFactory (compressed.GetDataStream ()); data = factory.NextPgpObject (); } signatureList = (PgpSignatureList) data; return GetDigitalSignatures (signatureList, content); } }
/// <summary> /// Imports secret pgp keys from the specified stream. /// </summary> /// <remarks> /// Imports secret pgp keys from the specified stream. /// </remarks> /// <param name="rawData">The raw key data.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="rawData"/> is <c>null</c>. /// </exception> /// <exception cref="System.IO.IOException"> /// <para>An error occurred while parsing the raw key-ring data</para> /// <para>-or-</para> /// <para>An error occured while saving the public key-ring bundle.</para> /// </exception> public virtual void ImportSecretKeys (Stream rawData) { if (rawData == null) throw new ArgumentNullException ("rawData"); using (var armored = new ArmoredInputStream (rawData)) { var imported = new PgpSecretKeyRingBundle (armored); if (imported.Count == 0) return; int secretKeysAdded = 0; foreach (PgpSecretKeyRing secring in imported.GetKeyRings ()) { if (!SecretKeyRingBundle.Contains (secring.GetSecretKey ().KeyId)) { SecretKeyRingBundle = PgpSecretKeyRingBundle.AddSecretKeyRing (SecretKeyRingBundle, secring); secretKeysAdded++; } } if (secretKeysAdded > 0) SaveSecretKeyRingBundle (); } }
/// <summary> /// Imports public pgp keys from the specified stream. /// </summary> /// <remarks> /// Imports public pgp keys from the specified stream. /// </remarks> /// <param name="stream">The raw key data.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="stream"/> is <c>null</c>. /// </exception> /// <exception cref="System.IO.IOException"> /// <para>An error occurred while parsing the raw key-ring data</para> /// <para>-or-</para> /// <para>An error occured while saving the public key-ring bundle.</para> /// </exception> public override void Import (Stream stream) { if (stream == null) throw new ArgumentNullException ("stream"); using (var armored = new ArmoredInputStream (stream)) { var imported = new PgpPublicKeyRingBundle (armored); if (imported.Count == 0) return; int publicKeysAdded = 0; foreach (PgpPublicKeyRing pubring in imported.GetKeyRings ()) { if (!PublicKeyRingBundle.Contains (pubring.GetPublicKey ().KeyId)) { PublicKeyRingBundle = PgpPublicKeyRingBundle.AddPublicKeyRing (PublicKeyRingBundle, pubring); publicKeysAdded++; } } if (publicKeysAdded > 0) SavePublicKeyRingBundle (); } }
/// <summary> /// Decrypts the specified encryptedData and extracts the digital signers if the content was also signed. /// </summary> /// <remarks> /// Decrypts the specified encryptedData and extracts the digital signers if the content was also signed. /// </remarks> /// <returns>The decrypted stream.</returns> /// <param name="encryptedData">The encrypted data.</param> /// <param name="signatures">A list of digital signatures if the data was both signed and encrypted.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="encryptedData"/> is <c>null</c>. /// </exception> /// <exception cref="PrivateKeyNotFoundException"> /// The private key could not be found to decrypt the stream. /// </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> /// <exception cref="Org.BouncyCastle.Bcpg.OpenPgp.PgpException"> /// An OpenPGP error occurred. /// </exception> public Stream GetDecryptedStream (Stream encryptedData, out DigitalSignatureCollection signatures) { if (encryptedData == null) throw new ArgumentNullException ("encryptedData"); using (var armored = new ArmoredInputStream (encryptedData)) { var factory = new PgpObjectFactory (armored); var obj = factory.NextPgpObject (); var list = obj as PgpEncryptedDataList; if (list == null) { // probably a PgpMarker... obj = factory.NextPgpObject (); list = obj as PgpEncryptedDataList; if (list == null) throw new PgpException ("Unexpected OpenPGP packet."); } PgpPublicKeyEncryptedData encrypted = null; PrivateKeyNotFoundException pkex = null; bool hasEncryptedPackets = false; PgpSecretKey secret = null; foreach (PgpEncryptedData data in list.GetEncryptedDataObjects ()) { if ((encrypted = data as PgpPublicKeyEncryptedData) == null) continue; hasEncryptedPackets = true; try { secret = GetSecretKey (encrypted.KeyId); break; } catch (PrivateKeyNotFoundException ex) { pkex = ex; } } if (!hasEncryptedPackets) throw new PgpException ("No encrypted packets found."); if (secret == null) throw pkex; factory = new PgpObjectFactory (encrypted.GetDataStream (GetPrivateKey (secret))); List<IDigitalSignature> onepassList = null; PgpSignatureList signatureList = null; PgpCompressedData compressed = null; var memory = new MemoryBlockStream (); obj = factory.NextPgpObject (); while (obj != null) { if (obj is PgpCompressedData) { if (compressed != null) throw new PgpException ("Recursive compression packets are not supported."); compressed = (PgpCompressedData) obj; factory = new PgpObjectFactory (compressed.GetDataStream ()); } else if (obj is PgpOnePassSignatureList) { if (memory.Length == 0) { var onepasses = (PgpOnePassSignatureList) obj; onepassList = new List<IDigitalSignature> (); for (int i = 0; i < onepasses.Count; i++) { var onepass = onepasses[i]; var pubkey = PublicKeyRingBundle.GetPublicKey (onepass.KeyId); if (pubkey == null) { // too messy, pretend we never found a one-pass signature list onepassList = null; break; } onepass.InitVerify (pubkey); var signature = new OpenPgpDigitalSignature (pubkey, onepass) { PublicKeyAlgorithm = GetPublicKeyAlgorithm (onepass.KeyAlgorithm), DigestAlgorithm = GetDigestAlgorithm (onepass.HashAlgorithm), }; onepassList.Add (signature); } } } else if (obj is PgpSignatureList) { signatureList = (PgpSignatureList) obj; } else if (obj is PgpLiteralData) { var literal = (PgpLiteralData) obj; using (var stream = literal.GetDataStream ()) { var buffer = new byte[4096]; int nread; while ((nread = stream.Read (buffer, 0, buffer.Length)) > 0) { if (onepassList != null) { // update our one-pass signatures... for (int index = 0; index < nread; index++) { byte c = buffer[index]; for (int i = 0; i < onepassList.Count; i++) { var pgp = (OpenPgpDigitalSignature) onepassList[i]; pgp.OnePassSignature.Update (c); } } } memory.Write (buffer, 0, nread); } } } obj = factory.NextPgpObject (); } memory.Position = 0; if (signatureList != null) { if (onepassList != null && signatureList.Count == onepassList.Count) { for (int i = 0; i < onepassList.Count; i++) { var pgp = (OpenPgpDigitalSignature) onepassList[i]; pgp.CreationDate = signatureList[i].CreationTime; pgp.Signature = signatureList[i]; } signatures = new DigitalSignatureCollection (onepassList); } else { signatures = GetDigitalSignatures (signatureList, memory); memory.Position = 0; } } else { signatures = null; } return memory; } }
public virtual void ImportSecretKeys (Stream rawData) { if (rawData == null) throw new ArgumentNullException (nameof (rawData)); using (var armored = new ArmoredInputStream (rawData)) Import (new PgpSecretKeyRingBundle (armored)); }
/// <summary> /// Imports public pgp keys from the specified stream. /// </summary> /// <remarks> /// Imports public pgp keys from the specified stream. /// </remarks> /// <param name="stream">The raw key data.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="stream"/> is <c>null</c>. /// </exception> /// <exception cref="System.IO.IOException"> /// <para>An error occurred while parsing the raw key-ring data</para> /// <para>-or-</para> /// <para>An error occured while saving the public key-ring bundle.</para> /// </exception> public override void Import (Stream stream) { if (stream == null) throw new ArgumentNullException (nameof (stream)); using (var armored = new ArmoredInputStream (stream)) Import (new PgpPublicKeyRingBundle (armored)); }
/// <summary> /// Decrypt and verify signature of data. /// </summary> /// <param name="data">Data to decrypt and verify</param> /// <returns>Returns decrypted data if signature verifies.</returns> public byte[] DecryptAndVerify(byte[] data, bool ignoreIntegrityCheck = false) { logger.Trace(string.Format("DecryptAndVerify({0}, {1})", data.Length, ignoreIntegrityCheck)); Context = new CryptoContext(Context); var isArmored = ASCIIEncoding.ASCII.GetString(data).IndexOf("-----BEGIN PGP MESSAGE-----") > -1; using (var dataIn = new MemoryStream(data)) { if (isArmored) { logger.Trace("isArmored"); using (var armoredIn = new ArmoredInputStream(dataIn)) { var factory = new PgpObjectFactory(armoredIn); while (true) { var obj = factory.NextPgpObject(); if (obj == null) return null; if (obj is PgpMarker) continue; var ret = DecryptHandlePgpObject(obj); if (Context.FailedIntegrityCheck && !ignoreIntegrityCheck) { logger.Error("DecryptAndVerify: Data not integrity protected."); throw new VerifyException("Data not integrity protected."); } logger.Trace("DecryptAndVerify: Returning " + (ret == null ? "null" : ret.Length.ToString()) + " bytes"); return ret; } } } else { var factory = new PgpObjectFactory(dataIn); while (true) { var obj = factory.NextPgpObject(); if (obj == null) return null; if (obj is PgpMarker) continue; var ret = DecryptHandlePgpObject(obj); if (Context.FailedIntegrityCheck && !ignoreIntegrityCheck) { logger.Error("DecryptAndVerify: Data not integrity protected."); throw new VerifyException("Data not integrity protected."); } logger.Trace("DecryptAndVerify: Returning " + (ret == null ? "null" : ret.Length.ToString()) + " bytes"); return ret; } } } }
/// <summary> /// Verifies the specified content using the detached signatureData. /// </summary> /// <remarks> /// Verifies the specified content using the detached signatureData. /// </remarks> /// <returns>A list of digital signatures.</returns> /// <param name="content">The content.</param> /// <param name="signatureData">The signature data.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="content"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="signatureData"/> is <c>null</c>.</para> /// </exception> public override DigitalSignatureCollection Verify (Stream content, Stream signatureData) { if (content == null) throw new ArgumentNullException ("content"); if (signatureData == null) throw new ArgumentNullException ("signatureData"); using (var armored = new ArmoredInputStream (signatureData)) { var factory = new PgpObjectFactory (armored); var data = factory.NextPgpObject (); PgpSignatureList signatureList; var compressed = data as PgpCompressedData; if (compressed != null) { factory = new PgpObjectFactory (compressed.GetDataStream ()); signatureList = (PgpSignatureList) factory.NextPgpObject (); } else { // FIXME: this should probably throw a FormatException? Also needs docs. if ((signatureList = data as PgpSignatureList) == null) throw new Exception ("Unexpected pgp object"); } return GetDigitalSignatures (signatureList, content); } }
/// <summary> /// Verify signature for cleartext (e.g. emails) /// </summary> /// <param name="data">Data to verify</param> /// <returns>Return true if signature validates, else false.</returns> public bool VerifyClear(byte[] data) { Context = new CryptoContext(Context); var crlf = new byte[] { (byte)'\r', (byte)'\n' }; var encoding = ASCIIEncoding.UTF8; using (var dataIn = new MemoryStream(data)) using (var armoredIn = new ArmoredInputStream(dataIn)) { if (!armoredIn.IsClearText()) throw new CryptoException("Error, message is not armored clear-text."); var headers = armoredIn.GetArmorHeaders(); if(headers != null) { foreach (var header in headers) { if (Regex.IsMatch(header, @"Charset: ([^\s]*)")) { var encodingType = Regex.Match(header, @"Charset: ([^\s]*)").Groups[1].Value; encoding = Encoding.GetEncoding(encodingType); } } } using (var clearOut = new MemoryStream()) { using (var clearIn = new MemoryStream()) { int ch = 0; while ((ch = armoredIn.ReadByte()) >= 0 && armoredIn.IsClearText()) clearIn.WriteByte((byte)ch); clearIn.Position = 0; using (var stringIn = new StringReader(encoding.GetString(clearIn.ToArray()))) { do { var line = stringIn.ReadLine(); if (line == null) break; line = line .TrimEnd(null) .TrimEnd(new char[] { ' ', '\t', '\n', '\r' }) .TrimEnd(null) +"\r\n"; var buff = encoding.GetBytes(line); clearOut.Write(buff, 0, buff.Length); } while (true); } } clearOut.Position = 0; var factory = new PgpObjectFactory(armoredIn); var signatureList = (PgpSignatureList)factory.NextPgpObject(); var signature = signatureList[0]; Context.IsEncrypted = false; Context.IsSigned = true; Context.SignedBy = GetPublicKey(signature.KeyId); if (Context.SignedBy == null) throw new PublicKeyNotFoundException("Public key not found for key id \"" + signature.KeyId + "\"."); signature.InitVerify(GetPublicKey(signature.KeyId)); signature.Update(clearOut.ToArray(), 0, (int)(clearOut.Length - 2)); Context.SignatureValidated = signature.Verify(); return Context.SignatureValidated; } } }
/// <summary> /// Verify signature /// </summary> /// <param name="data">Data to verify</param> /// <returns>Return true if signature validates, else false.</returns> public bool Verify(byte[] data) { Context = new CryptoContext(Context); using (var dataIn = new MemoryStream(data)) using (var armoredIn = new ArmoredInputStream(dataIn)) { if (!armoredIn.IsClearText()) { var factory = new PgpObjectFactory(armoredIn); DecryptHandlePgpObject(factory.NextPgpObject()); if (!Context.IsSigned) throw new CryptoException("Error, message is not signed."); return Context.SignatureValidated; } } return VerifyClear(data); }
/// <summary> /// Verify signature /// </summary> /// <param name="data">Data to verify</param> /// <returns>Return true if signature validates, else false.</returns> public bool Verify(byte[] data) { Context = new CryptoContext(Context); using (var dataIn = new MemoryStream(data)) using (var armoredIn = new ArmoredInputStream(dataIn)) { if (!armoredIn.IsClearText()) { var factory = new PgpObjectFactory(armoredIn); var pgpObject = factory.NextPgpObject(); if (pgpObject == null) return false; DecryptHandlePgpObject(pgpObject); if (Context.FailedIntegrityCheck) throw new VerifyException("Error, failed validation check."); if (!Context.IsSigned) throw new CryptoException("Error, message is not signed."); return Context.SignatureValidated; } } return VerifyClear(data); }
/// <summary> /// Decrypt a PGP message (i.e. "-----BEGIN PGP MESSAGE----- ... -----END PGP MESSAGE-----") /// using the supplied private key. /// </summary> /// <param name="armoredCipher">PGP message to decrypt</param> /// <param name="armoredPrivateKey">PGP private key</param> /// <param name="keyPassword">PGP private key password or null if none</param> /// <returns>decrypted plain text</returns> public static string PGPDecrypt(string armoredCipher, string armoredPrivateKey, string keyPassword) { // decode the private key PgpPrivateKey privateKey = null; using (MemoryStream ms = new MemoryStream(Encoding.ASCII.GetBytes(armoredPrivateKey))) { using (Stream dis = PgpUtilities.GetDecoderStream(ms)) { PgpSecretKeyRingBundle bundle = new PgpSecretKeyRingBundle(dis); foreach (PgpSecretKeyRing keyring in bundle.GetKeyRings()) { foreach (PgpSecretKey key in keyring.GetSecretKeys()) { privateKey = key.ExtractPrivateKey(keyPassword != null ? keyPassword.ToCharArray() : null); break; } } } } // decrypt armored block using our private key byte[] cipher = Encoding.ASCII.GetBytes(armoredCipher); using (MemoryStream decryptedStream = new MemoryStream()) { using (MemoryStream inputStream = new MemoryStream(cipher)) { using (ArmoredInputStream ais = new ArmoredInputStream(inputStream)) { PgpObject message = new PgpObjectFactory(ais).NextPgpObject(); if (message is PgpEncryptedDataList) { foreach (PgpPublicKeyEncryptedData pked in ((PgpEncryptedDataList)message).GetEncryptedDataObjects()) { message = new PgpObjectFactory(pked.GetDataStream(privateKey)).NextPgpObject(); } } if (message is PgpCompressedData) { message = new PgpObjectFactory(((PgpCompressedData)message).GetDataStream()).NextPgpObject(); } if (message is PgpLiteralData) { byte[] buffer = new byte[4096]; using (Stream stream = ((PgpLiteralData)message).GetInputStream()) { int read; while ((read = stream.Read(buffer, 0, 4096)) > 0) { decryptedStream.Write(buffer, 0, read); } } } return Encoding.UTF8.GetString(decryptedStream.ToArray()); } } } }
/// <summary> /// Decrypt an encrypted stream. /// </summary> /// <returns>The decrypted <see cref="MimeKit.MimeEntity"/>.</returns> /// <param name="encryptedData">The encrypted data.</param> /// <param name="signatures">A list of digital signatures if the data was both signed and encrypted.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="encryptedData"/> is <c>null</c>. /// </exception> /// <exception cref="PrivateKeyNotFoundException"> /// The private key could not be found to decrypt the stream. /// </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 MimeEntity Decrypt(Stream encryptedData, out DigitalSignatureCollection signatures) { if (encryptedData == null) throw new ArgumentNullException ("encryptedData"); // FIXME: document the exceptions that can be thrown by BouncyCastle using (var armored = new ArmoredInputStream (encryptedData)) { var factory = new PgpObjectFactory (armored); var obj = factory.NextPgpObject (); var list = obj as PgpEncryptedDataList; if (list == null) { // probably a PgpMarker... obj = factory.NextPgpObject (); list = obj as PgpEncryptedDataList; if (list == null) throw new Exception ("Unexpected pgp object"); } PgpPublicKeyEncryptedData encrypted = null; foreach (PgpEncryptedData data in list.GetEncryptedDataObjects ()) { if ((encrypted = data as PgpPublicKeyEncryptedData) != null) break; } if (encrypted == null) throw new Exception ("no encrypted data objects found?"); factory = new PgpObjectFactory (encrypted.GetDataStream (GetPrivateKey (encrypted.KeyId))); PgpOnePassSignatureList onepassList = null; PgpSignatureList signatureList = null; PgpCompressedData compressed = null; using (var memory = new MemoryStream ()) { obj = factory.NextPgpObject (); while (obj != null) { if (obj is PgpCompressedData) { if (compressed != null) throw new Exception ("recursive compression detected."); compressed = (PgpCompressedData) obj; factory = new PgpObjectFactory (compressed.GetDataStream ()); } else if (obj is PgpOnePassSignatureList) { onepassList = (PgpOnePassSignatureList) obj; } else if (obj is PgpSignatureList) { signatureList = (PgpSignatureList) obj; } else if (obj is PgpLiteralData) { var literal = (PgpLiteralData) obj; using (var stream = literal.GetDataStream ()) { stream.CopyTo (memory, 4096); } } obj = factory.NextPgpObject (); } memory.Position = 0; // FIXME: validate the OnePass signatures... and do what with them? // if (onepassList != null) { // for (int i = 0; i < onepassList.Count; i++) { // var onepass = onepassList[i]; // } // } if (signatureList != null) { signatures = GetDigitalSignatures (signatureList, memory); memory.Position = 0; } else { signatures = null; } return MimeEntity.Load (memory); } } }
public static bool VerifySig(byte[] asc, string sig, out string message) { try { foreach(PgpPublicKey pubkey in new PgpPublicKeyRing(GetStream(asc)).GetPublicKeys().OfType<PgpPublicKey>()) //java madness { //AGAIN MADNESS THIS MAKE PERFECT SENSE ! ArmoredInputStream sigInput = new ArmoredInputStream(new MemoryStream(Encoding.UTF8.GetBytes(sig))); // // read the input, making sure we ingore the last newline. // int ch; string newLine = null; MemoryStream bOut = new MemoryStream(); while((ch = sigInput.ReadByte()) >= 0 && sigInput.IsClearText()) { if(newLine != null) { foreach(var c in newLine) bOut.WriteByte((byte)c); newLine = null; } if(ch == '\r') { ch = sigInput.ReadByte(); if(ch == '\n') { newLine = "\r\n"; continue; } } if(ch == '\n') { newLine = "\n"; continue; } bOut.WriteByte((byte)ch); } var toSign = bOut.ToArray(); message = Encoding.UTF8.GetString(toSign); PgpObjectFactory pgpObjFactory = new PgpObjectFactory(sigInput); var list = (PgpSignatureList)pgpObjFactory.NextPgpObject(); PgpSignature pgpSig = list[0]; pgpSig.InitVerify(pubkey); pgpSig.Update(toSign); var result = pgpSig.Verify(); if(result) return result; Regex endofline = new Regex("[ ]+?(\r?)\n"); message = endofline.Replace(message, "$1\n"); toSign = Encoding.UTF8.GetBytes(message); pgpSig.InitVerify(pubkey); pgpSig.Update(toSign); result = pgpSig.Verify(); if(result) return result; } } catch //Don't do it at home kids { } message = null; return false; }