Created
May 15, 2019 01:11
-
-
Save RodGreen/403fbd4cf7c2076b10149fc135da988b to your computer and use it in GitHub Desktop.
FileIDUtil + MD4 for Unity AssetIDs in DLLs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//https://forum.unity.com/threads/yaml-fileid-hash-function-for-dll-scripts.252075/#post-1695479 | |
using System; | |
using System.Linq; | |
using System.Collections.Generic; | |
using System.Security.Cryptography; | |
// Taken from http://www.superstarcoders.com/blogs/posts/md4-hash-algorithm-in-c-sharp.aspx | |
// Probably not the best implementation of MD4, but it works. | |
public class MD4 : HashAlgorithm | |
{ | |
private uint _a; | |
private uint _b; | |
private uint _c; | |
private uint _d; | |
private uint[] _x; | |
private int _bytesProcessed; | |
public MD4() | |
{ | |
_x = new uint[16]; | |
Initialize(); | |
} | |
public override void Initialize() | |
{ | |
_a = 0x67452301; | |
_b = 0xefcdab89; | |
_c = 0x98badcfe; | |
_d = 0x10325476; | |
_bytesProcessed = 0; | |
} | |
protected override void HashCore(byte[] array, int offset, int length) | |
{ | |
ProcessMessage(Bytes(array, offset, length)); | |
} | |
protected override byte[] HashFinal() | |
{ | |
try | |
{ | |
ProcessMessage(Padding()); | |
return new [] {_a, _b, _c, _d}.SelectMany(word => Bytes(word)).ToArray(); | |
} | |
finally | |
{ | |
Initialize(); | |
} | |
} | |
private void ProcessMessage(IEnumerable<byte> bytes) | |
{ | |
foreach (byte b in bytes) | |
{ | |
int c = _bytesProcessed & 63; | |
int i = c >> 2; | |
int s = (c & 3) << 3; | |
_x[i] = (_x[i] & ~((uint)255 << s)) | ((uint)b << s); | |
if (c == 63) | |
{ | |
Process16WordBlock(); | |
} | |
_bytesProcessed++; | |
} | |
} | |
private static IEnumerable<byte> Bytes(byte[] bytes, int offset, int length) | |
{ | |
for (int i = offset; i < length; i++) | |
{ | |
yield return bytes[i]; | |
} | |
} | |
private IEnumerable<byte> Bytes(uint word) | |
{ | |
yield return (byte)(word & 255); | |
yield return (byte)((word >> 8) & 255); | |
yield return (byte)((word >> 16) & 255); | |
yield return (byte)((word >> 24) & 255); | |
} | |
private IEnumerable<byte> Repeat(byte value, int count) | |
{ | |
for (int i = 0; i < count; i++) | |
{ | |
yield return value; | |
} | |
} | |
private IEnumerable<byte> Padding() | |
{ | |
return Repeat(128, 1) | |
.Concat(Repeat(0, ((_bytesProcessed + 8) & 0x7fffffc0) + 55 - _bytesProcessed)) | |
.Concat(Bytes((uint)_bytesProcessed << 3)) | |
.Concat(Repeat(0, 4)); | |
} | |
private void Process16WordBlock() | |
{ | |
uint aa = _a; | |
uint bb = _b; | |
uint cc = _c; | |
uint dd = _d; | |
foreach (int k in new [] { 0, 4, 8, 12 }) | |
{ | |
aa = Round1Operation(aa, bb, cc, dd, _x[k], 3); | |
dd = Round1Operation(dd, aa, bb, cc, _x[k + 1], 7); | |
cc = Round1Operation(cc, dd, aa, bb, _x[k + 2], 11); | |
bb = Round1Operation(bb, cc, dd, aa, _x[k + 3], 19); | |
} | |
foreach (int k in new [] { 0, 1, 2, 3 }) | |
{ | |
aa = Round2Operation(aa, bb, cc, dd, _x[k], 3); | |
dd = Round2Operation(dd, aa, bb, cc, _x[k + 4], 5); | |
cc = Round2Operation(cc, dd, aa, bb, _x[k + 8], 9); | |
bb = Round2Operation(bb, cc, dd, aa, _x[k + 12], 13); | |
} | |
foreach (int k in new [] { 0, 2, 1, 3 }) | |
{ | |
aa = Round3Operation(aa, bb, cc, dd, _x[k], 3); | |
dd = Round3Operation(dd, aa, bb, cc, _x[k + 8], 9); | |
cc = Round3Operation(cc, dd, aa, bb, _x[k + 4], 11); | |
bb = Round3Operation(bb, cc, dd, aa, _x[k + 12], 15); | |
} | |
unchecked | |
{ | |
_a += aa; | |
_b += bb; | |
_c += cc; | |
_d += dd; | |
} | |
} | |
private static uint ROL(uint value, int numberOfBits) | |
{ | |
return (value << numberOfBits) | (value >> (32 - numberOfBits)); | |
} | |
private static uint Round1Operation(uint a, uint b, uint c, uint d, uint xk, int s) | |
{ | |
unchecked | |
{ | |
return ROL(a + ((b & c) | (~b & d)) + xk, s); | |
} | |
} | |
private static uint Round2Operation(uint a, uint b, uint c, uint d, uint xk, int s) | |
{ | |
unchecked | |
{ | |
return ROL(a + ((b & c) | (b & d) | (c & d)) + xk + 0x5a827999, s); | |
} | |
} | |
private static uint Round3Operation(uint a, uint b, uint c, uint d, uint xk, int s) | |
{ | |
unchecked | |
{ | |
return ROL(a + (b ^ c ^ d) + xk + 0x6ed9eba1, s); | |
} | |
} | |
} | |
public static class FileIDUtil | |
{ | |
public static int Compute(Type t) | |
{ | |
string toBeHashed = "s\0\0\0" + t.Namespace + t.Name; | |
using (HashAlgorithm hash = new MD4()) | |
{ | |
byte[] hashed = hash.ComputeHash(System.Text.Encoding.UTF8.GetBytes(toBeHashed)); | |
int result = 0; | |
for(int i = 3; i >= 0; --i) | |
{ | |
result <<= 8; | |
result |= hashed[i]; | |
} | |
return result; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment