private void ExtractData() { string DecryptedFileName = null; string Password = null; if (MessageBox.Show("Decrypt Encrypted Data", "Please Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != System.Windows.Forms.DialogResult.Yes) { return; } PGPPacket Packet = this; List <byte[]> SessionKeys = new List <byte[]>(); List <PKEncSessionKeyPacket> PKSessions = new List <PKEncSessionKeyPacket>(); List <SymEncSessionKeyPacket> SymSessions = new List <SymEncSessionKeyPacket>(); //byte SymmetricAlgorithm = 0; string ErrorMsg = ""; while ((Packet = OpenPGP.GetPreviousPacket(Packet)) != null) { if (Packet is PKEncSessionKeyPacket PKSessionPacket) { PKSessions.Add(PKSessionPacket); } else if (Packet is SymEncSessionKeyPacket SymKeySessionPacket) { SymSessions.Add(SymKeySessionPacket); } } // First try to see if we have any PK Secret keys foreach (var PKSession in PKSessions) { // Get all matching secret keys var SecKeyList = OpenPGP.FindPrimaryKey(PKSession.KeyId, true).Where(p => p.PacketTag == 5 || p.PacketTag == 7).ToList(); foreach (SecretKeyPacket SecKey in SecKeyList) { var PKAlgorithm = SecKey.PublicKeyAlgorithm; if (!PKAlgorithm.PrivateKeyDecrypted) { ErrorMsg = "Secret Key is encrypted, click on the encrypted node to decrypt it first"; continue; } var ClearBytes = PKAlgorithm.Decrypt(PKSession.PublicKeyTransformedData); long CheckSum = 0; for (int i = 1; i < ClearBytes.Length - 2; i++) { CheckSum += ClearBytes[i]; } CheckSum %= 65536; if ((CheckSum >> 8) != ClearBytes[ClearBytes.Length - 2] || (CheckSum & 0xFF) != ClearBytes[ClearBytes.Length - 1]) { continue; } //SymmetricAlgorithm = ClearBytes[0]; SessionKeys.Add(ClearBytes.SubArray(0, ClearBytes.Length - 2)); } } if (SessionKeys.Count() == 0) { if (ErrorMsg != "") { throw new Exception(ErrorMsg); } } // If no Public Key Encrypted keys found, then try any Sym keys if (SessionKeys.Count() == 0) { foreach (var SymSession in SymSessions) { if (Password == null) { // Ask for password only once PinEntry frm = new PinEntry(); if (frm.ShowDialog() == DialogResult.Cancel) { break; } Password = frm.Password; } byte[] DecryptionKey = SymSession.S2K.GetKey(Password); if (SymSession.EncryptedSessionKey == null) { byte[] SessionKey = new byte[DecryptionKey.Length + 1]; SessionKey[0] = SymSession.S2K.SymAlgo; Array.Copy(DecryptionKey, 0, SessionKey, 1, DecryptionKey.Length); SessionKeys.Add(SessionKey); } else { var KeyDecryptor = SymmProcess.GetDecryptor(SymSession.S2K.SymAlgo, DecryptionKey); var BlockSizeBytes = KeyDecryptor.InputBlockSize; int EncryptedLength = SymSession.EncryptedSessionKey.Length; int BlockFillLength = BlockSizeBytes * ((EncryptedLength / BlockSizeBytes) + 1); byte[] CryptBytes = new byte[BlockFillLength]; Array.Copy(SymSession.EncryptedSessionKey, 0, CryptBytes, 0, EncryptedLength); byte[] ClearBytes; using (MemoryStream msDecrypt = new MemoryStream()) { using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, KeyDecryptor, CryptoStreamMode.Write)) csDecrypt.Write(CryptBytes, 0, CryptBytes.Length); ClearBytes = msDecrypt.ToArray().SubArray(0, EncryptedLength); } SessionKeys.Add(ClearBytes); } } } //if (Packet == null || (Packet.PacketTag != 1 && Packet.PacketTag != 3)) // throw new Exception("No Public-Key/Symmetric-Key encrypted session key packet"); //if (SecKeyList.Count() == 0) // throw new Exception("Secret Key not available, please add the secret key to decrypt data"); if (SessionKeys.Count() == 0) { throw new Exception("Unable to Decrypt"); } // Session Key found DecryptedFileName = TempFiles.GetNewTempFile(); bool Success = false; using (PGPReader fsSource = new PGPReader(FileName)) { fsSource.DoIndexUpdate += OnIndexUpdate; fsSource.GetPacket(PacketIndex); fsSource.DoIndexUpdate -= OnIndexUpdate; byte version = fsSource.ReadByte(); long FileSize = fsSource.BytesRemaining; fsSource.BookMark(); foreach (var SessionKey in SessionKeys) { try { var decryptor = SymmProcess.GetDecryptor(SessionKey[0], SessionKey.SubArray(1, SessionKey.Length - 1)); int BlockSize = decryptor.InputBlockSize; fsSource.GoToBookMark(); using (FileStream fsDecrypt = new FileStream(DecryptedFileName, FileMode.Create, FileAccess.Write)) { SHA1 Sha1 = new SHA1Managed(); byte[] CryptBytes = new byte[BlockSize * 256]; // IMPORTANT: Make sure it is a multiple of block size byte[] PlainBytes = new byte[BlockSize * 256]; var BytesRemaining = FileSize - 22; // 2 byte MDC tag (0xD3, 0x14) and length, 20 byte SHA-1 hash int BlockAlign = (int)(BytesRemaining % BlockSize); BytesRemaining -= BlockAlign; // Transformation has to be done in blocks, so make sure it fits in blocks bool FirstTime = true; while (BytesRemaining > 0) { int ReadBytes = (int)BytesRemaining; if (BytesRemaining > CryptBytes.Length) { ReadBytes = CryptBytes.Length; } fsSource.Read(CryptBytes, 0, ReadBytes); decryptor.TransformBlock(CryptBytes, 0, ReadBytes, PlainBytes, 0); if (FirstTime) { // Validate the repeating bytes if (PlainBytes[BlockSize - 2] != PlainBytes[BlockSize] || PlainBytes[BlockSize - 1] != PlainBytes[BlockSize + 1]) { throw new Exception("Pre validation failed, session key may be invalid"); } fsDecrypt.Write(PlainBytes, BlockSize + 2, ReadBytes - BlockSize - 2); FirstTime = false; } else { fsDecrypt.Write(PlainBytes, 0, ReadBytes); } Sha1.TransformBlock(PlainBytes, 0, ReadBytes, PlainBytes, 0); StatusUpdate("Decrypting...", (int)(100 * (FileSize - BytesRemaining) / FileSize)); BytesRemaining -= ReadBytes; } int FinalBytes = BlockAlign + 22; fsSource.Read(CryptBytes, 0, FinalBytes); decryptor.TransformBlock(CryptBytes, 0, FinalBytes + Program.GetBlockAlignRemainder(FinalBytes, BlockSize), PlainBytes, 0); fsDecrypt.Write(PlainBytes, 0, BlockAlign); // Validate the MDC Packet if (PlainBytes[BlockAlign] != 0xD3 || PlainBytes[BlockAlign + 1] != 0x14) { throw new Exception("Modification Detection validation failed, data is corrupt"); } Sha1.TransformFinalBlock(PlainBytes, 0, BlockAlign + 2); // 0xD3, 0x14 bytes if (!PlainBytes.SubArray(BlockAlign + 2, 20).SequenceEqual(Sha1.Hash)) { throw new Exception("MDC hash verification failed, Data may have been modified or is corrupt"); } Success = true; break; } } catch (Exception ex) { } } } if (Success) { ByteBlock StartBlock = OpenPGP.Process(DecryptedFileName); OpenPGP.Validate(); ThisBlock.AddChildBlock(StartBlock); } }
private static string GetBinaryFile(string FileName) { using (FileStream sr = new FileStream(FileName, FileMode.Open, FileAccess.Read)) { int FirstByte = sr.ReadByte(); if ((FirstByte & 0x80) != 0) { return(FileName); } } // Assuming ASCII Armored Text File using (StreamReader reader = File.OpenText(FileName)) { string line = reader.ReadLine(); if (!line.StartsWith("-----")) { throw new InvalidDataException("Not a valid Open PGP file"); } FileInfo fi = new FileInfo(FileName); if (fi.Length > Program.MAX_ARMORED_LENGTH) { throw new InvalidDataException("ASCII-Armored file too big, please convert to binary and try again"); } while (!reader.EndOfStream && !string.IsNullOrWhiteSpace(reader.ReadLine())) { ; } StringBuilder sb = new StringBuilder(); long CheckSum = 0; while (!reader.EndOfStream) { line = reader.ReadLine(); if (line.StartsWith("=")) { byte[] CheckSumBytes = Convert.FromBase64String(line.Substring(1)); CheckSum = Program.GetBigEndian(CheckSumBytes, 0, CheckSumBytes.Length); break; } else if (string.IsNullOrWhiteSpace(line)) { break; } sb.Append(line); } byte[] DataBytes = Convert.FromBase64String(sb.ToString()); long CRC = Program.GetCRC24(DataBytes); if (CRC != CheckSum) { throw new InvalidDataException("ASCII-Armored checksum failed, file may be corrupt"); } string TempFileName = TempFiles.GetNewTempFile(); File.WriteAllBytes(TempFileName, DataBytes); return(TempFileName); } }
public void Extract(string SourceFileName) { string DestFileName; using (PGPReader fsSource = new PGPReader(SourceFileName)) { fsSource.DoIndexUpdate += OnIndexUpdate; fsSource.GetPacket(PacketIndex); fsSource.DoIndexUpdate -= OnIndexUpdate; byte CompressionAlgorithm = fsSource.ReadByte(); if (CompressionAlgorithm != 0 && CompressionAlgorithm != 1 && CompressionAlgorithm != 2 && CompressionAlgorithm != 3) { throw new Exception("Compression algorithm not supported"); } int HashBytes = 0; if (CompressionAlgorithm == 2) { // RFC 1950 HashBytes = 4; byte CMF = fsSource.ReadByte(); byte FLG = fsSource.ReadByte(); if ((FLG & 32) != 0) { byte[] DICT = new byte[4]; fsSource.Read(DICT, 0, 4); } } Adler32 adler32 = new Adler32(); byte[] Hash = null; PGPStream PGPStream = new PGPStream(fsSource, HashBytes); DestFileName = TempFiles.GetNewTempFile(); using (FileStream fsDest = new FileStream(DestFileName, FileMode.Create, FileAccess.Write)) { if (CompressionAlgorithm == 0) { CopyStream(PGPStream, PGPStream, fsDest); } else if (CompressionAlgorithm == 3) { using (var BZip2Stream = new BZip2InputStream(PGPStream)) { CopyStream(PGPStream, BZip2Stream, fsDest); } } else { using (DeflateStream decompressionStream = new DeflateStream(PGPStream, CompressionMode.Decompress)) { CopyStream(PGPStream, decompressionStream, fsDest, adler32); Hash = adler32.Hash; } } } if (HashBytes > 0) { byte[] HashCompare = new byte[4]; fsSource.Read(HashCompare, 0, 4); if (!HashCompare.Reverse().SequenceEqual(Hash)) { throw new Exception("Decompressed Hash Mismatch"); } } } ByteBlock StartBlock = OpenPGP.Process(DestFileName); OpenPGP.Validate(); ThisBlock.AddChildBlock(StartBlock); }