我一直在尝试使用BouncyCastle库来进行PGP加密/解密.我有一些代码需要修改才能使用流 – 没有文件.
我尝试删除PgpUtilities.WriteFileToLiteralData(),然后使其返回流,但它不起作用(输出流为空).
这里要更清楚的是该方法应该是什么:
public static Stream EncryptFile(MemoryStream inputStream,PgpPublicKey encKey,bool withIntegrityCheck)
private static void EncryptFile(Stream outputStream,string fileName,bool armor,bool withIntegrityCheck) { if (armor) outputStream = new ArmoredOutputStream(outputStream); try { MemoryStream bOut = new MemoryStream(); PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator( CompressionAlgorithmTag.Zip); PgpUtilities.WriteFileToLiteralData( comData.Open(bOut),PgpLiteralData.Binary,new FileInfo(fileName)); comData.Close(); PgpEncryptedDataGenerator cPk = new PgpEncryptedDataGenerator( SymmetricKeyAlgorithmTag.Cast5,withIntegrityCheck,new SecureRandom()); cPk.AddMethod(encKey); byte[] bytes = bOut.ToArray(); Stream cOut = cPk.Open(outputStream,bytes.Length); cOut.Write(bytes,bytes.Length); cOut.Close(); if (armor) outputStream.Close(); } catch (PgpException e) { Console.Error.WriteLine(e); Exception underlyingException = e.InnerException; if (underlyingException != null) { Console.Error.WriteLine(underlyingException.Message); Console.Error.WriteLine(underlyingException.StackTrace); } } } public void EncryptFile(string filePath,string publicKeyFile,string pathToSaveFile) { Stream keyIn,fos; keyIn = File.OpenRead(publicKeyFile); string[] fileSplit = filePath.Split('\\'); string fileName = fileSplit[fileSplit.Length - 1]; fos = File.Create(pathToSaveFile + fileName + ".asc"); EncryptFile(fos,filePath,ReadPublicKey(keyIn),true,true); keyIn.Close(); fos.Close(); }
解决方法
我搞定了.代码使用byte []进行解密和加密的输入和输出 – 没有文件.
这是全班:
class PGP { public PGP() { } /** * A simple routine that opens a key ring file and loads the first available key suitable for * encryption. * * @param in * @return * @m_out * @ */ public static PgpPublicKey ReadPublicKey(Stream inputStream) { inputStream = PgpUtilities.GetDecoderStream(inputStream); PgpPublicKeyRingBundle pgpPub = new PgpPublicKeyRingBundle(inputStream); // // we just loop through the collection till we find a key suitable for encryption,in the real // world you would probably want to be a bit smarter about this. // // // iterate through the key rings. // foreach (PgpPublicKeyRing kRing in pgpPub.GetKeyRings()) { foreach (PgpPublicKey k in kRing.GetPublicKeys()) { if (k.IsEncryptionKey) return k; } } throw new ArgumentException("Can't find encryption key in key ring."); } /** * Search a secret key ring collection for a secret key corresponding to * keyId if it exists. * * @param pgpSec a secret key ring collection. * @param keyId keyId we want. * @param pass passphrase to decrypt secret key with. * @return */ private static PgpPrivateKey FindSecretKey(PgpSecretKeyRingBundle pgpSec,long keyId,char[] pass) { PgpSecretKey pgpSecKey = pgpSec.GetSecretKey(keyId); if (pgpSecKey == null) return null; return pgpSecKey.ExtractPrivateKey(pass); } /** * Decrypt the byte array passed into inputData and return it as * another byte array. * * @param inputData - the data to decrypt * @param keyIn - a stream from your private keyring file * @param passCode - the password * @return - decrypted data as byte array */ public static byte[] Decrypt(byte[] inputData,Stream keyIn,string passCode) { byte[] error = Encoding.ASCII.GetBytes("ERROR"); Stream inputStream = new MemoryStream(inputData); inputStream = PgpUtilities.GetDecoderStream(inputStream); MemoryStream decoded = new MemoryStream(); try { PgpObjectFactory pgpF = new PgpObjectFactory(inputStream); PgpEncryptedDataList enc; PgpObject o = pgpF.NextPgpObject(); // // the first object might be a PGP marker packet. // if (o is PgpEncryptedDataList) enc = (PgpEncryptedDataList)o; else enc = (PgpEncryptedDataList)pgpF.NextPgpObject(); // // find the secret key // PgpPrivateKey sKey = null; PgpPublicKeyEncryptedData pbe = null; PgpSecretKeyRingBundle pgpSec = new PgpSecretKeyRingBundle( PgpUtilities.GetDecoderStream(keyIn)); foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects()) { sKey = FindSecretKey(pgpSec,pked.KeyId,passCode.tocharArray()); if (sKey != null) { pbe = pked; break; } } if (sKey == null) throw new ArgumentException("secret key for message not found."); Stream clear = pbe.GetDataStream(sKey); PgpObjectFactory plainFact = new PgpObjectFactory(clear); PgpObject message = plainFact.NextPgpObject(); if (message is PgpCompressedData) { PgpCompressedData cData = (PgpCompressedData)message; PgpObjectFactory pgpFact = new PgpObjectFactory(cData.GetDataStream()); message = pgpFact.NextPgpObject(); } if (message is PgpLiteralData) { PgpLiteralData ld = (PgpLiteralData)message; Stream unc = ld.GetInputStream(); Streams.PipeAll(unc,decoded); } else if (message is PgpOnePassSignatureList) throw new PgpException("encrypted message contains a signed message - not literal data."); else throw new PgpException("message is not a simple encrypted file - type unknown."); if (pbe.IsIntegrityProtected()) { if (!pbe.Verify()) MessageBox.Show(null,"Message Failed integrity check.","PGP Error",MessageBoxButtons.OK,MessageBoxIcon.Error); else MessageBox.Show(null,"Message integrity check passed.",MessageBoxIcon.Information); } else { MessageBox.Show(null,"No message integrity check.",MessageBoxIcon.Information); } return decoded.ToArray(); } catch (Exception e) { if (e.Message.StartsWith("Checksum mismatch")) MessageBox.Show(null,"Likely invalid passcode. Possible data corruption.","Invalid Passcode",MessageBoxIcon.Error); else if (e.Message.StartsWith("Object reference not")) MessageBox.Show(null,"PGP data does not exist.",MessageBoxIcon.Error); else if (e.Message.StartsWith("Premature end of stream")) MessageBox.Show(null,"Partial PGP data found.",MessageBoxIcon.Error); else MessageBox.Show(null,e.Message,MessageBoxIcon.Error); Exception underlyingException = e.InnerException; if (underlyingException != null) MessageBox.Show(null,underlyingException.Message,MessageBoxIcon.Error); return error; } } /** * Encrypt the data. * * @param inputData - byte array to encrypt * @param passPhrase - the password returned by "ReadPublicKey" * @param withIntegrityCheck - check the data for errors * @param armor - protect the data streams * @return - encrypted byte array */ public static byte[] Encrypt(byte[] inputData,PgpPublicKey passPhrase,bool withIntegrityCheck,bool armor) { byte[] processedData = Compress(inputData,PgpLiteralData.Console,CompressionAlgorithmTag.Uncompressed); MemoryStream bOut = new MemoryStream(); Stream output = bOut; if (armor) output = new ArmoredOutputStream(output); PgpEncryptedDataGenerator encGen = new PgpEncryptedDataGenerator(SymmetricKeyAlgorithmTag.Cast5,new SecureRandom()); encGen.AddMethod(passPhrase); Stream encOut = encGen.Open(output,processedData.Length); encOut.Write(processedData,processedData.Length); encOut.Close(); if (armor) output.Close(); return bOut.ToArray(); } private static byte[] Compress(byte[] clearData,CompressionAlgorithmTag algorithm) { MemoryStream bOut = new MemoryStream(); PgpCompressedDataGenerator comData = new PgpCompressedDataGenerator(algorithm); Stream cos = comData.Open(bOut); // open it with the final destination PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator(); // we want to Generate compressed data. This might be a user option later,// in which case we would pass in bOut. Stream pOut = lData.Open( cos,// the compressed output stream PgpLiteralData.Binary,fileName,// "filename" to store clearData.Length,// length of clear data DateTime.UtcNow // current time ); pOut.Write(clearData,clearData.Length); pOut.Close(); comData.Close(); return bOut.ToArray(); } }