Skip to content

Instantly share code, notes, and snippets.

@Bloodwyn
Last active January 6, 2023 21:03
Show Gist options
  • Save Bloodwyn/ff8fd940f064fd321757468b47c5a5ba to your computer and use it in GitHub Desktop.
Save Bloodwyn/ff8fd940f064fd321757468b47c5a5ba to your computer and use it in GitHub Desktop.
/*
Implementaion of the md5 hashing algorithm in sqf
en.wikipedia.org/wiki/md5
community.bistudio.com/wiki/SQF_syntax
Author: Bastian Kuth | "Bloodwyn"
Its rather slow (about 120ms per GUID), but can be used to convert the SteamID64 to the BattleEye GUID without having to use external tools or addons.
developer.valvesoftware.com/wiki/SteamID
The main challenge developing this was the lack of an Integer datatype in sqf.
I used this C implementaion from Tim Caswell as a reference: gist.github.com/creationix/4710780
*/
BW_hash_fnc_calloc = {
private _ret = [];
_ret set [_this-1,0];
_ret apply {0};
};
BW_hash_fnc_memcpy = {
params ["_dst", "_src", "_len"];
for "_i" from 0 to (_len-1) step 1 do {
_dst set [_i,_src # _i];
};
_dst;
};
BW_hash_fnc_shiftr = {
params [
["_a",0,[0]],
["_c",0,[0]]
];
floor (_a / (2 ^ _c));
};
BW_hash_fnc_shiftl = {
params [
["_a",0,[0]],
["_c",0,[0]]
];
(_a * (2 ^ _c)) mod 256;
};
BW_hash_fnc_shiftr32 = {
params [
["_a",[],[[]],4],
["_c",0,[0]]
];
_a = +_a;
private ["_r","_a0","_a1","_a2","_a3","_maskForOverflow"];
while {_c>8} do {
_c = _c-8;
_a deleteAt 3;
_a = [0] + _a;
};
_maskForOverflow = 2^_c-1;
_a0 = [_a#0,_c] call BW_hash_fnc_shiftr;
_r = [[_a#0,_maskForOverflow] call BIS_fnc_bitwiseAND, 8-_c] call BW_hash_fnc_shiftl;
_a1 = [[_a#1,_c] call BW_hash_fnc_shiftr,_r] call BIS_fnc_bitwiseOR;
_r = [[_a#1,_maskForOverflow] call BIS_fnc_bitwiseAND, 8-_c] call BW_hash_fnc_shiftl;
_a2 = [[_a#2,_c] call BW_hash_fnc_shiftr,_r] call BIS_fnc_bitwiseOR;
_r = [[_a#2,_maskForOverflow] call BIS_fnc_bitwiseAND, 8-_c] call BW_hash_fnc_shiftl;
_a3 = [[_a#3,_c] call BW_hash_fnc_shiftr,_r] call BIS_fnc_bitwiseOR;
[_a0,_a1,_a2,_a3];
};
BW_hash_fnc_shiftl32 = {
params [
["_a",[],[[]],4],
["_c",0,[0]]
];
_a = +_a;
private ["_r","_a0","_a1","_a2","_a3","_maskForOverflow"];
while {_c>8} do {
_c = _c-8;
_a deleteAt 0;
_a pushBack 0;
};
_maskForOverflow = [[2^(8-_c)-1] call BIS_fnc_bitwiseNOT,0xFF] call BIS_fnc_bitwiseAND;
_a3 = [_a#3,_c] call BW_hash_fnc_shiftl;
_r = [[_a#3,_maskForOverflow] call BIS_fnc_bitwiseAND, 8-_c] call BW_hash_fnc_shiftr;
_a2 = [[_a#2,_c] call BW_hash_fnc_shiftl,_r] call BIS_fnc_bitwiseOR;
_r = [[_a#2,_maskForOverflow] call BIS_fnc_bitwiseAND, 8-_c] call BW_hash_fnc_shiftr;
_a1 = [[_a#1,_c] call BW_hash_fnc_shiftl,_r] call BIS_fnc_bitwiseOR;
_r = [[_a#1,_maskForOverflow] call BIS_fnc_bitwiseAND, 8-_c] call BW_hash_fnc_shiftr;
_a0 = [[_a#0,_c] call BW_hash_fnc_shiftl,_r] call BIS_fnc_bitwiseOR;
[_a0 mod 256,_a1 mod 256,_a2 mod 256,_a3 mod 256];
};
BW_hash_fnc_and32 = {
params [
["_a",[],[[]],4],
["_b",[],[[]],4]
];
[
[_a#0,_b#0] call BIS_fnc_bitwiseAND,
[_a#1,_b#1] call BIS_fnc_bitwiseAND,
[_a#2,_b#2] call BIS_fnc_bitwiseAND,
[_a#3,_b#3] call BIS_fnc_bitwiseAND
];
};
BW_hash_fnc_or32 = {
params [
["_a",[],[[]],4],
["_b",[],[[]],4]
];
[
[_a#0,_b#0] call BIS_fnc_bitwiseOR,
[_a#1,_b#1] call BIS_fnc_bitwiseOR,
[_a#2,_b#2] call BIS_fnc_bitwiseOR,
[_a#3,_b#3] call BIS_fnc_bitwiseOR
];
};
BW_hash_fnc_xor32 = {
params [
["_a",[],[[]],4],
["_b",[],[[]],4]
];
[
([_a#0,_b#0] call BIS_fnc_bitwiseXOR) mod 256,
([_a#1,_b#1] call BIS_fnc_bitwiseXOR) mod 256,
([_a#2,_b#2] call BIS_fnc_bitwiseXOR) mod 256,
([_a#3,_b#3] call BIS_fnc_bitwiseXOR) mod 256
];
};
BW_hash_fnc_not32 = {
private _a = _this;
[
((_a#0) call BIS_fnc_bitwiseNOT) mod 256,
((_a#1) call BIS_fnc_bitwiseNOT) mod 256,
((_a#2) call BIS_fnc_bitwiseNOT) mod 256,
((_a#3) call BIS_fnc_bitwiseNOT) mod 256
];
};
BW_hash_fnc_add32 = {
params [
["_a",[],[[]],4],
["_b",[],[[]],4]
];
private ["_v1","_v2","_v3","_v4","_o"];
_v1 = (_a#3)+(_b#3);
_o = floor (_v1 / 256);
_v2 = (_a#2)+(_b#2)+_o;
_o = floor (_v2 / 256);
_v3 = (_a#1)+(_b#1)+_o;
_o = floor (_v3 / 256);
_v4 = (_a#0)+(_b#0)+_o;
_o = floor (_v3 / 256);
[_v4 mod 256,_v3 mod 256,_v2 mod 256,_v1 mod 256];
};
BW_hash_fnc_decStrMod = {
private _str = param [0,"",[""]];
private ["_r","_e"];
_e = "";
_parsed = parseNumber _str;
if(count _str < 3 or (_parsed < 256))exitWith{
[str (floor (_parsed / 256)),_parsed % 256];
};
_part = parseNumber (_str select [0,3]);
for "_i" from 3 to ((count _str)) step 1 do {
_r = _part % 256;
_e = _e + str floor (_part / 256);
_part = _r*10 + parseNumber (_str select [_i,1]);
};
[_e,_r];
};
BW_hash_fnc_fromDecStr = {
private _str = param [0,"",[""]];
_bytes = [];
while{!(_str isEqualTo "0")} do {
_ret = _str call BW_hash_fnc_decStrMod;
_str = _ret#0;
_bytes = [_ret#1] + _bytes;
};
_bytes;
};
BW_hash_fnc_fromHexStr = {
private ["_str","_num","_flag","_tn0","_tn1"];
_str = toLower _this;
if(_str select [0,2] isEqualTo "0x")then{_str = _str select [2,1e6]};
if((count _str) mod 2 isEqualTo 1)then{_str = "0"+_str};
_num = [];
_flag = true;
(toArray _str) apply {
if(_flag)then{
_flag = false;
_tn0 = if(_x >= 96)then{_x-87}else{_x-48};
}else{
_tn1 = if(_x >= 96)then{_x-87}else{_x-48};
_num pushBack (([_tn0,4] call BW_hash_fnc_shiftl) + _tn1);
_flag = true;
};
};
if(!_flag)then{
_num pushBack([_tn0,4] call BW_hash_fnc_shiftl);
};
_num;
};
BW_hash_fnc_toHexStr = {
if(typeName _this isEqualTo "ARRAY")exitWith{
_str = "";
_this apply {_str = _str + (_x call BW_hash_fnc_toHexStr)};
_str;
};
_lkup = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];
(_lkup # (floor (_this / 16))) + (_lkup # (_this mod 16));
};
BW_hash_fnc_toNum = {
_num = 0;
_this apply {_num = _num*256 + _x};
_num;
};
BW_hash_fnc_hashToString = {
_ui32ar = _this;
_str = "";
_ui32ar apply {
_bytes = _x;
_istr = "";
_bytes apply {
_istr = (_x call BW_hash_fnc_toHexStr) + _istr;
};
_str = _str + _istr;
};
_str
};
BW_hash_fnc_md5 = {
private ["_r","_k","_ho","_h1","_h2","_h3","_initial_msg","_initial_len","_new_len","_msg","_bits_len","_a","_b","_c","_d","_f","_g","_temp","_shift","_toshift","_selfrom"];
_r = [ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21];
_k = [
[0xd7,0x6a,0xa4,0x78], [0xe8,0xc7,0xb7,0x56], [0x24,0x20,0x70,0xdb], [0xc1,0xbd,0xce,0xee],
[0xf5,0x7c,0x0f,0xaf], [0x47,0x87,0xc6,0x2a], [0xa8,0x30,0x46,0x13], [0xfd,0x46,0x95,0x01],
[0x69,0x80,0x98,0xd8], [0x8b,0x44,0xf7,0xaf], [0xff,0xff,0x5b,0xb1], [0x89,0x5c,0xd7,0xbe],
[0x6b,0x90,0x11,0x22], [0xfd,0x98,0x71,0x93], [0xa6,0x79,0x43,0x8e], [0x49,0xb4,0x08,0x21],
[0xf6,0x1e,0x25,0x62], [0xc0,0x40,0xb3,0x40], [0x26,0x5e,0x5a,0x51], [0xe9,0xb6,0xc7,0xaa],
[0xd6,0x2f,0x10,0x5d], [0x02,0x44,0x14,0x53], [0xd8,0xa1,0xe6,0x81], [0xe7,0xd3,0xfb,0xc8],
[0x21,0xe1,0xcd,0xe6], [0xc3,0x37,0x07,0xd6], [0xf4,0xd5,0x0d,0x87], [0x45,0x5a,0x14,0xed],
[0xa9,0xe3,0xe9,0x05], [0xfc,0xef,0xa3,0xf8], [0x67,0x6f,0x02,0xd9], [0x8d,0x2a,0x4c,0x8a],
[0xff,0xfa,0x39,0x42], [0x87,0x71,0xf6,0x81], [0x6d,0x9d,0x61,0x22], [0xfd,0xe5,0x38,0x0c],
[0xa4,0xbe,0xea,0x44], [0x4b,0xde,0xcf,0xa9], [0xf6,0xbb,0x4b,0x60], [0xbe,0xbf,0xbc,0x70],
[0x28,0x9b,0x7e,0xc6], [0xea,0xa1,0x27,0xfa], [0xd4,0xef,0x30,0x85], [0x04,0x88,0x1d,0x05],
[0xd9,0xd4,0xd0,0x39], [0xe6,0xdb,0x99,0xe5], [0x1f,0xa2,0x7c,0xf8], [0xc4,0xac,0x56,0x65],
[0xf4,0x29,0x22,0x44], [0x43,0x2a,0xff,0x97], [0xab,0x94,0x23,0xa7], [0xfc,0x93,0xa0,0x39],
[0x65,0x5b,0x59,0xc3], [0x8f,0x0c,0xcc,0x92], [0xff,0xef,0xf4,0x7d], [0x85,0x84,0x5d,0xd1],
[0x6f,0xa8,0x7e,0x4f], [0xfe,0x2c,0xe6,0xe0], [0xa3,0x01,0x43,0x14], [0x4e,0x08,0x11,0xa1],
[0xf7,0x53,0x7e,0x82], [0xbd,0x3a,0xf2,0x35], [0x2a,0xd7,0xd2,0xbb], [0xeb,0x86,0xd3,0x91]
];
_h0 = [0x67,0x45,0x23,0x01];
_h1 = [0xef,0xcd,0xab,0x89];
_h2 = [0x98,0xba,0xdc,0xfe];
_h3 = [0x10,0x32,0x54,0x76];
_initial_msg = _this;
if(typeName _this isEqualTo "STRING")then{
_initial_msg = (toArray _initial_msg);
};
_initial_len = (count _initial_msg);
_new_len = ((floor ((_initial_len + 8) / 64) + 1) * 64) - 8;
_msg = (_new_len + 64) call BW_hash_fnc_calloc;
_msg = [_msg, _initial_msg, _initial_len] call BW_hash_fnc_memcpy;
_msg set [_initial_len,128];
_bits_len = 8 * _initial_len;
_msg set [_new_len+3 ,floor (_bits_len / (2^24)) mod 256];
_msg set [_new_len+2,floor (_bits_len / (2^16)) mod 256];
_msg set [_new_len+1,floor (_bits_len / (2^8)) mod 256];
_msg set [_new_len+0,floor (_bits_len) mod 256];
for "_offset" from 0 to (_new_len-1) step (512 / 8) do {
_a = _h0;
_b = _h1;
_c = _h2;
_d = _h3;
for "_i" from 0 to (64-1) step 1 do {
switch (true) do {
case (_i < 16) : {
_f = [
[_b,_c] call BW_hash_fnc_and32,
[_b call BW_hash_fnc_not32,_d] call BW_hash_fnc_and32
] call BW_hash_fnc_or32;
_g = [0,0,0,_i];
};
case (_i < 32) : {
_f = [
[_d,_b] call BW_hash_fnc_and32,
[_d call BW_hash_fnc_not32,_c] call BW_hash_fnc_and32
] call BW_hash_fnc_or32;
_g = [0,0,0,(5 * _i + 1) % 16];
};
case (_i < 48) : {
_f = [[_b,_c] call BW_hash_fnc_xor32,_d] call BW_hash_fnc_xor32;
_g = [0,0,0,(3 * _i + 5) % 16];
};
default {
_f = [_c,[_b,_d call BW_hash_fnc_not32] call BW_hash_fnc_or32] call BW_hash_fnc_xor32;
_g = [0,0,0,(7 * _i) % 16];
};
};
_temp = _d;
_d = _c;
_c = _b;
_shift = _r#_i;
_selfrom = _offset + ((_g call BW_hash_fnc_toNum)*4);
_toshift = [[[_a, _f] call BW_hash_fnc_add32,_k#_i] call BW_hash_fnc_add32,[_msg # (_selfrom+3), _msg # (_selfrom+2), _msg # (_selfrom+1), _msg # _selfrom]] call BW_hash_fnc_add32;
_b = [_b,[[_toshift,_shift] call BW_hash_fnc_shiftl32,[_toshift,32 - _shift] call BW_hash_fnc_shiftr32] call BW_hash_fnc_or32] call BW_hash_fnc_add32;
_a = _temp;
};
_h0 = [_h0,_a] call BW_hash_fnc_add32;
_h1 = [_h1,_b] call BW_hash_fnc_add32;
_h2 = [_h2,_c] call BW_hash_fnc_add32;
_h3 = [_h3,_d] call BW_hash_fnc_add32;
};
[_h0,_h1,_h2,_h3] call BW_hash_fnc_hashToString;
};
BW_hash_fnc_steamIdToGUID = {
private _steamid = param [0, "",[""]];
private _bytes = _steamid call BW_hash_fnc_fromDecStr;
reverse _bytes;
_tohash = (toArray "BE") + _bytes;
((toArray "BE") + _bytes) call BW_hash_fnc_md5;
};
["76561198055205907"] call BW_hash_fnc_steamidToGUID; // returns "861211889e6b3e4c3a584c5d42cb4825"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment