Beispiel #1
0
        private static List <uint> _MakeMiniSectorOffsetChain(
            _CompoundFileInfo cfi, uint startMiniSectorId)
        {
            var chain = new List <uint>();

            if (!_IsRegulerSectorId(startMiniSectorId))
            {
                return(chain);
            }

            var miniFatSoc = _MakeSectorOffsetChain(
                cfi, cfi.firstMiniFatSectorId
                );
            var miniStreamSoc = _MakeSectorOffsetChain(
                cfi, cfi.firstMiniStreamSectorId
                );

            var next = startMiniSectorId;

            do
            {
                var n      = next / cfi.miniStreamCountPerSector;
                var m      = next % cfi.miniStreamCountPerSector;
                var offset = miniStreamSoc[(int)n] + (m * cfi.miniStreamSize);
                chain.Add(offset);
                var a             = next / cfi.fatEntryCountPerSector;
                var b             = next % cfi.fatEntryCountPerSector;
                var miniFatOffset = miniFatSoc[(int)a] + (b * 4);
                next = _ToU32(_ReadBytes(cfi.stream, miniFatOffset, 4));
            } while (_IsRegulerSectorId(next));
            return(chain);
        }
Beispiel #2
0
        private static byte[] _ReadUserDefinedData(
            _CompoundFileInfo cfi, uint entryOffset)
        {
            var         eo            = entryOffset;
            var         startSectorId = _ToU32(_ReadBytes(cfi.stream, eo + 0x0074, 4));
            var         streamSize    = _ToI64(_ReadBytes(cfi.stream, eo + 0x0078, 8));
            uint        sectorSize;
            List <uint> chain;

            if (streamSize >= cfi.miniStreamSizeCutoff)
            {
                sectorSize = cfi.sectorSize;
                chain      = _MakeSectorOffsetChain(cfi, startSectorId);
            }
            else
            {
                sectorSize = cfi.miniStreamSize;
                chain      = _MakeMiniSectorOffsetChain(cfi, startSectorId);
            }
            var bytes = new byte[streamSize];

            for (var n = 0; n < chain.Count; ++n)
            {
                var srcOffset = chain[n];
                var dstOffset = n * sectorSize;
                var count     = System.Math.Min(sectorSize, streamSize - dstOffset);
                cfi.stream.Position = srcOffset;
                cfi.stream.Read(bytes, (int)dstOffset, (int)count);
            }
            return(bytes);
        }
Beispiel #3
0
        private static uint _GetFirstMiniStreamSectorId(_CompoundFileInfo cfi)
        {
            var rootEntryOffset
                = (cfi.firstDirectorySectorId + 1) * cfi.sectorSize;

            return(_ToU32(_ReadBytes(cfi.stream, rootEntryOffset + 0x0074, 4)));
        }
Beispiel #4
0
        private static byte[] _ReadEncryptedPackage(_CompoundFileInfo cfi)
        {
            var offset = _FindDirectoryEntryOffset(cfi, "EncryptedPackage");

            if (offset == 0)
            {
                return(null);
            }
            return(_ReadUserDefinedData(cfi, offset));
        }
Beispiel #5
0
        private static _EncryptionInfo _ReadEncryptionInfo(
            _CompoundFileInfo cfi)
        {
            var offset = _FindDirectoryEntryOffset(cfi, "EncryptionInfo");

            if (offset == 0)
            {
                return(null);
            }
            var bytes = _ReadUserDefinedData(cfi, offset);

            return(new _EncryptionInfo(bytes));
        }
Beispiel #6
0
        internal static bool IsEncryptedFile(Stream stream)
        {
            if (!_IsCompoundFileFormat(stream))
            {
                return(false);
            }
            var cfi = new _CompoundFileInfo(stream);
            var ei  = _ReadEncryptionInfo(cfi);

            if (ei == null)
            {
                return(false);
            }
            return(true);
        }
Beispiel #7
0
        private static List <uint> _MakeDifatOffsetChain(_CompoundFileInfo cfi)
        {
            var chain = new List <uint>();

            chain.Add(0x004C);
            var next = _ToU32(_ReadBytes(cfi.stream, 0x0044, 4));

            while (_IsRegulerSectorId(next))
            {
                var offset = (next + 1) * cfi.sectorSize;
                chain.Add(offset);
                next = _ToU32(_ReadBytes(
                                  cfi.stream, offset + (cfi.sectorSize - 4), 4
                                  ));
            }
            return(chain);
        }
Beispiel #8
0
        private static List <uint> _MakeSectorOffsetChain(
            _CompoundFileInfo cfi, uint startSectorId)
        {
            var chain = new List <uint>();

            if (!_IsRegulerSectorId(startSectorId))
            {
                return(chain);
            }
            var next = startSectorId;

            do
            {
                var offset = (next + 1) * cfi.sectorSize;
                chain.Add(offset);
                var fatOffset = _FindFatSectorOffset(cfi, next);
                var n         = 4 * (next % cfi.fatEntryCountPerSector);
                next = _ToU32(_ReadBytes(cfi.stream, fatOffset + n, 4));
            } while (_IsRegulerSectorId(next));
            return(chain);
        }
Beispiel #9
0
        private static uint _FindDirectoryEntryOffset(
            _CompoundFileInfo cfi, string entryName)
        {
            var startSectorId = cfi.firstDirectorySectorId;
            var chain         = _MakeSectorOffsetChain(cfi, startSectorId);
            var mCount        = cfi.directoryEntryCountPerSector;
            var deSize        = _CompoundFileInfo.DirectoryEntrySize;

            for (uint n = 0; n < chain.Count; ++n)
            {
                for (uint m = 0; m < mCount; ++m)
                {
                    var offset = chain[(int)n] + (m * deSize);
                    var bytes  = _ReadBytes(cfi.stream, offset, 64);
                    var name   = _ReadNullTerminatedUnicodeString(bytes);
                    if (name == entryName)
                    {
                        return(offset);
                    }
                }
            }
            return(0);
        }
Beispiel #10
0
        private static uint _FindFatSectorOffset(
            _CompoundFileInfo cfi, uint sectorId)
        {
            var  decih           = _CompoundFileInfo.DifatEntryCountInHeader;
            var  decps           = cfi.difatEntryCountPerSector;
            var  difatEntryIndex = sectorId / cfi.fatEntryCountPerSector;
            uint n = 0;
            uint m = 0;

            if (difatEntryIndex < decih)
            {
                m = 4 * difatEntryIndex;
            }
            else
            {
                n = 1 + ((difatEntryIndex - decih) / decps);
                m = 4 * ((difatEntryIndex - decih) % decps);
            }
            var pos         = cfi.difatOffsetChain[(int)n] + m;
            var fatSectorId = _ToU32(_ReadBytes(cfi.stream, pos, 4));

            return((fatSectorId + 1) * cfi.sectorSize);
        }
Beispiel #11
0
        internal static IEnumerator Decrypt(
            Stream stream, string password, Result result)
        {
            var startTicks = DateTime.Now.Ticks;

            System.Func <bool> keepControl = () => {
                var ticks = DateTime.Now.Ticks;
                if (startTicks < 0)
                {
                    startTicks = ticks;
                }
                if (ticks - startTicks < MaxControlTicks)
                {
                    return(true);
                }
                startTicks = -1;
                return(false);
            };

            if (!_IsCompoundFileFormat(stream))
            {
                result.error = "Invalid file format.";
                yield break;
            }
            var cfi = new _CompoundFileInfo(stream);
            var ei  = _ReadEncryptionInfo(cfi);

            if (ei == null)
            {
                result.error = "EncryptionInfo not found.";
                yield break;
            }
            result.error = _VerifyEncryptionInfo(ei);
            if (!string.IsNullOrEmpty(result.error))
            {
                yield break;
            }
            yield return(null);

            var hAlg = _CreateHashAlgorithmForKey(ei);

            byte[] hFinalPrev = null;
            foreach (var h in _GenerateHFinalPrev(hAlg, ei, password))
            {
                hFinalPrev = h;
                if (!keepControl())
                {
                    yield return(null);
                }
            }
            yield return(null);

            var isSuccess = _VerifyEncryptionKey(hAlg, ei, hFinalPrev);

            if (!isSuccess)
            {
                result.error = "Password incorrect.";
                yield break;
            }
            var ep = _ReadEncryptedPackage(cfi);

            yield return(null);

            var ek    = _MakeDataEncryptionKey(hAlg, ei, hFinalPrev);
            var bytes = new byte[ep.Length - 8];
            var dec   = _DecryptPackage(ei, ek, ep, bytes, 0).GetEnumerator();

            while (dec.MoveNext())
            {
                if (!keepControl())
                {
                    yield return(null);
                }
            }
            var streamSize = _ToI64(ep, 0);

            System.Array.Resize(ref bytes, (int)streamSize);
            result.bytes = bytes;
        }