Advertisement
Guest User

Resonance of Fate

a guest
Oct 31st, 2015
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. "
  2. Security:
  3. -> Custom Encryption
  4. -> Custom Checksum
  5.  
  6. Additional:
  7. Below you can see the SaveData class, which de/encrypts the main layers. It includes all the important functions and informations regarding the security. This code is not compileable, since some trivial structs and classes are missing.
  8.  
  9. This class does not show how to edit credits and other stuff, because this would go beyond the scope of a security archive.
  10. "
  11.  
  12. public class SaveData {
  13.     private byte[] data;
  14.  
  15.     private uint[] mainSalts, customSalts;
  16.     private uint block0Salt, block1Salt;
  17.  
  18.     private MasterIO xIO;
  19.     private Random random;
  20.     private Header header;
  21.  
  22.     public SaveData(byte[] data, bool raw = false) {
  23.         if (data == null)
  24.             throw new ArgumentNullException("data", "RoF.SaveData: The reference to the save data is null!");
  25.  
  26.         this.data = data;
  27.         this.random = new Random(data.GetHashCode());
  28.  
  29.         Initialize(raw); // raw = decrypted data for research purpose.
  30.     }
  31.  
  32.     private void Initialize(bool raw) {
  33.         xIO = new MasterIO(data, Endian.Big);
  34.  
  35.         GetHeader();
  36.         GetNReadSalts();
  37.  
  38.         if (!raw)
  39.             DecSections();
  40.  
  41.         GetSubSalts();
  42.  
  43.         if (!raw)
  44.             DecSubSections();
  45.     }
  46.  
  47.     private void GetHeader() {
  48.         header.Mode = (Mode) xIO.Reader.ReadInt32();
  49.         header.Version = xIO.Reader.ReadInt32();
  50.         header.FileSize = xIO.Reader.ReadInt32();
  51.         header.MainSize = xIO.Reader.ReadInt32();
  52.  
  53.         if (!header.IsValid())
  54.             throw new Exception("RoF.SaveData: Header data is invalid!");
  55.     }
  56.  
  57.     private void GetNReadSalts() {
  58.         switch (header.Mode) {
  59.             case Mode.RFIR:
  60.                 mainSalts = new uint[] { 0x1A7D154A, 0xBC35769B, 0xC41C5A4D,
  61.                     0x9139A8CF, 0x67569371, 0xA388D36A, 0x242BFAB6 };
  62.                 break;
  63.             case Mode.RFSD:
  64.                 mainSalts = new uint[] { 0xCF7AF41A, 0x22E3CC23, 0xDA6AF8DF,
  65.                     0xA904FBB9, 0x6EF2B76E, 0xC2C9F8E7, 0x1695DE99 };
  66.                 break;
  67.             default:
  68.                 throw new Exception("RoF.SaveData: Save mode is not supported!");
  69.         }
  70.  
  71.         customSalts = new uint[7];
  72.         for (int i = 0; i < customSalts.Length; ++i)
  73.             customSalts[i] = xIO.Reader.ReadUInt32();
  74.     }
  75.  
  76.     private void DecSections() {
  77.         DecSection(0x70, 64, 0, 1);
  78.         DecSection(0xB0, header.MainSize, 2, 3);
  79.  
  80.         xIO.Offset = 76;
  81.         if (!xIO.Reader.ReadBytes(36).Compare(CalculateHash()))
  82.             throw new Exception("RoF.SaveData: Save data is corrupt!");
  83.     }
  84.  
  85.     private void GetSubSalts() {
  86.         xIO.Offset = 0xC7C;
  87.         block0Salt = xIO.Reader.ReadUInt32();
  88.  
  89.         xIO.Offset = 0x39CA8;
  90.         block1Salt = xIO.Reader.ReadUInt32();
  91.     }
  92.  
  93.     private void DecSubSections() {
  94.         CryptBlock0(0x128, 0x100);
  95.         CryptBlock1(0x1C90, 0x38000);
  96.     }
  97.  
  98.     private void DecSection(int offset, int size, uint salt1, uint salt2) {
  99.         uint next, t;
  100.         salt1 = customSalts[salt1] ^ mainSalts[salt1];
  101.         salt2 = customSalts[salt2] ^ mainSalts[salt2];
  102.  
  103.         xIO.Offset = offset;
  104.         if ((size & 2) == 0) {
  105.             next = (salt1 + 3 * salt2 + 0x1B5F5) ^ 0xF5D6A9BA;
  106.             for (int i = 0; i < (size >> 1); ++i) {
  107.                 next = (next * 0x425F5) + 0x195C3;
  108.                 t = (next >> 14) ^ xIO.Reader.ReadUInt16();
  109.                 xIO.Offset -= 2;
  110.                 xIO.Writer.WriteUInt16((ushort) t);
  111.             }
  112.         }
  113.  
  114.         for (int i = offset; i < (offset + size); ++i) {
  115.             salt2 = (salt2 * 0x1CDED5) + 0x4C829;
  116.             data[i] ^= (byte) (salt2 >> 19);
  117.         }
  118.  
  119.         next = ((salt1 >> 1) & 0x7F) + 0xE;
  120.         for (int i = offset; i < (offset + size); ++i) {
  121.             salt1 = (salt1 * 0x16AB5) + 0x44BB1;
  122.             data[i] ^= (byte) ((salt1 >> 13) ^ next);
  123.             next = data[i] ^ 0x6B;
  124.         }
  125.     }
  126.  
  127.     private void EncData() {
  128.         CryptBlock0(0x128, 0x100);
  129.         CryptBlock1(0x1C90, 0x38000);
  130.  
  131.         xIO.Offset = 76;
  132.         xIO.Writer.WriteBytes(CalculateHash());
  133.  
  134.         EncSection(0x70, 64, 0, 1);
  135.         EncSection(0xB0, header.MainSize, 2, 3);
  136.     }
  137.  
  138.     private void EncSection(int offset, int size, uint salt1, uint salt2) {
  139.         uint r5, r9, next;
  140.         salt1 = customSalts[salt1] ^ mainSalts[salt1];
  141.         salt2 = customSalts[salt2] ^ mainSalts[salt2];
  142.  
  143.         next = salt1;
  144.  
  145.         r9 = ((salt1 >> 1) & 0x7F) + 0xE;
  146.         for (int i = offset; i < (offset + size); ++i) {
  147.             next = (next * 0x16AB5) + 0x44BB1;
  148.             r5 = (next >> 13) ^ r9 ^ data[i];
  149.             r9 = (uint) (data[i] ^ 0x6B);
  150.             data[i] = (byte) r5;
  151.         }
  152.  
  153.         next = salt2;
  154.         for (int i = offset; i < (offset + size); ++i) {
  155.             next = (next * 0x1CDED5) + 0x4C829;
  156.             data[i] ^= (byte) (next >> 19);
  157.         }
  158.  
  159.         xIO.Offset = offset;
  160.         if ((size % 2) == 0) {
  161.             next = (3 * salt2 + salt1 + 0x1B5F5) ^ 0xF5D6A9BA;
  162.             for (int i = 0; i < (size >> 1); ++i) {
  163.                 next = (next * 0x425F5) + 0x195C3;
  164.                 salt2 = xIO.Reader.ReadUInt16();
  165.                 xIO.Offset -= 2;
  166.                 xIO.Writer.WriteUInt16((ushort) ((next >> 14) ^ salt2));
  167.             }
  168.         }
  169.     }
  170.  
  171.     private byte[] CalculateHash() {
  172.         byte[] hash = new byte[36];
  173.         Buffer.BlockCopy(CalculateHashPart(0, 64, 4), 0, hash, 0, 12);
  174.         Buffer.BlockCopy(CalculateHashPart(0x70, 64, 5), 0, hash, 12, 12);
  175.         Buffer.BlockCopy(CalculateHashPart(0xB0, header.MainSize, 6), 0, hash, 24, 12);
  176.         return hash;
  177.     }
  178.  
  179.     private byte[] CalculateHashPart(int offset, int size, int salt) {
  180.         byte[] hash = new byte[12];
  181.         int sum1, sum2, sum3;
  182.  
  183.         salt = (int) (customSalts[salt] ^ mainSalts[salt]);
  184.  
  185.         sum1 = salt ^ 0x4DBBBA99;
  186.         for (int i = offset; i < (offset + size); ++i)
  187.             sum1 += ((i - offset) % 2 == 0) ? data[i] : 3 * data[i];
  188.  
  189.         sum2 = sum1 + 0xDAE;
  190.         for (int i = offset; i < (offset + size); ++i)
  191.             sum2 = (sum2 * 0x1C12B) + data[i] + 0x2335F7;
  192.  
  193.         sum3 = -1;
  194.         for (int i = offset; i < (offset + size); ++i) {
  195.             sum3 ^= data[i] << 24;
  196.             for (int j = 0; j < 8; ++j)
  197.                 sum3 = (sum3 >= 0) ? (sum3 << 1) : (sum3 << 1) ^ salt;
  198.         }
  199.  
  200.         using (var xIO = new MasterIO(hash, Endian.Big)) {
  201.             xIO.Writer.WriteInt32(sum1 ^ 0x220F57E3);
  202.             xIO.Writer.WriteInt32(sum2 ^ ~0x7400E28);
  203.             xIO.Writer.WriteInt32(sum3 ^ 0x68A4DC10);
  204.             return hash;
  205.         }
  206.     }
  207.  
  208.     private void CryptBlock0(int offset, int size) {
  209.         uint next = block0Salt;
  210.         for (int i = offset; i < (offset + size); ++i) {
  211.             next = (next * 0xE33BB) + 0x41897;
  212.             data[i] ^= (byte) (next >> 20);
  213.         }
  214.     }
  215.  
  216.     private void CryptBlock1(int offset, int size) {
  217.         uint next = block1Salt;
  218.         for (int i = offset; i < (offset + size); ++i) {
  219.             next = (next * 0x386B67) + 0xED051E;
  220.             data[i] ^= (byte) (next >> 17);
  221.         }
  222.     }
  223.  
  224.     public byte[] Write() {
  225.         xIO.Offset = 16;
  226.         for (int i = 0; i < customSalts.Length; ++i)
  227.             xIO.Writer.WriteUInt32(customSalts[i] ^= (uint) random.Next(-2147483648, 2147483647));
  228.  
  229.         EncData();
  230.         byte[] res = (byte[]) data.Clone();
  231.  
  232.         DecSections();
  233.         DecSubSections();
  234.  
  235.         return res;
  236.  
  237.     }
  238.  
  239.     public void Close() {
  240.         xIO.Close();
  241.     }
  242.  
  243. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement