private static string SwapNibbles(IntPtrEx src, int len) { using (IntPtrEx pBuffer = new IntPtrEx(new byte[len])) { return(SwapNibbles(pBuffer, src, len).Read <string>()); } }
private static IntPtrEx SwapNibbles(IntPtrEx dst, string src, int len) { using (IntPtrEx pSrc = new IntPtrEx(src)) { return(SwapNibbles(dst, pSrc, len)); } }
private static IntPtr DESProcessBlock(byte rounds, IntPtrEx dst, IntPtrEx src, byte[] ks, CryptoType dir) { byte[] tmp = new byte[4]; MemCpy(src, dst, 8); DESPermutation(dst, DES_IP); if (rounds > 0) { for (int i = 0; i < rounds; i++) { //DES_RawProcessBlock(dst, ks + (dir == CryptoType.Decrypt ? 0xF - i : i) * 8); DESRawProcessBlock(dst, ks); MemCpy(dst, tmp, 4); MemCpy(dst + 4, dst, 4); MemCpy(tmp, dst + 4, 4); } } MemCpy(dst, tmp, 4); MemCpy(dst + 4, dst, 4); MemCpy(tmp, dst + 4, 4); DESPermutation(dst, DES_IP_INV); return(dst); }
private static IntPtr GRFProcess(IntPtrEx dst, IntPtrEx src, int len, byte flags, int digitsGen, byte[] ks, CryptoType dir) { int digits, i; if ((flags & GRFFILE_FLAG_MIXCRYPT) == GRFFILE_FLAG_MIXCRYPT) { for (i = digitsGen, digits = 0; i > 0; i /= 0xA, digits++) { ; } if (digits < 1) { digits = 1; } GRFMixedProcess(dst, src, len, (byte)digits, ks, dir); } else if ((flags & GRFFILE_FLAG_0x14_DES) == GRFFILE_FLAG_0x14_DES) { i = len / 8; if (i > 0x14) { i = 0x14; MemCpy(src + 0x14 * 8, dst + 0x14 * 8, len - 0x14 * 8); } DESProcess(dst, src, i * 8, ks, dir); } else { MemCpy(src, dst, len); } return(dst); }
private void ReadVer2Info() { if (m_IntVersion != 0x200) { throw new GrfException(); } byte[] buf = new byte[8], zbuf; int len, len2; FileStream.Read(buf, 0, 8); len = EndianConverter.LittleEndian(BitConverter.ToInt32(buf, 0)); if (0 == (len2 = EndianConverter.LittleEndian(BitConverter.ToInt32(buf, 4)))) { return; } zbuf = new byte[len]; FileStream.Read(zbuf, 0, len); using (IntPtrEx pBuffer = new IntPtrEx(ZlibStream.UncompressBuffer(zbuf))) { string name = null; GrfItem item; try { for (int i = 0, offset = 0; i < m_Items.Capacity; i++, offset += 0x11) { name = pBuffer.Read <string>(offset); len = name.Length + 1; if (len >= GRF_NAMELEN) { throw new GrfException(); } offset += len; item = GrfItem.CreateV2 ( this, name, EndianConverter.LittleEndian(pBuffer.Read <int>(offset)), EndianConverter.LittleEndian(pBuffer.Read <int>(offset + 4)), EndianConverter.LittleEndian(pBuffer.Read <int>(offset + 8)), (GrfFileFlags)pBuffer[offset + 0xC], EndianConverter.LittleEndian(pBuffer.Read <int>(offset + 0xD)) + GRF_HEADER_FULL_LEN ); m_Items.GrfAdd(item); } } catch (Exception ex) { throw new Exception(ex.Message); } } }
/// <summary> /// Decrypts a filename in a <see cref="GrfArchive"/> that has a version major of 1. /// </summary> /// <param name="buffer">The input buffer of the filename.</param> /// <param name="len">The length of the filename.</param> /// <returns>A <see cref="String"/> with the decrypted filename.</returns> public static string DecryptNameVer1(byte[] buffer, int len) { using (IntPtrEx pBuffer = new IntPtrEx(buffer), pNamebuf = new IntPtrEx(new byte[len])) { GRFMixedProcess(pNamebuf, pBuffer, len, 1, KeySchedule, CryptoType.Decrypt); return(pNamebuf); } }
private static IntPtrEx SwapNibbles(IntPtrEx dst, IntPtrEx src, int len) { for (int i = 0; i < len; i++) { dst[i] = (byte)((src[i] << 4) | (src[i] >> 4)); } return(dst); }
/// <summary> /// Encodes the name with the proper encoding. /// </summary> /// <param name="name">The name to encode.</param> /// <returns>A <see cref="String"/> with the properly encoded filename.</returns> public static string Encode(string name) { byte[] buffer = new byte[name.Length]; using (IntPtrEx pName = new IntPtrEx(name)) { Marshal.Copy(pName, buffer, 0, name.Length); } return Encode(buffer); }
/// <summary> /// Encodes the name with the proper encoding. /// </summary> /// <param name="name">The name to encode.</param> /// <returns>A <see cref="String"/> with the properly encoded filename.</returns> public static string Encode(string name) { byte[] buffer = new byte[name.Length]; using (IntPtrEx pName = new IntPtrEx(name)) { Marshal.Copy(pName, buffer, 0, name.Length); } return(Encode(buffer)); }
/// <summary> /// Encrypts a filename in a <see cref="GrfArchive"/> that has a version major of 1. /// </summary> /// <param name="name">The name to encrypt.</param> /// <param name="len">The length of the name.</param> /// <returns>A <see cref="Byte"/> array containing the encrypted filename.</returns> public static byte[] EncryptNameVer1(string name, int len) { byte[] namebuf = new byte[len]; using (IntPtrEx pName = new IntPtrEx(name), pNamebuf = new IntPtrEx(namebuf)) { GRFMixedProcess(pNamebuf, pName, len, 1, KeySchedule, CryptoType.Encrypt); return(namebuf); } }
/// <summary> /// Encrypts the contents of a file inside the <see cref="GrfArchive"/>. /// </summary> /// <param name="buffer">The unencrypted contents.</param> /// <param name="len">The length of the contents. /// (Note: this is the AlignedCompressedLength, not the CompressedLength)</param> /// <param name="flags">The <see cref="GrfFileFlags"/> of the file.</param> /// <returns>A <see cref="Byte"/> array containing the encrypted contents of the file.</returns> public static byte[] EncryptFileBuffer(byte[] buffer, int len, GrfFileFlags flags) { byte[] dst = new byte[buffer.Length]; using (IntPtrEx pDst = new IntPtrEx(dst), pBuffer = new IntPtrEx(buffer)) { GRFProcess(pDst, pBuffer, buffer.Length, (byte)flags, len, m_KeySchedule, CryptoType.Encrypt); return(dst); } }
private static IntPtr DESProcess(IntPtrEx dst, IntPtrEx src, int len, byte[] ks, CryptoType dir) { IntPtr orig = dst; for (int i = 0; i < len / 8; i++, dst += 8, src += 8) { DESProcessBlock(1, dst, src, ks, dir); } return(orig); }
private static IntPtr DESRawProcessBlock(IntPtrEx block, byte[] ks) { int tmp; byte[][] tmpblock = new byte[2][]; tmpblock[0] = new byte[8]; tmpblock[1] = new byte[8]; for (int i = 0; i < 0x30; i++) { tmp = DES_E[i] + 0x1F; if ((block[tmp >> 3] & BitMap[tmp & 7]) > 0) { tmpblock[0][i / 6] |= BitMap[i % 6]; } } for (int i = 0; i < 8; i++) { tmpblock[0][i] ^= ks[i]; } for (int i = 0; i < 8; i++) { if (i % 2 > 0) { tmpblock[1][i >> 1] += DES_S(i)[tmpblock[0][i] >> 2]; } else { tmpblock[1][i >> 1] = (byte)(DES_S(i)[tmpblock[0][i] >> 2] << 4); } } tmpblock[0] = new byte[8]; for (int i = 0; i < 0x20; i++) { tmp = DES_P[i] - 1; if ((tmpblock[1][tmp >> 3] & BitMap[tmp & 7]) > 0) { tmpblock[0][i >> 3] |= BitMap[i & 7]; } } block[0] ^= tmpblock[0][0]; block[1] ^= tmpblock[0][1]; block[2] ^= tmpblock[0][2]; block[3] ^= tmpblock[0][3]; return(block); }
private static IntPtr DESPermutation(IntPtrEx block, byte[] table) { byte[] tmpblock = new byte[8]; byte tmp; for (int i = 0; i < 0x40; i++) { tmp = (byte)(table[i] - 1); if ((block[tmp >> 3] & BitMap[tmp & 7]) > 0) { tmpblock[i >> 3] |= BitMap[i & 7]; } } MemCpy(tmpblock, block, 8); return(block); }
public void IntPtrSubtractTest() { int[] arr = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 }; unsafe { fixed(int *parr = arr) { // Get the size of an array element. const int Size = sizeof(int); var ptr = IntPtrEx.Add(new IntPtr(parr), Size * (arr.Length - 1)); var index = arr.Length - 1; for (var ctr = 0; ctr < arr.Length; ctr++) { var newPtr = IntPtrEx.Subtract(ptr, ctr * Size); Assert.AreEqual(arr[index], Marshal.ReadInt32(newPtr)); index--; } } } }
/// <summary> /// Decrypts a filename in a <see cref="GrfArchive"/> that has a version major of 1. /// </summary> /// <param name="buffer">The input buffer of the filename.</param> /// <param name="len">The length of the filename.</param> /// <returns>A <see cref="String"/> with the decrypted filename.</returns> public static string DecryptNameVer1(byte[] buffer, int len) { using (IntPtrEx pBuffer = new IntPtrEx(buffer), pNamebuf = new IntPtrEx(new byte[len])) { GRFMixedProcess(pNamebuf, pBuffer, len, 1, KeySchedule, CryptoType.Decrypt); return pNamebuf; } }
private static void MemCpy(IntPtrEx src, byte[] dst, int len) { Marshal.Copy(src, dst, 0, len); }
private void FlushVer2() { byte[] buffer = new byte[m_Items.Count * GRF_ITEM_SIZE]; IntPtrEx pName; int i, offset, len; GrfFileInfo gfile = null; try { m_Items.SortToPosition(); using (IntPtrEx pBuffer = new IntPtrEx(buffer)) { for (i = offset = 0; i < Items.Count; i++) { len = m_Items[i].FullName.Length + 1; using (pName = new IntPtrEx(m_Items[i].FullName)) { Marshal.Copy(pName, buffer, offset, len); } offset += len; if (m_Items[i] is GrfFileInfo) { gfile = (GrfFileInfo)m_Items[i]; if (m_ForceRepack) { gfile.CompressedLength = 0; gfile.AlignedCompressedLength = 0; gfile.Position = 0; } if (gfile.CompressedLength == 0 && gfile.AlignedCompressedLength == 0 && gfile.Position == 0 && gfile.Length != 0) { if (!m_AllowCrypt) { gfile.Flags &= ~(GrfFileFlags.MixCrypt | GrfFileFlags.Des_0x14); } FlushFile(i); } pBuffer.Write <int>(offset, EndianConverter.LittleEndian(gfile.CompressedLength)); pBuffer.Write <int>(offset + 4, EndianConverter.LittleEndian(gfile.AlignedCompressedLength)); pBuffer.Write <int>(offset + 8, EndianConverter.LittleEndian(gfile.Length)); pBuffer.Write <int>(offset + 0xD, EndianConverter.LittleEndian(gfile.Position - GRF_HEADER_FULL_LEN)); } else { pBuffer.Write <int>(offset, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZSMALL)); pBuffer.Write <int>(offset + 4, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZFILE)); pBuffer.Write <int>(offset + 8, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZORIG)); pBuffer.Write <int>(offset + 0xD, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_OFFSET - GRF_HEADER_FULL_LEN)); } pBuffer.Write <byte>(offset + 0xC, (byte)m_Items[i].Flags); offset += 0x11; } } } catch (Exception ex) { throw new Exception(ex.Message); } Array.Resize <byte>(ref buffer, offset); buffer = ZlibStream.CompressBuffer(buffer); m_Items.SortToPosition(); int writeOffset = m_Items.FindUnused(8 + buffer.Length); if (writeOffset == 0) { FileStream.Seek(0, SeekOrigin.End); writeOffset = (int)FileStream.Position; } else { FileStream.Seek(writeOffset, SeekOrigin.Begin); } FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(buffer.Length)), 0, 4); FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(offset)), 0, 4); FileStream.Write(buffer, 0, buffer.Length); FileStream.Seek(GRF_HEADER_MID_LEN, SeekOrigin.Begin); FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(writeOffset - GRF_HEADER_FULL_LEN)), 0, 4); FileStream.Write(BitConverter.GetBytes(0), 0, 4); FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(i + 7)), 0, 4); }
private static IntPtr GRFMixedProcess(IntPtrEx dst, IntPtrEx src, int len, byte cycle, byte[] ks, CryptoType dir) { IntPtr orig = dst; byte j = 0, tmp; if (cycle < 3) cycle = 1; else if (cycle < 5) cycle++; else if (cycle < 7) cycle += 9; else cycle += 0xF; for (int i = 0; i < len / 8; i++, dst += 8, src += 8) { if (i < 0x14 || i % cycle == 0) { DESProcessBlock(1, dst, src, ks, dir); } else { if (j == 7) { if (dir == CryptoType.Decrypt) { // 3450162 MemCpy(src + 3, dst, 2); // 01_____ dst[2] = src[6]; // 012____ MemCpy(src, dst + 3, 3); // 012345_ dst[6] = src[5]; } else { // 0123456 MemCpy(src, dst + 3, 2); // ___01__ dst[6] = src[2]; // ___01_2 MemCpy(src + 3, dst, 3); // 34501_2 dst[5] = src[6]; // 3450162 } // Modify byte 7 if ((tmp = src[7]) <= 0x77) { if (tmp == 0x77) // 0x77 dst[7] = 0x48; else if (tmp == 0) // 0x00 dst[7] = 0x2B; else if ((--tmp) == 0) // 0x01 dst[7] = 0x68; else if ((tmp -= 0x2A) == 0) // 0x2B dst[7] = 0x00; else if ((tmp -= 0x1D) == 0) // 0x48 dst[7] = 0x77; else if ((tmp -= 0x18) == 0) // 0x60 dst[7] = 0xFF; else if ((tmp -= 0x08) == 0) // 0x68 dst[7] = 0x01; else if ((tmp -= 0x04) == 0) // 0x6C dst[7] = 0x80; else dst[7] = src[7]; } else { if ((tmp -= 0x80) == 0) // 0x80 dst[7] = 0x6C; else if ((tmp -= 0x39) == 0) // 0xB9 dst[7] = 0xC0; else if ((tmp -= 0x07) == 0) // 0xC0 dst[7] = 0xB9; else if ((tmp -= 0x2B) == 0) // 0xEB dst[7] = 0xFE; else if ((tmp -= 0x13) == 0) // 0xFE dst[7] = 0xEB; else if ((--tmp) == 0) // 0xFF dst[7] = 0x60; else dst[7] = src[7]; } j = 0; } else { MemCpy(src, dst, 8); } j++; } } return orig; }
private static void MemCpy(IntPtrEx src, IntPtrEx dst, int len) { byte[] buffer = new byte[len]; Marshal.Copy(src, buffer, 0, len); Marshal.Copy(buffer, 0, dst, len); }
private static IntPtr DESPermutation(IntPtrEx block, byte[] table) { byte[] tmpblock = new byte[8]; byte tmp; for (int i = 0; i < 0x40; i++) { tmp = (byte)(table[i] - 1); if ((block[tmp >> 3] & BitMap[tmp & 7]) > 0) tmpblock[i >> 3] |= BitMap[i & 7]; } MemCpy(tmpblock, block, 8); return block; }
private static IntPtr DESProcessBlock(byte rounds, IntPtrEx dst, IntPtrEx src, byte[] ks, CryptoType dir) { byte[] tmp = new byte[4]; MemCpy(src, dst, 8); DESPermutation(dst, DES_IP); if (rounds > 0) { for (int i = 0; i < rounds; i++) { //DES_RawProcessBlock(dst, ks + (dir == CryptoType.Decrypt ? 0xF - i : i) * 8); DESRawProcessBlock(dst, ks); MemCpy(dst, tmp, 4); MemCpy(dst + 4, dst, 4); MemCpy(tmp, dst + 4, 4); } } MemCpy(dst, tmp, 4); MemCpy(dst + 4, dst, 4); MemCpy(tmp, dst + 4, 4); DESPermutation(dst, DES_IP_INV); return dst; }
private void ReadVer1Info() { if (m_IntVersion > 0x103) throw new GrfException(); int offset = (int)FileStream.Position; int len2, len = (int)FileStream.Length - offset; byte[] buffer = new byte[len], namebuf = new byte[GRF_NAMELEN]; try { FileStream.Read(buffer, 0, len); string name = null; GrfItem item; using (IntPtrEx pBuffer = new IntPtrEx(buffer)) { for (int i = offset = 0; i < m_Items.Capacity; i++) { len = EndianConverter.LittleEndian(pBuffer.Read<int>(offset)); offset += 4; if (m_IntVersion < 0x101) { len2 = pBuffer.Read<string>(offset).Length; if (len2 >= GRF_NAMELEN) throw new GrfException(); name = SwapNibbles(pBuffer + offset, len2); } else if (m_IntVersion < 0x104) { offset += 2; len2 = len - 6; if (len2 >= GRF_NAMELEN) throw new GrfException(); SwapNibbles(namebuf, pBuffer + offset, len2); name = GrfCrypt.DecryptNameVer1(namebuf, len2); len -= 2; } offset += len; item = GrfItem.CreateV1 ( this, name, EndianConverter.LittleEndian(pBuffer.Read<int>(offset)) - EndianConverter.LittleEndian(pBuffer.Read<int>(offset + 8)) - 0x02CB, EndianConverter.LittleEndian(pBuffer.Read<int>(offset + 4)) - 0x92CB, EndianConverter.LittleEndian(pBuffer.Read<int>(offset + 8)), (GrfFileFlags)pBuffer[offset + 0xC], EndianConverter.LittleEndian(pBuffer.Read<int>(offset + 0xD)) + GRF_HEADER_FULL_LEN ); m_Items.GrfAdd(item); offset += 0x11; } } } catch (Exception ex) { throw new Exception(ex.Message); } }
private static string SwapNibbles(IntPtrEx src, int len) { using (IntPtrEx pBuffer = new IntPtrEx(new byte[len])) { return SwapNibbles(pBuffer, src, len).Read<string>(); } }
private void ReadVer2Info() { if (m_IntVersion != 0x200) throw new GrfException(); byte[] buf = new byte[8], zbuf; int len, len2; FileStream.Read(buf, 0, 8); len = EndianConverter.LittleEndian(BitConverter.ToInt32(buf, 0)); if (0 == (len2 = EndianConverter.LittleEndian(BitConverter.ToInt32(buf, 4)))) return; zbuf = new byte[len]; FileStream.Read(zbuf, 0, len); using (IntPtrEx pBuffer = new IntPtrEx(ZlibStream.UncompressBuffer(zbuf))) { string name = null; GrfItem item; try { for (int i = 0, offset = 0; i < m_Items.Capacity; i++, offset += 0x11) { name = pBuffer.Read<string>(offset); len = name.Length + 1; if (len >= GRF_NAMELEN) throw new GrfException(); offset += len; item = GrfItem.CreateV2 ( this, name, EndianConverter.LittleEndian(pBuffer.Read<int>(offset)), EndianConverter.LittleEndian(pBuffer.Read<int>(offset + 4)), EndianConverter.LittleEndian(pBuffer.Read<int>(offset + 8)), (GrfFileFlags)pBuffer[offset + 0xC], EndianConverter.LittleEndian(pBuffer.Read<int>(offset + 0xD)) + GRF_HEADER_FULL_LEN ); m_Items.GrfAdd(item); } } catch (Exception ex) { throw new Exception(ex.Message); } } }
private void ReadHeader() { if (FileStream.CanWrite && FileStream.Length < 1) { byte[] zbuf = ZlibStream.CompressBuffer(new byte[0]); byte[] zero = new byte[4]; int zlen_le = EndianConverter.LittleEndian(zbuf.Length), zero_fcount = EndianConverter.LittleEndian(7), create_ver = EndianConverter.LittleEndian(m_IntVersion); FileStream.Write(Encoding.ASCII.GetBytes(GRF_HEADER), 0, GRF_HEADER_LEN); FileStream.Write(CryptWatermark, 0, CryptWatermark.Length); FileStream.Write(zero, 0, 4); FileStream.Write(zero, 0, 4); FileStream.Write(BitConverter.GetBytes(zero_fcount), 0, 4); FileStream.Write(BitConverter.GetBytes(create_ver), 0, 4); FileStream.Write(BitConverter.GetBytes(zlen_le), 0, 4); FileStream.Write(zero, 0, 4); FileStream.Write(zbuf, 0, zbuf.Length); FileStream.Seek(0, SeekOrigin.Begin); } byte[] buf = new byte[GRF_HEADER_FULL_LEN]; FileStream.Read(buf, 0, buf.Length); if (buf[GRF_HEADER_LEN + 1] == 1) { m_AllowCrypt = true; // 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E for (byte i = 0; i < 0xF; i++) { if (buf[GRF_HEADER_LEN + i] != i) { throw new GrfException(); } } } else if (buf[GRF_HEADER_LEN] == 0) { m_AllowCrypt = false; // 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 for (byte i = 0; i < 0xF; i++) { if (buf[GRF_HEADER_LEN + i] != 0) { throw new GrfException(); } } } else { throw new GrfException(); } using (IntPtrEx pBuffer = new IntPtrEx(buf)) { m_Items = new GrfItemCollection(this); m_IntVersion = EndianConverter.LittleEndian(pBuffer.Read <int>(GRF_HEADER_MID_LEN + 0xC)); m_Items.Capacity = EndianConverter.LittleEndian(pBuffer.Read <int>(GRF_HEADER_MID_LEN + 8)) - EndianConverter.LittleEndian(pBuffer.Read <int>(GRF_HEADER_MID_LEN + 4)) - 7; FileStream.Seek(EndianConverter.LittleEndian(pBuffer.Read <int>(GRF_HEADER_MID_LEN) + GRF_HEADER_FULL_LEN), SeekOrigin.Begin); } switch (m_IntVersion & 0xFF00) { case 0x0200: ReadVer2Info(); break; case 0x0100: ReadVer1Info(); break; default: throw new GrfException(); } }
private void ReadVer1Info() { if (m_IntVersion > 0x103) { throw new GrfException(); } int offset = (int)FileStream.Position; int len2, len = (int)FileStream.Length - offset; byte[] buffer = new byte[len], namebuf = new byte[GRF_NAMELEN]; try { FileStream.Read(buffer, 0, len); string name = null; GrfItem item; using (IntPtrEx pBuffer = new IntPtrEx(buffer)) { for (int i = offset = 0; i < m_Items.Capacity; i++) { len = EndianConverter.LittleEndian(pBuffer.Read <int>(offset)); offset += 4; if (m_IntVersion < 0x101) { len2 = pBuffer.Read <string>(offset).Length; if (len2 >= GRF_NAMELEN) { throw new GrfException(); } name = SwapNibbles(pBuffer + offset, len2); } else if (m_IntVersion < 0x104) { offset += 2; len2 = len - 6; if (len2 >= GRF_NAMELEN) { throw new GrfException(); } SwapNibbles(namebuf, pBuffer + offset, len2); name = GrfCrypt.DecryptNameVer1(namebuf, len2); len -= 2; } offset += len; item = GrfItem.CreateV1 ( this, name, EndianConverter.LittleEndian(pBuffer.Read <int>(offset)) - EndianConverter.LittleEndian(pBuffer.Read <int>(offset + 8)) - 0x02CB, EndianConverter.LittleEndian(pBuffer.Read <int>(offset + 4)) - 0x92CB, EndianConverter.LittleEndian(pBuffer.Read <int>(offset + 8)), (GrfFileFlags)pBuffer[offset + 0xC], EndianConverter.LittleEndian(pBuffer.Read <int>(offset + 0xD)) + GRF_HEADER_FULL_LEN ); m_Items.GrfAdd(item); offset += 0x11; } } } catch (Exception ex) { throw new Exception(ex.Message); } }
/// <summary> /// Encrypts the contents of a file inside the <see cref="GrfArchive"/>. /// </summary> /// <param name="buffer">The unencrypted contents.</param> /// <param name="len">The length of the contents. /// (Note: this is the AlignedCompressedLength, not the CompressedLength)</param> /// <param name="flags">The <see cref="GrfFileFlags"/> of the file.</param> /// <returns>A <see cref="Byte"/> array containing the encrypted contents of the file.</returns> public static byte[] EncryptFileBuffer(byte[] buffer, int len, GrfFileFlags flags) { byte[] dst = new byte[buffer.Length]; using (IntPtrEx pDst = new IntPtrEx(dst), pBuffer = new IntPtrEx(buffer)) { GRFProcess(pDst, pBuffer, buffer.Length, (byte)flags, len, m_KeySchedule, CryptoType.Encrypt); return dst; } }
private void ReadHeader() { if (FileStream.CanWrite && FileStream.Length < 1) { byte[] zbuf = ZlibStream.CompressBuffer(new byte[0]); byte[] zero = new byte[4]; int zlen_le = EndianConverter.LittleEndian(zbuf.Length), zero_fcount = EndianConverter.LittleEndian(7), create_ver = EndianConverter.LittleEndian(m_IntVersion); FileStream.Write(Encoding.ASCII.GetBytes(GRF_HEADER), 0, GRF_HEADER_LEN); FileStream.Write(CryptWatermark, 0, CryptWatermark.Length); FileStream.Write(zero, 0, 4); FileStream.Write(zero, 0, 4); FileStream.Write(BitConverter.GetBytes(zero_fcount), 0, 4); FileStream.Write(BitConverter.GetBytes(create_ver), 0, 4); FileStream.Write(BitConverter.GetBytes(zlen_le), 0, 4); FileStream.Write(zero, 0, 4); FileStream.Write(zbuf, 0, zbuf.Length); FileStream.Seek(0, SeekOrigin.Begin); } byte[] buf = new byte[GRF_HEADER_FULL_LEN]; FileStream.Read(buf, 0, buf.Length); if (buf[GRF_HEADER_LEN + 1] == 1) { m_AllowCrypt = true; // 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E for (byte i = 0; i < 0xF; i++) if (buf[GRF_HEADER_LEN + i] != i) throw new GrfException(); } else if (buf[GRF_HEADER_LEN] == 0) { m_AllowCrypt = false; // 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 for (byte i = 0; i < 0xF; i++) if (buf[GRF_HEADER_LEN + i] != 0) throw new GrfException(); } else { throw new GrfException(); } using (IntPtrEx pBuffer = new IntPtrEx(buf)) { m_Items = new GrfItemCollection(this); m_IntVersion = EndianConverter.LittleEndian(pBuffer.Read<int>(GRF_HEADER_MID_LEN + 0xC)); m_Items.Capacity = EndianConverter.LittleEndian(pBuffer.Read<int>(GRF_HEADER_MID_LEN + 8)) - EndianConverter.LittleEndian(pBuffer.Read<int>(GRF_HEADER_MID_LEN + 4)) - 7; FileStream.Seek(EndianConverter.LittleEndian(pBuffer.Read<int>(GRF_HEADER_MID_LEN) + GRF_HEADER_FULL_LEN), SeekOrigin.Begin); } switch (m_IntVersion & 0xFF00) { case 0x0200: ReadVer2Info(); break; case 0x0100: ReadVer1Info(); break; default: throw new GrfException(); } }
/// <summary> /// Encrypts a filename in a <see cref="GrfArchive"/> that has a version major of 1. /// </summary> /// <param name="name">The name to encrypt.</param> /// <param name="len">The length of the name.</param> /// <returns>A <see cref="Byte"/> array containing the encrypted filename.</returns> public static byte[] EncryptNameVer1(string name, int len) { byte[] namebuf = new byte[len]; using (IntPtrEx pName = new IntPtrEx(name), pNamebuf = new IntPtrEx(namebuf)) { GRFMixedProcess(pNamebuf, pName, len, 1, KeySchedule, CryptoType.Encrypt); return namebuf; } }
private void FlushVer2() { byte[] buffer = new byte[m_Items.Count * GRF_ITEM_SIZE]; IntPtrEx pName; int i, offset, len; GrfFileInfo gfile = null; try { m_Items.SortToPosition(); using (IntPtrEx pBuffer = new IntPtrEx(buffer)) { for (i = offset = 0; i < Items.Count; i++) { len = m_Items[i].FullName.Length + 1; using (pName = new IntPtrEx(m_Items[i].FullName)) { Marshal.Copy(pName, buffer, offset, len); } offset += len; if (m_Items[i] is GrfFileInfo) { gfile = (GrfFileInfo)m_Items[i]; if (m_ForceRepack) { gfile.CompressedLength = 0; gfile.AlignedCompressedLength = 0; gfile.Position = 0; } if (gfile.CompressedLength == 0 && gfile.AlignedCompressedLength == 0 && gfile.Position == 0 && gfile.Length != 0) { if (!m_AllowCrypt) gfile.Flags &= ~(GrfFileFlags.MixCrypt | GrfFileFlags.Des_0x14); FlushFile(i); } pBuffer.Write<int>(offset, EndianConverter.LittleEndian(gfile.CompressedLength)); pBuffer.Write<int>(offset + 4, EndianConverter.LittleEndian(gfile.AlignedCompressedLength)); pBuffer.Write<int>(offset + 8, EndianConverter.LittleEndian(gfile.Length)); pBuffer.Write<int>(offset + 0xD, EndianConverter.LittleEndian(gfile.Position - GRF_HEADER_FULL_LEN)); } else { pBuffer.Write<int>(offset, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZSMALL)); pBuffer.Write<int>(offset + 4, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZFILE)); pBuffer.Write<int>(offset + 8, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZORIG)); pBuffer.Write<int>(offset + 0xD, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_OFFSET - GRF_HEADER_FULL_LEN)); } pBuffer.Write<byte>(offset + 0xC, (byte)m_Items[i].Flags); offset += 0x11; } } } catch (Exception ex) { throw new Exception(ex.Message); } Array.Resize<byte>(ref buffer, offset); buffer = ZlibStream.CompressBuffer(buffer); m_Items.SortToPosition(); int writeOffset = m_Items.FindUnused(8 + buffer.Length); if (writeOffset == 0) { FileStream.Seek(0, SeekOrigin.End); writeOffset = (int)FileStream.Position; } else { FileStream.Seek(writeOffset, SeekOrigin.Begin); } FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(buffer.Length)), 0, 4); FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(offset)), 0, 4); FileStream.Write(buffer, 0, buffer.Length); FileStream.Seek(GRF_HEADER_MID_LEN, SeekOrigin.Begin); FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(writeOffset - GRF_HEADER_FULL_LEN)), 0, 4); FileStream.Write(BitConverter.GetBytes(0), 0, 4); FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(i + 7)), 0, 4); }
private static IntPtr DESProcess(IntPtrEx dst, IntPtrEx src, int len, byte[] ks, CryptoType dir) { IntPtr orig = dst; for (int i = 0; i < len / 8; i++, dst += 8, src += 8) DESProcessBlock(1, dst, src, ks, dir); return orig; }
private void FlushVer1() { byte[] buffer = new byte[m_Items.Count * GRF_ITEM_SIZE]; int i, offset, len, writeOffset; GrfFileInfo gfile = null; try { m_Items.SortToPosition(); using (IntPtrEx pBuffer = new IntPtrEx(buffer)) { for (i = offset = 0; i < Items.Count; i++) { if (m_Items[i] is GrfFileInfo) { gfile = (GrfFileInfo)m_Items[i]; if (m_ForceRepack) { gfile.CompressedLength = 0; gfile.AlignedCompressedLength = 0; gfile.Position = 0; } if (gfile.CompressedLength == 0 && gfile.AlignedCompressedLength == 0 && gfile.Position == 0 && gfile.Length != 0) { if (gfile.CheckExtension()) gfile.Flags = (gfile.Flags & ~GrfFileFlags.MixCrypt) | GrfFileFlags.Des_0x14; else gfile.Flags = (gfile.Flags & ~GrfFileFlags.Des_0x14) | GrfFileFlags.MixCrypt; FlushFile(i); } } len = m_Items[i].FullName.Length + 1; if (m_IntVersion < 0x101) { pBuffer.Write<int>(offset, len); SwapNibbles(pBuffer + offset + 4, m_Items[i].FullName, len); offset += 4 + len; } else if (m_IntVersion < 0x104) { pBuffer.Write<int>(offset, len + 6); offset += 4; SwapNibbles(pBuffer + offset + 6, GrfCrypt.EncryptNameVer1(m_Items[i].Name, len), len); offset += len + 6; } if (m_Items[i] is GrfDirectoryInfo) { pBuffer.Write<int>(offset, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZSMALL + GrfItem.GRFFILE_DIR_SZORIG + 0x02CB)); pBuffer.Write<int>(offset + 4, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZFILE + 0x92CB)); pBuffer.Write<int>(offset + 8, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZORIG)); pBuffer.Write<int>(offset + 0xD, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_OFFSET - GRF_HEADER_FULL_LEN)); } else { pBuffer.Write<int>(offset, EndianConverter.LittleEndian(gfile.CompressedLength + gfile.Length + 0x02CB)); pBuffer.Write<int>(offset + 4, EndianConverter.LittleEndian(gfile.AlignedCompressedLength + 0x92CB)); pBuffer.Write<int>(offset + 8, EndianConverter.LittleEndian(gfile.Length)); pBuffer.Write<int>(offset + 0xD, EndianConverter.LittleEndian(gfile.Position - GRF_HEADER_FULL_LEN)); } pBuffer.Write<byte>(offset + 0xC, (byte)(m_Items[i].Flags & GrfFileFlags.File)); offset += 0x11; } } } catch (Exception ex) { throw new Exception(ex.Message); } FileStream.Seek(0, SeekOrigin.End); writeOffset = (int)FileStream.Position; FileStream.Write(buffer, 0, offset); FileStream.Seek(GRF_HEADER_MID_LEN, SeekOrigin.End); FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(writeOffset - GRF_HEADER_FULL_LEN)), 0, 4); FileStream.Write(BitConverter.GetBytes(0), 0, 4); FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(i + 0 + 7)), 0, 4); }
private static IntPtr DESRawProcessBlock(IntPtrEx block, byte[] ks) { int tmp; byte[][] tmpblock = new byte[2][]; tmpblock[0] = new byte[8]; tmpblock[1] = new byte[8]; for (int i = 0; i < 0x30; i++) { tmp = DES_E[i] + 0x1F; if ((block[tmp >> 3] & BitMap[tmp & 7]) > 0) tmpblock[0][i / 6] |= BitMap[i % 6]; } for (int i = 0; i < 8; i++) tmpblock[0][i] ^= ks[i]; for (int i = 0; i < 8; i++) { if (i % 2 > 0) tmpblock[1][i >> 1] += DES_S(i)[tmpblock[0][i] >> 2]; else tmpblock[1][i >> 1] = (byte)(DES_S(i)[tmpblock[0][i] >> 2] << 4); } tmpblock[0] = new byte[8]; for (int i = 0; i < 0x20; i++) { tmp = DES_P[i] - 1; if ((tmpblock[1][tmp >> 3] & BitMap[tmp & 7]) > 0) tmpblock[0][i >> 3] |= BitMap[i & 7]; } block[0] ^= tmpblock[0][0]; block[1] ^= tmpblock[0][1]; block[2] ^= tmpblock[0][2]; block[3] ^= tmpblock[0][3]; return block; }
private static IntPtrEx SwapNibbles(IntPtrEx dst, IntPtrEx src, int len) { for (int i = 0; i < len; i++) dst[i] = (byte)((src[i] << 4) | (src[i] >> 4)); return dst; }
private static IntPtr GRFProcess(IntPtrEx dst, IntPtrEx src, int len, byte flags, int digitsGen, byte[] ks, CryptoType dir) { int digits, i; if ((flags & GRFFILE_FLAG_MIXCRYPT) == GRFFILE_FLAG_MIXCRYPT) { for (i = digitsGen, digits = 0; i > 0; i /= 0xA, digits++) ; if (digits < 1) digits = 1; GRFMixedProcess(dst, src, len, (byte)digits, ks, dir); } else if ((flags & GRFFILE_FLAG_0x14_DES) == GRFFILE_FLAG_0x14_DES) { i = len / 8; if (i > 0x14) { i = 0x14; MemCpy(src + 0x14 * 8, dst + 0x14 * 8, len - 0x14 * 8); } DESProcess(dst, src, i * 8, ks, dir); } else { MemCpy(src, dst, len); } return dst; }
private static IntPtr GRFMixedProcess(IntPtrEx dst, IntPtrEx src, int len, byte cycle, byte[] ks, CryptoType dir) { IntPtr orig = dst; byte j = 0, tmp; if (cycle < 3) { cycle = 1; } else if (cycle < 5) { cycle++; } else if (cycle < 7) { cycle += 9; } else { cycle += 0xF; } for (int i = 0; i < len / 8; i++, dst += 8, src += 8) { if (i < 0x14 || i % cycle == 0) { DESProcessBlock(1, dst, src, ks, dir); } else { if (j == 7) { if (dir == CryptoType.Decrypt) { // 3450162 MemCpy(src + 3, dst, 2); // 01_____ dst[2] = src[6]; // 012____ MemCpy(src, dst + 3, 3); // 012345_ dst[6] = src[5]; } else { // 0123456 MemCpy(src, dst + 3, 2); // ___01__ dst[6] = src[2]; // ___01_2 MemCpy(src + 3, dst, 3); // 34501_2 dst[5] = src[6]; // 3450162 } // Modify byte 7 if ((tmp = src[7]) <= 0x77) { if (tmp == 0x77) // 0x77 { dst[7] = 0x48; } else if (tmp == 0) // 0x00 { dst[7] = 0x2B; } else if ((--tmp) == 0) // 0x01 { dst[7] = 0x68; } else if ((tmp -= 0x2A) == 0) // 0x2B { dst[7] = 0x00; } else if ((tmp -= 0x1D) == 0) // 0x48 { dst[7] = 0x77; } else if ((tmp -= 0x18) == 0) // 0x60 { dst[7] = 0xFF; } else if ((tmp -= 0x08) == 0) // 0x68 { dst[7] = 0x01; } else if ((tmp -= 0x04) == 0) // 0x6C { dst[7] = 0x80; } else { dst[7] = src[7]; } } else { if ((tmp -= 0x80) == 0) // 0x80 { dst[7] = 0x6C; } else if ((tmp -= 0x39) == 0) // 0xB9 { dst[7] = 0xC0; } else if ((tmp -= 0x07) == 0) // 0xC0 { dst[7] = 0xB9; } else if ((tmp -= 0x2B) == 0) // 0xEB { dst[7] = 0xFE; } else if ((tmp -= 0x13) == 0) // 0xFE { dst[7] = 0xEB; } else if ((--tmp) == 0) // 0xFF { dst[7] = 0x60; } else { dst[7] = src[7]; } } j = 0; } else { MemCpy(src, dst, 8); } j++; } } return(orig); }
private static void MemCpy(byte[] src, IntPtrEx dst, int len) { Marshal.Copy(src, 0, dst, len); }
private static IntPtrEx SwapNibbles(IntPtrEx dst, string src, int len) { using (IntPtrEx pSrc = new IntPtrEx(src)) { return SwapNibbles(dst, pSrc, len); } }
private void FlushVer1() { byte[] buffer = new byte[m_Items.Count * GRF_ITEM_SIZE]; int i, offset, len, writeOffset; GrfFileInfo gfile = null; try { m_Items.SortToPosition(); using (IntPtrEx pBuffer = new IntPtrEx(buffer)) { for (i = offset = 0; i < Items.Count; i++) { if (m_Items[i] is GrfFileInfo) { gfile = (GrfFileInfo)m_Items[i]; if (m_ForceRepack) { gfile.CompressedLength = 0; gfile.AlignedCompressedLength = 0; gfile.Position = 0; } if (gfile.CompressedLength == 0 && gfile.AlignedCompressedLength == 0 && gfile.Position == 0 && gfile.Length != 0) { if (gfile.CheckExtension()) { gfile.Flags = (gfile.Flags & ~GrfFileFlags.MixCrypt) | GrfFileFlags.Des_0x14; } else { gfile.Flags = (gfile.Flags & ~GrfFileFlags.Des_0x14) | GrfFileFlags.MixCrypt; } FlushFile(i); } } len = m_Items[i].FullName.Length + 1; if (m_IntVersion < 0x101) { pBuffer.Write <int>(offset, len); SwapNibbles(pBuffer + offset + 4, m_Items[i].FullName, len); offset += 4 + len; } else if (m_IntVersion < 0x104) { pBuffer.Write <int>(offset, len + 6); offset += 4; SwapNibbles(pBuffer + offset + 6, GrfCrypt.EncryptNameVer1(m_Items[i].Name, len), len); offset += len + 6; } if (m_Items[i] is GrfDirectoryInfo) { pBuffer.Write <int>(offset, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZSMALL + GrfItem.GRFFILE_DIR_SZORIG + 0x02CB)); pBuffer.Write <int>(offset + 4, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZFILE + 0x92CB)); pBuffer.Write <int>(offset + 8, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_SZORIG)); pBuffer.Write <int>(offset + 0xD, EndianConverter.LittleEndian(GrfItem.GRFFILE_DIR_OFFSET - GRF_HEADER_FULL_LEN)); } else { pBuffer.Write <int>(offset, EndianConverter.LittleEndian(gfile.CompressedLength + gfile.Length + 0x02CB)); pBuffer.Write <int>(offset + 4, EndianConverter.LittleEndian(gfile.AlignedCompressedLength + 0x92CB)); pBuffer.Write <int>(offset + 8, EndianConverter.LittleEndian(gfile.Length)); pBuffer.Write <int>(offset + 0xD, EndianConverter.LittleEndian(gfile.Position - GRF_HEADER_FULL_LEN)); } pBuffer.Write <byte>(offset + 0xC, (byte)(m_Items[i].Flags & GrfFileFlags.File)); offset += 0x11; } } } catch (Exception ex) { throw new Exception(ex.Message); } FileStream.Seek(0, SeekOrigin.End); writeOffset = (int)FileStream.Position; FileStream.Write(buffer, 0, offset); FileStream.Seek(GRF_HEADER_MID_LEN, SeekOrigin.End); FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(writeOffset - GRF_HEADER_FULL_LEN)), 0, 4); FileStream.Write(BitConverter.GetBytes(0), 0, 4); FileStream.Write(BitConverter.GetBytes(EndianConverter.LittleEndian(i + 0 + 7)), 0, 4); }