diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index f8d2c8aa..c9850e37 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -103,6 +103,7 @@ + diff --git a/ArcFormats/KiriKiri/ArcXP3.cs b/ArcFormats/KiriKiri/ArcXP3.cs index 3f723c98..9bad7268 100644 --- a/ArcFormats/KiriKiri/ArcXP3.cs +++ b/ArcFormats/KiriKiri/ArcXP3.cs @@ -2,7 +2,7 @@ //! \date Wed Jul 16 13:58:17 2014 //! \brief KiriKiri engine archive implementation. // -// Copyright (C) 2014-2015 by morkt +// Copyright (C) 2014-2016 by morkt // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to @@ -837,505 +837,4 @@ NextEntry: } #endregion } - - [Serializable] - public abstract class ICrypt - { - /// - /// whether Adler32 checksum should be calculated after contents have been encrypted. - /// - public virtual bool HashAfterCrypt { get { return false; } } - - /// - /// whether XP3 index is obfuscated: - /// - duplicate entries - /// - entries have additional dummy segments - /// - public virtual bool ObfuscatedIndex { get { return false; } } - - public virtual byte Decrypt (Xp3Entry entry, long offset, byte value) - { - byte[] buffer = new byte[1] { value }; - Decrypt (entry, offset, buffer, 0, 1); - return buffer[0]; - } - - public abstract void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count); - - public virtual void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - throw new NotImplementedException (arcStrings.MsgEncNotImplemented); - } - } - - [Serializable] - public class NoCrypt : ICrypt - { - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - return value; - } - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - return; - } - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - return; - } - } - - [Serializable] - public class FateCrypt : ICrypt - { - public override bool HashAfterCrypt { get { return true; } } - - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - byte result = (byte)(value ^ 0x36); - if (0x13 == offset) - result ^= 1; - else if (0x2ea29 == offset) - result ^= 3; - return result; - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - for (int i = 0; i < count; ++i) - { - values[pos+i] ^= 0x36; - } - if (offset > 0x2ea29) - return; - if (offset + count > 0x2ea29) - values[pos+0x2ea29-offset] ^= 3; - if (offset > 0x13) - return; - if (offset + count > 0x13) - values[pos+0x13-offset] ^= 1; - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - Decrypt (entry, offset, values, pos, count); - } - } - - [Serializable] - public class HashCrypt : ICrypt - { - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - return (byte)(value ^ entry.Hash); - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - byte key = (byte)entry.Hash; - for (int i = 0; i < count; ++i) - { - values[pos+i] ^= key; - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - Decrypt (entry, offset, values, pos, count); - } - } - - [Serializable] - public class XorCrypt : ICrypt - { - private byte m_key; - - public byte Key - { - get { return m_key; } - set { m_key = value; } - } - - public XorCrypt (uint key) - { - m_key = (byte)key; - } - - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - return (byte)(value ^ m_key); - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - for (int i = 0; i < count; ++i) - { - values[pos+i] ^= m_key; - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - Decrypt (entry, offset, values, pos, count); - } - } - - [Serializable] - public class SwanSongCrypt : ICrypt - { - static private byte Adjust (uint hash, out int shift) - { - int cl = (int)(hash & 0xff); - if (0 == cl) cl = 0x0f; - shift = cl & 7; - int ch = (int)((hash >> 8) & 0xff); - if (0 == ch) ch = 0xf0; - return (byte)ch; - } - - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - int shift; - byte xor = Adjust (entry.Hash, out shift); - uint data = (uint)(value ^ xor); - return (byte)((data >> shift) | (data << (8 - shift))); - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - int shift; - byte xor = Adjust (entry.Hash, out shift); - for (int i = 0; i < count; ++i) - { - uint data = (uint)(values[pos+i] ^ xor); - values[pos+i] = (byte)((data >> shift) | (data << (8 - shift))); - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - int shift; - byte xor = Adjust (entry.Hash, out shift); - for (int i = 0; i < count; ++i) - { - uint data = values[pos+i]; - data = (byte)((data << shift) | (data >> (8 - shift))); - values[pos+i] = (byte)(data ^ xor); - } - } - } - - [Serializable] - public class SeitenCrypt : ICrypt - { - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - uint key = entry.Hash ^ (uint)offset; - if (0 != (key & 2)) - { - int ecx = (int)key & 0x18; - value ^= (byte)((key >> ecx) | (key >> (ecx & 8))); - } - if (0 != (key & 4)) - { - value += (byte)key; - } - if (0 != (key & 8)) - { - value -= (byte)(key >> (int)(key & 0x10)); - } - return value; - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] buffer, int pos, int count) - { - for (int i = 0; i < count; ++i) - { - int shift; - uint key = entry.Hash ^ (uint)offset; - byte v = buffer[pos+i]; - if (0 != (key & 2)) - { - shift = (int)key & 0x18; - uint ebx = key >> shift; - shift &= 8; - v ^= (byte)(ebx | (key >> shift)); - } - if (0 != (key & 4)) - { - v += (byte)key; - } - if (0 != (key & 8)) - { - shift = (int)key & 0x10; - v -= (byte)(key >> shift); - } - buffer[pos+i] = v; - ++offset; - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - for (int i = 0; i < count; ++i) - { - uint key = entry.Hash ^ (uint)offset; - if (0 != (key & 8)) - { - values[pos+i] += (byte)(key >> (int)(key & 0x10)); - } - if (0 != (key & 4)) - { - values[pos+i] -= (byte)key; - } - if (0 != (key & 2)) - { - int ecx = (int)key & 0x18; - values[pos+i] ^= (byte)((key >> ecx) | (key >> (ecx & 8))); - } - } - } - } - - [Serializable] - public class OkibaCrypt : ICrypt - { - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - if (offset < 0x65) - return (byte)(value ^ (byte)(entry.Hash >> 4)); - uint key = entry.Hash; - // 0,1,2,3 -> 1,0,3,2 - key = ((key & 0xff0000) << 8) | ((key & 0xff000000) >> 8) - | ((key & 0xff00) >> 8) | ((key & 0xff) << 8); - key >>= 8 * ((int)(offset - 0x65) & 3); - return (byte)(value ^ (byte)key); - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - int i = 0; - if (offset < 0x65) - { - uint key = entry.Hash >> 4; - int limit = Math.Min (count, (int)(0x65 - offset)); - for (; i < limit; ++i) - { - values[pos+i] ^= (byte)key; - ++offset; - } - } - if (i < count) - { - offset -= 0x65; - uint key = entry.Hash; - key = ((key & 0xff0000) << 8) | ((key & 0xff000000) >> 8) - | ((key & 0xff00) >> 8) | ((key & 0xff) << 8); - do - { - values[pos+i] ^= (byte)(key >> (8 * ((int)offset & 3))); - ++offset; - } - while (++i < count); - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - Decrypt (entry, offset, values, pos, count); - } - } - - [Serializable] - public class SaiminCrypt : ICrypt - { - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - byte key = (byte)entry.Hash; - if (offset < 0x7B) - value ^= (byte)(21 * key); - else if (offset < 0xF6) - value += (byte)(-32 * key); - else if (offset < 0x171) - value ^= (byte)(43 * key); - else if (offset <= 0xffffffffL) - value += (byte)(-54 * key); - return value; - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - byte key = (byte)entry.Hash; - for (int i = 0; i < count && offset <= 0xffffffffL; ++i, ++offset) - { - if (offset < 0x7B) - values[pos+i] ^= (byte)(21 * key); - else if (offset < 0xF6) - values[pos+i] += (byte)(-32 * key); - else if (offset >= 0x171) - values[pos+i] += (byte)(-54 * key); - else - values[pos+i] ^= (byte)(43 * key); - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - byte key = (byte)entry.Hash; - for (int i = 0; i < count && offset <= 0xffffffffL; ++i, ++offset) - { - if (offset < 0x7B) - values[pos+i] ^= (byte)(21 * key); - else if (offset < 0xF6) - values[pos+i] -= (byte)(-32 * key); - else if (offset >= 0x171) - values[pos+i] -= (byte)(-54 * key); - else - values[pos+i] ^= (byte)(43 * key); - } - } - } - - [Serializable] - public class DameganeCrypt : ICrypt - { - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - if (0 != (offset & 1)) - return (byte)(value ^ entry.Hash); - else - return (byte)(value ^ offset); - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - for (int i = 0; i < count; ++i, ++offset) - { - if (0 != (offset & 1)) - values[pos+i] ^= (byte)entry.Hash; - else - values[pos+i] ^= (byte)offset; - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - Decrypt (entry, offset, values, pos, count); - } - } - - [Serializable] - public class GakuenButouCrypt : ICrypt - { - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - if (0 != (offset & 1)) - return (byte)(value ^ offset); - else - return (byte)(value ^ entry.Hash); - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - for (int i = 0; i < count; ++i, ++offset) - { - if (0 != (offset & 1)) - values[pos+i] ^= (byte)offset; - else - values[pos+i] ^= (byte)entry.Hash; - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - Decrypt (entry, offset, values, pos, count); - } - } - - [Serializable] - public class AlteredPinkCrypt : ICrypt - { - static readonly byte[] KeyTable = { - 0x43, 0xF8, 0xAD, 0x08, 0xDF, 0xB7, 0x26, 0x44, 0xF0, 0xD9, 0xE9, 0x24, 0x1A, 0xC1, 0xEE, 0xB4, - 0x11, 0x4B, 0xE4, 0xAF, 0x01, 0x5B, 0xF0, 0xAB, 0x6A, 0x70, 0x78, 0x84, 0xB0, 0x78, 0x4F, 0xED, - 0x39, 0x52, 0x69, 0xAF, 0xC4, 0x92, 0x2A, 0x21, 0xDE, 0xDC, 0x6E, 0x63, 0x9D, 0x9B, 0x63, 0xE1, - 0xB1, 0x94, 0x40, 0x6E, 0x3A, 0x52, 0x5A, 0x28, 0x08, 0x4D, 0xFB, 0x22, 0x18, 0xEB, 0xBA, 0x98, - 0x49, 0x77, 0xBF, 0xAA, 0x43, 0x75, 0xF5, 0xD3, 0x83, 0x71, 0x58, 0xA4, 0xAF, 0x1B, 0x53, 0x99, - 0x8A, 0x27, 0x5B, 0xC2, 0x7F, 0x7A, 0xCD, 0x8D, 0x33, 0x59, 0xEB, 0xA6, 0xFA, 0x7C, 0x00, 0x19, - 0xC4, 0xAA, 0x24, 0xF8, 0x84, 0xCD, 0xF7, 0x20, 0x4B, 0xAB, 0xF1, 0xD5, 0x01, 0x6F, 0x7C, 0x91, - 0x08, 0x7D, 0x8D, 0x89, 0x7C, 0x71, 0x65, 0x99, 0x9B, 0x6F, 0x3A, 0x1C, 0x49, 0xE3, 0xAF, 0x1F, - 0xC6, 0xA5, 0x79, 0xFE, 0xAE, 0xA1, 0xCA, 0x59, 0x3C, 0xEE, 0xC1, 0x02, 0xBD, 0x2B, 0x8E, 0xC5, - 0x7D, 0x38, 0x80, 0x8F, 0x72, 0xF3, 0x86, 0x5D, 0xF4, 0x20, 0x0A, 0x5B, 0xA0, 0xE3, 0x85, 0xB5, - 0x67, 0x43, 0x96, 0xBB, 0x75, 0x86, 0x8D, 0x7E, 0x7E, 0xE6, 0xAA, 0x18, 0x57, 0xC4, 0xAA, 0x87, - 0xDC, 0x74, 0x05, 0xAA, 0xBD, 0x5E, 0x4F, 0xA9, 0xB5, 0x5E, 0xC5, 0xE8, 0x11, 0x6D, 0x68, 0x89, - 0x17, 0x7C, 0x10, 0x05, 0xA2, 0xBA, 0x43, 0x01, 0xD6, 0xFD, 0x26, 0x19, 0x57, 0xFA, 0x4D, 0x01, - 0xB0, 0xED, 0x3A, 0x55, 0xEB, 0x65, 0x8E, 0xD1, 0x58, 0x27, 0xAD, 0xA1, 0x5E, 0x57, 0x3F, 0xA0, - 0xEF, 0x59, 0x3E, 0xA4, 0xEB, 0x12, 0x15, 0x60, 0xBE, 0x95, 0x61, 0x0B, 0x98, 0xF5, 0xF4, 0x12, - 0x1C, 0xD8, 0x62, 0x3F, 0xFD, 0xCF, 0x01, 0x3A, 0xE7, 0xC2, 0x19, 0x38, 0x6C, 0xC3, 0x90, 0x3E, - }; - - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - return (byte)(value ^ KeyTable[offset & 0xFF]); - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - for (int i = 0; i < count; ++i) - { - values[pos+i] ^= KeyTable[(offset+i) & 0xFF]; - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - Decrypt (entry, offset, values, pos, count); - } - } - - [Serializable] - public class NatsupochiCrypt : ICrypt - { - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - return (byte)(value ^ (entry.Hash >> 3)); - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - byte key = (byte)(entry.Hash >> 3); - for (int i = 0; i < count; ++i) - { - values[pos+i] ^= key; - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - Decrypt (entry, offset, values, pos, count); - } - } - - [Serializable] - public class IncubusCrypt : ICrypt - { - public override byte Decrypt (Xp3Entry entry, long offset, byte value) - { - return (byte)~(value ^ (entry.Hash + 1)); - } - - public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - byte key = (byte)~(entry.Hash + 1); - for (int i = 0; i < count; ++i) - { - values[pos+i] ^= key; - } - } - - public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) - { - Decrypt (entry, offset, values, pos, count); - } - } } diff --git a/ArcFormats/KiriKiri/CryptAlgorithms.cs b/ArcFormats/KiriKiri/CryptAlgorithms.cs new file mode 100644 index 00000000..c84089fd --- /dev/null +++ b/ArcFormats/KiriKiri/CryptAlgorithms.cs @@ -0,0 +1,530 @@ +//! \file CryptAlgorithms.cs +//! \date Thu Feb 04 12:08:40 2016 +//! \brief KiriKiri engine encryption algorithms. +// +// Copyright (C) 2016 by morkt +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System; + +namespace GameRes.Formats.KiriKiri +{ + [Serializable] + public abstract class ICrypt + { + /// + /// whether Adler32 checksum should be calculated after contents have been encrypted. + /// + public virtual bool HashAfterCrypt { get { return false; } } + + /// + /// whether XP3 index is obfuscated: + /// - duplicate entries + /// - entries have additional dummy segments + /// + public virtual bool ObfuscatedIndex { get { return false; } } + + public virtual byte Decrypt (Xp3Entry entry, long offset, byte value) + { + byte[] buffer = new byte[1] { value }; + Decrypt (entry, offset, buffer, 0, 1); + return buffer[0]; + } + + public abstract void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count); + + public virtual void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + throw new NotImplementedException (Strings.arcStrings.MsgEncNotImplemented); + } + } + + [Serializable] + public class NoCrypt : ICrypt + { + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + return value; + } + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + return; + } + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + return; + } + } + + [Serializable] + public class FateCrypt : ICrypt + { + public override bool HashAfterCrypt { get { return true; } } + + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + byte result = (byte)(value ^ 0x36); + if (0x13 == offset) + result ^= 1; + else if (0x2ea29 == offset) + result ^= 3; + return result; + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + for (int i = 0; i < count; ++i) + { + values[pos+i] ^= 0x36; + } + if (offset > 0x2ea29) + return; + if (offset + count > 0x2ea29) + values[pos+0x2ea29-offset] ^= 3; + if (offset > 0x13) + return; + if (offset + count > 0x13) + values[pos+0x13-offset] ^= 1; + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + Decrypt (entry, offset, values, pos, count); + } + } + + [Serializable] + public class HashCrypt : ICrypt + { + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + return (byte)(value ^ entry.Hash); + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + byte key = (byte)entry.Hash; + for (int i = 0; i < count; ++i) + { + values[pos+i] ^= key; + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + Decrypt (entry, offset, values, pos, count); + } + } + + [Serializable] + public class XorCrypt : ICrypt + { + private byte m_key; + + public byte Key + { + get { return m_key; } + set { m_key = value; } + } + + public XorCrypt (uint key) + { + m_key = (byte)key; + } + + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + return (byte)(value ^ m_key); + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + for (int i = 0; i < count; ++i) + { + values[pos+i] ^= m_key; + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + Decrypt (entry, offset, values, pos, count); + } + } + + [Serializable] + public class SwanSongCrypt : ICrypt + { + static private byte Adjust (uint hash, out int shift) + { + int cl = (int)(hash & 0xff); + if (0 == cl) cl = 0x0f; + shift = cl & 7; + int ch = (int)((hash >> 8) & 0xff); + if (0 == ch) ch = 0xf0; + return (byte)ch; + } + + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + int shift; + byte xor = Adjust (entry.Hash, out shift); + uint data = (uint)(value ^ xor); + return (byte)((data >> shift) | (data << (8 - shift))); + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + int shift; + byte xor = Adjust (entry.Hash, out shift); + for (int i = 0; i < count; ++i) + { + uint data = (uint)(values[pos+i] ^ xor); + values[pos+i] = (byte)((data >> shift) | (data << (8 - shift))); + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + int shift; + byte xor = Adjust (entry.Hash, out shift); + for (int i = 0; i < count; ++i) + { + uint data = values[pos+i]; + data = (byte)((data << shift) | (data >> (8 - shift))); + values[pos+i] = (byte)(data ^ xor); + } + } + } + + [Serializable] + public class SeitenCrypt : ICrypt + { + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + uint key = entry.Hash ^ (uint)offset; + if (0 != (key & 2)) + { + int ecx = (int)key & 0x18; + value ^= (byte)((key >> ecx) | (key >> (ecx & 8))); + } + if (0 != (key & 4)) + { + value += (byte)key; + } + if (0 != (key & 8)) + { + value -= (byte)(key >> (int)(key & 0x10)); + } + return value; + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] buffer, int pos, int count) + { + for (int i = 0; i < count; ++i) + { + int shift; + uint key = entry.Hash ^ (uint)offset; + byte v = buffer[pos+i]; + if (0 != (key & 2)) + { + shift = (int)key & 0x18; + uint ebx = key >> shift; + shift &= 8; + v ^= (byte)(ebx | (key >> shift)); + } + if (0 != (key & 4)) + { + v += (byte)key; + } + if (0 != (key & 8)) + { + shift = (int)key & 0x10; + v -= (byte)(key >> shift); + } + buffer[pos+i] = v; + ++offset; + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + for (int i = 0; i < count; ++i) + { + uint key = entry.Hash ^ (uint)offset; + if (0 != (key & 8)) + { + values[pos+i] += (byte)(key >> (int)(key & 0x10)); + } + if (0 != (key & 4)) + { + values[pos+i] -= (byte)key; + } + if (0 != (key & 2)) + { + int ecx = (int)key & 0x18; + values[pos+i] ^= (byte)((key >> ecx) | (key >> (ecx & 8))); + } + } + } + } + + [Serializable] + public class OkibaCrypt : ICrypt + { + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + if (offset < 0x65) + return (byte)(value ^ (byte)(entry.Hash >> 4)); + uint key = entry.Hash; + // 0,1,2,3 -> 1,0,3,2 + key = ((key & 0xff0000) << 8) | ((key & 0xff000000) >> 8) + | ((key & 0xff00) >> 8) | ((key & 0xff) << 8); + key >>= 8 * ((int)(offset - 0x65) & 3); + return (byte)(value ^ (byte)key); + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + int i = 0; + if (offset < 0x65) + { + uint key = entry.Hash >> 4; + int limit = Math.Min (count, (int)(0x65 - offset)); + for (; i < limit; ++i) + { + values[pos+i] ^= (byte)key; + ++offset; + } + } + if (i < count) + { + offset -= 0x65; + uint key = entry.Hash; + key = ((key & 0xff0000) << 8) | ((key & 0xff000000) >> 8) + | ((key & 0xff00) >> 8) | ((key & 0xff) << 8); + do + { + values[pos+i] ^= (byte)(key >> (8 * ((int)offset & 3))); + ++offset; + } + while (++i < count); + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + Decrypt (entry, offset, values, pos, count); + } + } + + [Serializable] + public class SaiminCrypt : ICrypt + { + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + byte key = (byte)entry.Hash; + if (offset < 0x7B) + value ^= (byte)(21 * key); + else if (offset < 0xF6) + value += (byte)(-32 * key); + else if (offset < 0x171) + value ^= (byte)(43 * key); + else if (offset <= 0xffffffffL) + value += (byte)(-54 * key); + return value; + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + byte key = (byte)entry.Hash; + for (int i = 0; i < count && offset <= 0xffffffffL; ++i, ++offset) + { + if (offset < 0x7B) + values[pos+i] ^= (byte)(21 * key); + else if (offset < 0xF6) + values[pos+i] += (byte)(-32 * key); + else if (offset >= 0x171) + values[pos+i] += (byte)(-54 * key); + else + values[pos+i] ^= (byte)(43 * key); + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + byte key = (byte)entry.Hash; + for (int i = 0; i < count && offset <= 0xffffffffL; ++i, ++offset) + { + if (offset < 0x7B) + values[pos+i] ^= (byte)(21 * key); + else if (offset < 0xF6) + values[pos+i] -= (byte)(-32 * key); + else if (offset >= 0x171) + values[pos+i] -= (byte)(-54 * key); + else + values[pos+i] ^= (byte)(43 * key); + } + } + } + + [Serializable] + public class DameganeCrypt : ICrypt + { + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + if (0 != (offset & 1)) + return (byte)(value ^ entry.Hash); + else + return (byte)(value ^ offset); + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + for (int i = 0; i < count; ++i, ++offset) + { + if (0 != (offset & 1)) + values[pos+i] ^= (byte)entry.Hash; + else + values[pos+i] ^= (byte)offset; + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + Decrypt (entry, offset, values, pos, count); + } + } + + [Serializable] + public class GakuenButouCrypt : ICrypt + { + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + if (0 != (offset & 1)) + return (byte)(value ^ offset); + else + return (byte)(value ^ entry.Hash); + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + for (int i = 0; i < count; ++i, ++offset) + { + if (0 != (offset & 1)) + values[pos+i] ^= (byte)offset; + else + values[pos+i] ^= (byte)entry.Hash; + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + Decrypt (entry, offset, values, pos, count); + } + } + + [Serializable] + public class AlteredPinkCrypt : ICrypt + { + static readonly byte[] KeyTable = { + 0x43, 0xF8, 0xAD, 0x08, 0xDF, 0xB7, 0x26, 0x44, 0xF0, 0xD9, 0xE9, 0x24, 0x1A, 0xC1, 0xEE, 0xB4, + 0x11, 0x4B, 0xE4, 0xAF, 0x01, 0x5B, 0xF0, 0xAB, 0x6A, 0x70, 0x78, 0x84, 0xB0, 0x78, 0x4F, 0xED, + 0x39, 0x52, 0x69, 0xAF, 0xC4, 0x92, 0x2A, 0x21, 0xDE, 0xDC, 0x6E, 0x63, 0x9D, 0x9B, 0x63, 0xE1, + 0xB1, 0x94, 0x40, 0x6E, 0x3A, 0x52, 0x5A, 0x28, 0x08, 0x4D, 0xFB, 0x22, 0x18, 0xEB, 0xBA, 0x98, + 0x49, 0x77, 0xBF, 0xAA, 0x43, 0x75, 0xF5, 0xD3, 0x83, 0x71, 0x58, 0xA4, 0xAF, 0x1B, 0x53, 0x99, + 0x8A, 0x27, 0x5B, 0xC2, 0x7F, 0x7A, 0xCD, 0x8D, 0x33, 0x59, 0xEB, 0xA6, 0xFA, 0x7C, 0x00, 0x19, + 0xC4, 0xAA, 0x24, 0xF8, 0x84, 0xCD, 0xF7, 0x20, 0x4B, 0xAB, 0xF1, 0xD5, 0x01, 0x6F, 0x7C, 0x91, + 0x08, 0x7D, 0x8D, 0x89, 0x7C, 0x71, 0x65, 0x99, 0x9B, 0x6F, 0x3A, 0x1C, 0x49, 0xE3, 0xAF, 0x1F, + 0xC6, 0xA5, 0x79, 0xFE, 0xAE, 0xA1, 0xCA, 0x59, 0x3C, 0xEE, 0xC1, 0x02, 0xBD, 0x2B, 0x8E, 0xC5, + 0x7D, 0x38, 0x80, 0x8F, 0x72, 0xF3, 0x86, 0x5D, 0xF4, 0x20, 0x0A, 0x5B, 0xA0, 0xE3, 0x85, 0xB5, + 0x67, 0x43, 0x96, 0xBB, 0x75, 0x86, 0x8D, 0x7E, 0x7E, 0xE6, 0xAA, 0x18, 0x57, 0xC4, 0xAA, 0x87, + 0xDC, 0x74, 0x05, 0xAA, 0xBD, 0x5E, 0x4F, 0xA9, 0xB5, 0x5E, 0xC5, 0xE8, 0x11, 0x6D, 0x68, 0x89, + 0x17, 0x7C, 0x10, 0x05, 0xA2, 0xBA, 0x43, 0x01, 0xD6, 0xFD, 0x26, 0x19, 0x57, 0xFA, 0x4D, 0x01, + 0xB0, 0xED, 0x3A, 0x55, 0xEB, 0x65, 0x8E, 0xD1, 0x58, 0x27, 0xAD, 0xA1, 0x5E, 0x57, 0x3F, 0xA0, + 0xEF, 0x59, 0x3E, 0xA4, 0xEB, 0x12, 0x15, 0x60, 0xBE, 0x95, 0x61, 0x0B, 0x98, 0xF5, 0xF4, 0x12, + 0x1C, 0xD8, 0x62, 0x3F, 0xFD, 0xCF, 0x01, 0x3A, 0xE7, 0xC2, 0x19, 0x38, 0x6C, 0xC3, 0x90, 0x3E, + }; + + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + return (byte)(value ^ KeyTable[offset & 0xFF]); + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + for (int i = 0; i < count; ++i) + { + values[pos+i] ^= KeyTable[(offset+i) & 0xFF]; + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + Decrypt (entry, offset, values, pos, count); + } + } + + [Serializable] + public class NatsupochiCrypt : ICrypt + { + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + return (byte)(value ^ (entry.Hash >> 3)); + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + byte key = (byte)(entry.Hash >> 3); + for (int i = 0; i < count; ++i) + { + values[pos+i] ^= key; + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + Decrypt (entry, offset, values, pos, count); + } + } + + [Serializable] + public class IncubusCrypt : ICrypt + { + public override byte Decrypt (Xp3Entry entry, long offset, byte value) + { + return (byte)~(value ^ (entry.Hash + 1)); + } + + public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + byte key = (byte)~(entry.Hash + 1); + for (int i = 0; i < count; ++i) + { + values[pos+i] ^= key; + } + } + + public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count) + { + Decrypt (entry, offset, values, pos, count); + } + } +}