public void DoHash(PGPReader Reader, HashAlgorithm[] HashAlgorithms) { long TotalBytes = Reader.BytesRemaining; long RemainingBytes = TotalBytes; byte[] Buffer = new byte[4096]; long CurrentTick = DateTime.Now.Ticks; while (RemainingBytes > 0) { int BytesToRead = (int)RemainingBytes; if (BytesToRead > Buffer.Length) { BytesToRead = Buffer.Length; } int BytesRead = Reader.Read(Buffer, 0, BytesToRead); foreach (var HashAlgo in HashAlgorithms) { HashAlgo.TransformBlock(Buffer, 0, BytesRead, Buffer, 0); } if (CurrentTick + 10000000 < DateTime.Now.Ticks) { CurrentTick = DateTime.Now.Ticks; ProgressUpdate?.Invoke("Computing Hash...", (int)(100 * (TotalBytes - RemainingBytes) / TotalBytes)); } RemainingBytes -= BytesRead; } }
public TreeBuilder(PGPReader fs) { _fs = fs; _StartBlock = new ByteBlock(); CurrentBlock = _StartBlock; _Level = new Stack <ByteBlock>(); AddChildLevel = false; }
public void Extract(string SourceFileName) { SaveFileDialog SaveDialog = new SaveFileDialog { OverwritePrompt = true, FileName = ExtractFileName }; if (SaveDialog.ShowDialog() != DialogResult.OK) { return; } string DestFileName = SaveDialog.FileName; using (PGPReader fsSource = new PGPReader(SourceFileName)) { fsSource.DoIndexUpdate += OnIndexUpdate; fsSource.GetPacket(PacketIndex); fsSource.DoIndexUpdate -= OnIndexUpdate; fsSource.ReadByte(); int len = fsSource.ReadByte(); byte[] buf = new byte[256]; fsSource.Read(buf, 0, len); fsSource.Read(buf, 0, 4); // unix time using (FileStream fsDest = new FileStream(DestFileName, FileMode.Create, FileAccess.Write)) { byte[] DataBytes = new byte[4096]; var BytesRemaining = fsSource.BytesRemaining; var TotalBytes = BytesRemaining; long CurrentTick = DateTime.Now.Ticks; while (BytesRemaining > 0) { int ReadBytes = (int)BytesRemaining; if (BytesRemaining > DataBytes.Length) { ReadBytes = DataBytes.Length; } fsSource.Read(DataBytes, 0, ReadBytes); fsDest.Write(DataBytes, 0, ReadBytes); BytesRemaining -= ReadBytes; if (CurrentTick + 10000000 < DateTime.Now.Ticks) { CurrentTick = DateTime.Now.Ticks; OnStatusUpdate("Saving...", (int)(100 * (TotalBytes - BytesRemaining) / TotalBytes)); } } } } }
public static ByteBlock Process(string PGPFile) { var Root = new ByteBlock(); PGPPacket pgp; PublicKeyPacket PrimaryKeyPacket = null; PublicKeyPacket SubKeyPacket = null; UserIDPacket UIDPacket = null; Stack <OnePassSignaturePacket> OPSigPacketStack = new Stack <OnePassSignaturePacket>(); HashAlgorithm[] HashAlgorithms = null; using (var PacketReader = new PGPReader(PGPFile)) { PacketReader.DoIndexUpdate += IndexUpdate; while ((pgp = PacketReader.ReadNextPacket()) != null) { TreeBuilder Tree = new TreeBuilder(PacketReader); pgp.Parse(Tree); if (pgp is LiteralDataPacket litPgp) { if (HashAlgorithms == null) { HashAlgorithms = GetHashAlgorithms(OPSigPacketStack); } litPgp.ProgressUpdate += StatusUpdate; litPgp.DoHash(PacketReader, HashAlgorithms); } else { if (pgp is OnePassSignaturePacket OPSig) { OPSigPacketStack.Push(OPSig); } else if (pgp.PacketTag == 6 || pgp.PacketTag == 5) { PrimaryKeyPacket = (PublicKeyPacket)pgp; } else if (pgp is UserIDPacket) { UIDPacket = (UserIDPacket)pgp; } else if (pgp.PacketTag == 14 || pgp.PacketTag == 7) { SubKeyPacket = (PublicKeyPacket)pgp; } else if (pgp is SignaturePacket Sig) { if ((Sig.SignatureType == 0x18 || Sig.SignatureType == 0x19) && PrimaryKeyPacket != null && SubKeyPacket != null && SubKeyPacket.PacketDataPublicKey != null) { Sig.GenerateSubKeyBindingHash(PrimaryKeyPacket, SubKeyPacket); } if (Sig.SignatureType >= 0x10 && Sig.SignatureType <= 0x13 && PrimaryKeyPacket != null && UIDPacket != null) { Sig.GenerateCertifyHash(PrimaryKeyPacket, UIDPacket); } // Signature of a Binary Document if (Sig.SignatureType == 0x00) { // Are we generating hash for One Pass Signature Packet if (OPSigPacketStack.Count() > 0) { var OnePassSignaturePacket = OPSigPacketStack.Pop(); if (OnePassSignaturePacket.HashAlgorithm == Sig.HashAlgorithm) { Sig.GenerateBinaryHash(HashAlgorithmTypes.GetHashAlgoManaged(Sig.HashAlgorithm, HashAlgorithms)); } } } } } PacketBlock pb = new PacketBlock(pgp); pb.AddChildBlock(Tree.StartBlock); Root.AddChildBlock(pb); _PacketNodes.Add(pb); } } return(Root.ChildBlock); }
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); } }
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); }