Exemplo n.º 1
0
 public static string FixXmlHash(string str, uint target_hash)
 {
     str  = Utils.StripBOM(str);
     str  = Utils.NormalizeLineEndings(str);
     str += $"\n{XML_MARKER}\n<!-- Fix hash: ";
     str += new CBDataHasher(str).CalculatePreimage(target_hash, " -->\n");
     return(str);
 }
Exemplo n.º 2
0
        /// <summary>
        /// Finds a string that when appended to another string with the current hash, will have a final
        /// hash equal to targetHash.
        ///
        /// Hence, to bring the hash of a string to any value, do:
        ///
        /// str += new CBDataHasher(str).CalculatePreimage(targetHash, " whatever text ");
        /// </summary>
        /// <param name="targetHash">The target hash value.</param>
        /// <param name="tail">An optional suffix that the output string must end with.</param>
        /// <returns>The string to append.</returns>
        public string CalculatePreimage(uint targetHash, string tail = "")
        {
            // The effect of appending n characters to a string with this hash algorithm is effectively:
            //
            // hash(str + chars) = hash(str) * 33^n.Length + hash(chars) mod 2^32
            //
            // We calculate the hash value `chars` would need to have to set the hash to `targetHash`,
            // assuming it is 5 characters.
            //
            // In this way, we can use an algorithm that only needs to bring 0 to a certain hash value,
            // and not any value to any value.
            CBDataHasher target = new CBDataHasher(targetHash);

            target.UpdateReverse(tail);            // account for the tail
            target.State -= this.State * 39135393; // 33^5

            // We calculate the string in reverse, effectively trying to bring the value of target down
            // to zero. The calculation in reverse is:
            //
            // hash(c + str) = (hash(str) - c) * 33^1 mod 2^32
            //
            // As long as 33 evenly divides (hash(str) - c), the modular division will behave as ordinary
            // division. As this value will always decrease, it eventually reaches zero, at which point
            // we can just output null characters until we have 5 characters.
            var outStr = "";

            for (int i = 0; i < 5; i++)
            {
                var tint = target.State;
                // Avoid generating surrogate pairs or BOMs (The CLR does weird things to it)
                var next = (tint >= 0xD800 && tint <= 0xDFFF) || tint == 0xFEFF ? 0x752D + (tint % 33) :
                           tint <= 0xFFFF ? tint : 0xFFC0 + (tint % 33);
                var next_ch = (char)next;

                outStr = next_ch + outStr;
                target.UpdateReverse(next_ch);
            }
            Trace.Assert(target.State == 0, "CalculatePreimage failed.");
            return(outStr + tail);
        }