Пример #1
0
 public ArraySegment <byte> GetData(Stream stream, byte[] key, string[] compressionMethods)
 {
     lock (stream)
     {
         if (CompressionMethodIndex == 0U)
         {
             stream.Position = Offset + StructSize;
             if (Encrypted)
             {
                 var data = new byte[(Size & 15) == 0 ? Size : (Size / 16 + 1) * 16];
                 stream.Read(data, 0, data.Length);
                 return(new ArraySegment <byte>(AESDecryptor.DecryptAES(data, key), 0, (int)UncompressedSize));
             }
             else
             {
                 var data = new byte[UncompressedSize];
                 stream.Read(data, 0, data.Length);
                 return(new ArraySegment <byte>(data));
             }
         }
         else
         {
             var data = new byte[UncompressedSize];
             Decompress(stream, key, compressionMethods, data);
             return(new ArraySegment <byte>(data));
         }
     }
     throw new NotImplementedException("Decompression not yet implemented");
 }
Пример #2
0
        public bool TestAesKey(byte[] bytes, byte[] key)
        {
            BinaryReader IndexReader = new BinaryReader(new MemoryStream(AESDecryptor.DecryptAES(bytes, key)));
            int          stringLen   = IndexReader.ReadInt32();

            if (stringLen > 128 || stringLen < -128)
            {
                return(false);
            }
            if (stringLen == 0)
            {
                return(IndexReader.ReadUInt16() == 0);
            }
            if (stringLen < 0)
            {
                int nullTerminatedPos = 4 - (stringLen - 1) * 2;
                IndexReader.BaseStream.Seek(nullTerminatedPos, SeekOrigin.Begin);
                return(IndexReader.ReadInt16() == 0);
            }
            else
            {
                int nullTerminatedPos = 4 + stringLen - 1;
                IndexReader.BaseStream.Seek(nullTerminatedPos, SeekOrigin.Begin);
                return(IndexReader.ReadSByte() == 0);
            }
        }
Пример #3
0
 bool DecryptAndValidateIndex(ref byte[] IndexData, byte[] aesKey, FSHAHash ExpectedHash, out FSHAHash OutHash)
 {
     if (Info.bEncryptedIndex)
     {
         IndexData = AESDecryptor.DecryptAES(IndexData, aesKey);
     }
     OutHash = ExpectedHash; // too lazy to actually check against the hash
     // https://github.com/EpicGames/UnrealEngine/blob/79a64829237ae339118bb50b61d84e4599c14e8a/Engine/Source/Runtime/PakFile/Private/IPlatformFilePak.cpp#L5371
     return(true);
 }
Пример #4
0
        public void can_encrypt_and_decrypt_using_aes()
        {
            var encryptor = new AESEncryptor("SBcvpEo21MnyWamdiPxf1O+kBKk53s5GWRnrv3JoUVQ=", "vLWsT81pAOlk7hKd4cyz5A==");
            var encr      = encryptor.Encrypt("some string");

            var stringy   = Convert.ToBase64String(encr);
            var decryptor = new AESDecryptor("SBcvpEo21MnyWamdiPxf1O+kBKk53s5GWRnrv3JoUVQ=", "vLWsT81pAOlk7hKd4cyz5A==");
            var decr      = decryptor.Decrypt(encr);

            decr.ShouldBe("some string");
        }
Пример #5
0
        private void Decompress(Stream stream, byte[] key, string[] compressionMethods, byte[] outData)
        {
            if (compressionMethods == null || compressionMethods.Length == 0)
            {
                throw new ArgumentOutOfRangeException(nameof(compressionMethods), "CompressionMethods are null or empty");
            }

            string compressionMethod = compressionMethods[CompressionMethodIndex - 1]; // -1 because we dont have 'NAME_None' in the array
            int    bytesRead         = 0;

            for (int i = 0; i < CompressionBlocks.Length; i++)
            {
                stream.Position = Offset + CompressionBlocks[i].CompressedStart;
                int uncompressedSize = (int)Math.Min(CompressionBlockSize, outData.Length - bytesRead);

                byte[] blockBbuffer;
                if (Encrypted)
                {
                    blockBbuffer = new byte[BinaryHelper.Align(CompressionBlocks[i].Size, AESDecryptor.BLOCK_SIZE)];
                    stream.Read(blockBbuffer, 0, blockBbuffer.Length);
                    blockBbuffer = AESDecryptor.DecryptAES(blockBbuffer, key);
                }
                else
                {
                    blockBbuffer = new byte[CompressionBlocks[i].Size];
                    stream.Read(blockBbuffer, 0, blockBbuffer.Length);
                }

                using var blockMs = new MemoryStream(blockBbuffer, false);
                using Stream compressionStream = compressionMethod switch
                      {
                          "Zlib" => new ZlibStream(blockMs, CompressionMode.Decompress),
                          "Gzip" => new GZipStream(blockMs, CompressionMode.Decompress),
                          "Oodle" => new OodleStream(blockBbuffer, uncompressedSize),
                          _ => throw new NotImplementedException($"Decompression not yet implemented ({compressionMethod})")
                      };

                bytesRead += compressionStream.Read(outData, bytesRead, uncompressedSize);
            }
        }
Пример #6
0
        void ReadIndexInternal(byte[] key, PakFilter filter, out Exception exc)
        {
            if (Initialized)
            {
                exc = new InvalidOperationException("Index is already initialized");
                return;
            }

            if (Info.bEncryptedIndex && key == null)
            {
                exc = new ArgumentException("Index is encrypted but no key was provided", nameof(key));
                return;
            }

            Stream.Position = Info.IndexOffset;

            BinaryReader IndexReader;

            if (Info.bEncryptedIndex)
            {
                IndexReader = new BinaryReader(new MemoryStream(AESDecryptor.DecryptAES(Reader.ReadBytes((int)Info.IndexSize), key)));
                int stringLen = IndexReader.ReadInt32();
                if (stringLen > 512 || stringLen < -512)
                {
                    exc = new ArgumentException("The provided key is invalid", nameof(key));
                    return;
                }
                if (stringLen < 0)
                {
                    IndexReader.BaseStream.Position += (stringLen - 1) * 2;
                    if (IndexReader.ReadUInt16() != 0)
                    {
                        exc = new ArgumentException("The provided key is invalid", nameof(key));
                        return;
                    }
                }
                else
                {
                    IndexReader.BaseStream.Position += stringLen - 1;
                    if (IndexReader.ReadByte() != 0)
                    {
                        exc = new ArgumentException("The provided key is invalid", nameof(key));
                        return;
                    }
                }
                IndexReader.BaseStream.Position = 0;
            }
            else
            {
                IndexReader = Reader;
            }

            Dictionary <string, FPakEntry> tempFiles;

            if (Info.Version >= EPakVersion.PATH_HASH_INDEX)
            {
                ReadIndexUpdated(IndexReader, key, out tempFiles, filter);
            }
            else
            {
                // https://github.com/EpicGames/UnrealEngine/blob/bf95c2cbc703123e08ab54e3ceccdd47e48d224a/Engine/Source/Runtime/PakFile/Private/IPlatformFilePak.cpp#L4509
                MountPoint = IndexReader.ReadFString();
                if (MountPoint.StartsWith("../../.."))
                {
                    MountPoint = MountPoint.Substring(8);
                }
                else
                {
                    // Weird mount point location...
                    MountPoint = "/";
                }
                if (!CaseSensitive)
                {
                    MountPoint = MountPoint.ToLowerInvariant();
                }

                var NumEntries = IndexReader.ReadInt32();
                tempFiles = new Dictionary <string, FPakEntry>(NumEntries);
                for (int i = 0; i < NumEntries; i++)
                {
                    var entry = new FPakEntry(IndexReader, Info.Version, CaseSensitive, FileName);
                    // if there is no filter OR the filter passes
                    if (filter == null || filter.CheckFilter(MountPoint + entry.Name, CaseSensitive))
                    {
                        // Filename is without the MountPoint concatenated to save memory
                        tempFiles[entry.Name] = entry;
                    }
                }
            }

            Paks.Merge(tempFiles, out var files, MountPoint);
            Entries = files;

            DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PakFileReader]", "[ReadIndexInternal]", $"{FileName} contains {Entries.Count} files, mount point: \"{this.MountPoint}\", version: {(int)this.Info.Version}");

            if (Info.bEncryptedIndex)
            {
                // underlying stream is a MemoryStream of the decrypted index, might improve performance with a crypto stream of some sort
                IndexReader.Dispose();
            }

            Reader.Dispose();
            Initialized = true;
            exc         = null;
        }
Пример #7
0
        void ReadIndexInternal(byte[] key, PakFilter filter, out Exception exc)
        {
            if (Initialized)
            {
                exc = new InvalidOperationException("Index is already initialized");
                return;
            }

            if (Info.bEncryptedIndex && key == null)
            {
                exc = new ArgumentException("Index is encrypted but no key was provided", nameof(key));
                return;
            }

            Stream.Position = Info.IndexOffset;

            BinaryReader IndexReader;

            if (Info.bEncryptedIndex)
            {
                IndexReader = new BinaryReader(new MemoryStream(AESDecryptor.DecryptAES(Reader.ReadBytes((int)Info.IndexSize), key)));
                int stringLen = IndexReader.ReadInt32();
                if (stringLen > 512 || stringLen < -512)
                {
                    exc = new ArgumentException("The provided key is invalid", nameof(key));
                    return;
                }
                if (stringLen < 0)
                {
                    IndexReader.BaseStream.Position += (stringLen - 1) * 2;
                    if (IndexReader.ReadUInt16() != 0)
                    {
                        exc = new ArgumentException("The provided key is invalid", nameof(key));
                        return;
                    }
                }
                else
                {
                    IndexReader.BaseStream.Position += stringLen - 1;
                    if (IndexReader.ReadByte() != 0)
                    {
                        exc = new ArgumentException("The provided key is invalid", nameof(key));
                        return;
                    }
                }
                IndexReader.BaseStream.Position = 0;
            }
            else
            {
                IndexReader = Reader;
            }

            Dictionary <string, FPakEntry> tempFiles;

            if (Info.Version >= EPakVersion.PATH_HASH_INDEX)
            {
                ReadIndexUpdated(IndexReader, key, out tempFiles, filter);
            }
            else
            {
                // https://github.com/EpicGames/UnrealEngine/blob/bf95c2cbc703123e08ab54e3ceccdd47e48d224a/Engine/Source/Runtime/PakFile/Private/IPlatformFilePak.cpp#L4509
                MountPoint = IndexReader.ReadFString() ?? "";
                if (MountPoint.StartsWith("../../.."))
                {
                    MountPoint = MountPoint[8..];
Пример #8
0
 protected AesPacValidator(AESDecryptor decryptor, AESEncryptor encryptor, byte[] signature, ref byte[] pac)
     : base(signature, ref pac)
 {
     this.decryptor = decryptor;
     this.encryptor = encryptor;
 }
Пример #9
0
 public FilesController(IConfiguration iConfig)
 {
     configuration = iConfig;
     _AESDecryptor = new AESDecryptor(configuration.GetSection("AESKey").Value, configuration.GetSection("AESIV").Value);
 }