XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > StarCraft (только чтение)> StarCraft 2 inside
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

FULL DESCRIPTION HERE: xgm.ru/p/sc2/scencrypt

 
ScorpioT1000
Работаем
offline
Опыт: отключен
[galaxy] ScEncrypt v0.01
Библиотека шифрования на основе xor-алгоритма с закрытым ключом готова :)
((кат old text

Зачем это нужно?

Насколько мне известно, данные банков без подписи в Starcraft II не шифруются и доступны для изменения. Единственный выход - шифровка данных, наподобие save/load системы: xgm.ru/p/wc3/creating_loading_code
Отдельная благодарность NETRAT'у за помощь с алгоритмами.
Кроме этого, есть ещё очень много применений ScEncrypt, даже для той же генерации сейвлоад (загрузочных) кодов, да для чего угодно, где нужно "запаролить данные и засунуть их в строку", включая обратную операцию.

Как это использовать?

Сначала вам нужно каким-либо образом сделать так, чтобы код библиотеки ScEncryptLibrary оказался внутри кода карты. Например, так: xgm.ru/forum/showthread.php?t=35589 (т.е. просто копируем его в свободную область)
Библиотека содержит три пользовательские функции:
//==== Encrypt portion of data:
string scEncryptString(string source, string key)


//==== Decrypt portion of data:
string scDecryptString(string coded, string key)

//==== On Initialize event:
bool scEncryptInit()
Последнюю надо запустить из триггера инициализации карты.
Первая функцияscEncryptString(string source, string key) – принимает:
  • исходную строку. Это может быть любая строка, туда можно записать уровни, ресурсы, статы и прочие параметры вашей игры, которые надо зашифровать. Главное - чтобы ваш алгоритм знал, как их укомплектовать в string и достать оттуда в обратном порядке.
  • секретный ключ. Вот тут всё посложнее. Был бы это Warcraft 3, мы бы смогли просто использовать имя пользователя + ещё какие-либо данные, чтобы ключ стал уникальным, но в SC2 такой возможности нам не предоставили. Я думаю, что в вашей карте вы должны предложить игроку "залогиниться", т.е. ввести его постоянный пароль. После этого мы каким-то образом преобразовываем наш виртуальный пароль (допустим, у нас ещё имеется "имя текущей игры") и генерируем секретный ключ, с помощью которого потом можно будет расшифровать данные.
Функция возвращает код из символов алфавита scEncryptAlphabet, который уже можно будет заталкивать в банк или показывать пользователю на запись (открытый ключ). Код этот в (4/3)+3 раза больше входных данных, т.к. алфавит ascii больше алфавита кода :)
Вторая функцияscDecryptString(string coded, string key) – принимает:
  • кодированную строку. Это тот самый код, который вернула scEncryptString, называемый открытым ключом.
  • секретный ключ. Ключ, описанный выше. Он-то нам и нужен для расшифровки.
Функция возвращает ваши расшифрованные данные.
При ошибках ввода, вывода, переполнениях и т.п. вызывается функция scassert (в подбиблиотеке ScDebug) и устанавливается флаг scisassert на значение 1, а в scassertnotes записана причина ассерта.
Далее вы уже можете проверять, какой игрок сфейлил свой код, т.е. по очереди для игроков вызывать шифрование/дешифрование и после ввода проверять флаг, затем устанавливать на 0 для следующего игрока.

Ограничения

  • длина входных данных по умолчанию - от 4 до 4096 символов
  • длина ключа по умолчанию - от 2 до 4096 символов
  • входные данные могут быть записаны только в ASCII (я не думаю, что кому-то вдруг надо будет шифровать сообщения пользователей или Войну и Мир)
  • однопоточность
  • не рекомендуется использовать оба символа - 0 "zero" и O "ou" - в scEncryptAlphabet, если вы хотите показывать код игроку на экране, т.к. эти символы в шрифте SC2 абсолютно одинаковые

Исходный код

Смотреть "User Functions" внизу.
ScEncryptLibrary:

//==================================================================================================​======
// ScEncryptLibrary
// (c) ScorpioT1000 2010
//==================================================================================================​======


//====================================================
// name: ScMath
// author: ScorpioT1000
// note: my libs uses it
//====================================================

int ceil(fixed f) {
    int x = FixedToInt(f);
    if(f > IntToFixed(x)) { return x+1; }
    return x;
}

// little endian, from 0
int int2byte0(int source) { return (source & 0xFF); }
int int2byte(int source, int index) { return ((source >> (index*8)) &  0xFF); }
int int2short0(int source) { return (source & 0x0000FFFF); }
int int2short1(int source) { return (source  << 8); }

//====================================================
// name: ScString
// author: ScorpioT1000
// note: '\n' and '\r' chars don't work
//====================================================
const string scASCIITable="\x1\x2\x3\x4\x5\x6\x7\x8\x9\x1\xB\x1\xD\xE\xF\x10\x11\x12\x13\x14\x15\x16\x17\x18​\x19\x1A\x1B\x1C\x1D\x1E\x1F\x20!\x22#$%&'()*+,-./0123456789:;\x3C=\x3E?@ABCDEFGHIJKLMNOPQRSTUVW​XYZ[\x5C]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7F"; 

// conversion
int string2char(string s) {
    return (StringFind(scASCIITable,s,true));
}
string char2string(int ch) {
    if(ch==0) { return "\x0"; }
    return StringSub(scASCIITable,ch,ch);
}

// add one char to the tail
string stringAddChar(string s, int ch) {
    return s+char2string(ch);
}

// get/set one char in specific position (from 0)
int stringGetChar(string s, int position) {
    return string2char(StringSub(s,position+1,position+1));
}
int stringGetCharPos(string s, string ch) {
    return (StringFind(s,ch,true)-1);
}
string stringSetChar(string s, int position, int ch) {
    int len = StringLength(s);
    position = position + 1; //from 0
    if(len <= 1) { return char2string(ch); }
    if(position == 1) {
        return char2string(ch)+StringSub(s,2,len);
    } else if(position >= (len-1)) {
        return StringSub(s,1,(len-2))+char2string(ch);
    }
    return StringSub(s,1,position-1)+char2string(ch)+StringSub(s,position+1,(len-1));
}

string substr(string src, int start, int end) { return StringSub(src,start+1,end+1); }
string strchar(string src, int index) { return StringSub(src,index+1,index+1); }

//====================================================
// name: ScDebug
// author: ScorpioT1000
// note: my libs uses it
//====================================================

bool scDebugEnable = true;

void scdebug(string msg) {
    UIDisplayMessage(PlayerGroupAll(),c_messageAreaDebug,StringToText("[debug] "+msg));
}

void scassertmsg(string msg) {
    UIDisplayMessage(PlayerGroupAll(),c_messageAreaDebug,StringToText("[assert] "+msg));
}

int sc__isassert=0;
string sc__assertnotes="";
void scassert(bool cond, string notes) {
    if((! cond) && scDebugEnable) {
        scassertmsg("\""+notes+"\" - assertion failed!");
        sc__isassert=1;
        sc__assertnotes = notes;
        TriggerStop(TriggerGetCurrent());
    }
}

//====================================================
// name: ScEncrypt v0.01
// author: ScorpioT1000
// special thanks: NETRAT
// source: www.xgm.ru
// note: it's not recommended to use both "zero"(0) and "ou"(O) symbols in the alphabet
//====================================================

const int scEncryptMaxDataSize = 4096;
const int scEncryptMinDataSize = 4;
const string scEncryptAlphabet = "$#@123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; // 64 !

int sce_a; int sce_b; int sce_c; int sce_w; int sce_x; int sce_y; int sce_z;

//====================================================
//===== Private Functions ============================
//====================================================

//===== data coding

// code 3 8-bit-int (a,b,c) to 4 6-bit-int (w,x,y,z)
void sceCodeData(int a, int b, int c) {
    sce_w = a >> 2;
    sce_x = ((a & 3)<<4) | (b>>4);
    sce_y = ((b & 15)<<2) | (c>>6);
    sce_z = c & 63;
}

// code 4 6-bit-int (w,x,y,z) to 3 8-bit-int (a,b,c)
void sceDecodeData(int w, int x, int y, int z) {
    sce_a = (w<<2) | (x>>4);
    sce_b = ((x & 15)<<4) | (y>>2);
    sce_c = ((y & 3)<<6) | z;
}

//
int [scEncryptMaxDataSize] sce__DataBuffer0;
int sce__DataBuffer0Size =0;
bool sce__inited0 =false;

void sce__DataBufferClear() {
    int i=0;
    while(i < scEncryptMaxDataSize) {
        sce__DataBuffer0[i]=0;
        i=i+1;
    }
}


string sce__CodeS() {
    string s;
    int i=0;
    // integer math, check 4 chars in 2 bytes
    scassert(sce__DataBuffer0Size == ((sce__DataBuffer0Size/3)*3), "sce__CodeS: wrong size");
    while(i < sce__DataBuffer0Size) {
        sceCodeData(sce__DataBuffer0[i],sce__DataBuffer0[i+1],sce__DataBuffer0[i+2]);
        s = s + strchar(scEncryptAlphabet,sce_w);
        s = s + strchar(scEncryptAlphabet,sce_x);
        s = s + strchar(scEncryptAlphabet,sce_y);
        s = s + strchar(scEncryptAlphabet,sce_z);
        i = i+3;
    }
    return s;
}
void sce__DecodeS(string coded) {
    int len = StringLength(coded);
    int i=0;
    int j=0;
    len = (len/4)*4; // integer math, check 3 bytes in 4 chars
    sce__DataBuffer0Size = ceil(len * 0.75); // 3/4
    scassert(sce__DataBuffer0Size > scEncryptMinDataSize, "sce__DecodeS: buffer size is too small");
    scassert(sce__DataBuffer0Size < (scEncryptMaxDataSize+scEncryptMinDataSize), "sce__DecodeS: buffer overflow");
    while(i<len) {
        sce_w = stringGetCharPos(scEncryptAlphabet,strchar(coded,i));
        sce_x = stringGetCharPos(scEncryptAlphabet,strchar(coded,i+1));
        sce_y = stringGetCharPos(scEncryptAlphabet,strchar(coded,i+2));
        sce_z = stringGetCharPos(scEncryptAlphabet,strchar(coded,i+3));
        sceDecodeData(sce_w,sce_x,sce_y,sce_z);
        sce__DataBuffer0[j] = sce_a;
        sce__DataBuffer0[j+1] = sce_b;
        sce__DataBuffer0[j+2] = sce_c;
        j=j+3;
        i=i+4;
    }
}

//===== encryption

string sce__EncryptS(string src, string key) {
    string rk;
    string result;
    int N = StringLength(src);
    int Nk = StringLength(key);
    int i=0;
    int j=0;
    scassert(N < (scEncryptMaxDataSize+scEncryptMinDataSize), "sce__EncryptS: input overflow");
    if(N > Nk) { // rep. key
        while(i < N) {
            if(j >= Nk) {
                j=0;
            }
            rk = rk + strchar(key,j);
            j=j+1;
            i=i+1;
        }
    } else {
        rk = substr(key,0,N-1);
    }
    sce__DataBuffer0[1] = int2byte0(N) ^ string2char(strchar(rk,0)); // c1 = N0 xor rk0
    sce__DataBuffer0[0] = int2byte(N,1) ^ sce__DataBuffer0[1]; // c0 = N1 xor c1
    i=0;
    while(i<N) { // encrypt
        sce__DataBuffer0[i+2] = (string2char(strchar(src,i)) ^ (string2char(strchar(rk,i)) ^ i));
        i=i+1;
    }
    sce__DataBuffer0Size = (i+2);
    j = ((sce__DataBuffer0Size/3) *3);
    if(j != sce__DataBuffer0Size) { sce__DataBuffer0Size = sce__DataBuffer0Size + (j+3-sce__DataBuffer0Size); }
    result = sce__CodeS();
    sce__DataBufferClear();
    return result;
}

string sce__DecryptS(string coded, string key) {
    string result;
    string rk;
    int N =0; // size
    int i=0;
    int j=0;
    int Nk = StringLength(key);
    sce__DecodeS(coded); // decode
    N = (sce__DataBuffer0[1] ^ string2char(strchar(key,0))); // d1 = c1 xor rk0
    N = (((sce__DataBuffer0[0] ^ sce__DataBuffer0[1])<<8) | N); // d0 = c0 xor d1
    scassert(N >= (sce__DataBuffer0Size-scEncryptMinDataSize), "sce__DecryptS: wrong size(-)");
    scassert(N < sce__DataBuffer0Size, "sce__DecryptS: wrong size(+)");
    if(N > Nk) { // rep. key 
        while(i < N) {
            if(j >= Nk) {
                j=0;
            }
            rk = rk + strchar(key,j);
            j=j+1;
            i=i+1;
        }
    } else {
        rk = substr(key,0,N-1);
    }
    i=0;
    while(i < N) { // decrypt
        result = result + char2string(sce__DataBuffer0[i+2] ^ (string2char(strchar(rk,i)) ^ i));
        i=i+1;
    }
    sce__DataBufferClear();
    return result;
}

bool sce__Init0() {
    sce__inited0 = true;
    sce__DataBufferClear();
    return true;
}



//====================================================
//===== User Functions ===============================
// Encrypt and decrypt any data in string by private key.
// note: it's not recommended to use some identical symbols successively
// source size:     from (scEncryptMinDataSize) to (scEncryptMaxDataSize)
// key size:        from 2 to (scEncryptMaxDataSize)
//====================================================

// Encrypt portion of data
string scEncryptString(string source, string key) { return sce__EncryptS(source,key); }

// Decrypt portion of data
string scDecryptString(string coded, string key) { return sce__DecryptS(coded,key); }

// Initialize encryption system
bool scEncryptInit() { return sce__Init0(); }

//====================================================
//====================================================

void scInit() {
    scEncryptInit();
}

А что если взломают?

Особенность системы xor-шифрования в разделении исходных данных на конечный код и секретный ключ. Получаются "две половинки", по которым можно восстановить данные. Если взломщик не будет иметь ключ, то восстановить данные этой системой будет трудно даже полностью зная весь её алгоритм.
Для большей надёжности я бы посоветовал следующее:
  • не заполняйте данные идущими подряд нулями или одинаковыми символами, чтобы не рассекретить ключ
  • используйте как можно большую длину ключа (например, введите ограничение на ключ от 6 символов)

English Description

((кат ScEncrypt in english
Introduction
As far as I know, the data of Starcraft II banks isn't encrypted, therefore they are accessible for modifying. The only solution is to encrypt data like save/load systems. Special thanks to NETRAT for helping with algorithms.
How to use it?
First include the ScEncryptLibrary source to the map code. For example, so xgm.ru/forum/attachment.php?attachmentid=65696
The library contains three user functions:
==== Encrypt portion of data:
string scEncryptString(string source, string key)
==== Decrypt portion of data:
string scDecryptString(string coded, string key)
==== On Initialize event:
bool scEncryptInit()
The last one should be launched from the initialization trigger.
The first function – scEncryptString(string source, string key) – takes:
the source string. It can be any string, where it is possible to write down any levels, resources, stats and other parameters of your game which should be encrypted. It's important to ensure, that your algorithm is properly serializing data and also getting it back in reverse order.
the secret key. There are some complexities. We'd simply used <user name> + <any data> to make the unique key in WC3, but there's no such possibility in SC2. I think that you should offer the player to "log in" in your map, i.e. enter his permanent password. After that we somehow transform our virtual password (say, we still have a "name of the current game") and generate the secret key, which is used later do data decryption.
Function returns the code from scEncryptAlphabet characters which can be pushed in bank or shown to the user (public key). Remember, the O 'ou' and 0 'zero' characters in SC2 font are absolutely identical.
The second function – scDecryptString(string source, string key) – takes:
the coded string. It is the code returned by scEncryptString, named public key.
the secret key, described above.
Function returns your decrypted data.
Function scassert is called on I/O errors, overflows, etc., where scisassert == 1 and scassertnotes == reason
Restrictions
source size: from (scEncryptMinDataSize =4) to (scEncryptMaxDataSize=4096)
key size: from 2 to (scEncryptMaxDataSize=4096)
input data can be written only in ASCII
single-threading
Note: it's not recommended to use some identical symbols successively, it reduces privacy of the key
Give me some examples!
Examples and source files are in the attachment.
))

))
Прикрепленные файлы
Тип файла: rar ScEncrypt v0_01.rar (26.8 Кбайт, 44 просмотров )

Отредактировано ScorpioT1000, 15.03.2012 в 20:37.
Старый 04.12.2010, 03:32
Ark

offline
Опыт: 21,182
Активность:
круто) но до кромарти не дотягивает =).
Старый 04.12.2010, 03:38
ScorpioT1000
Работаем
offline
Опыт: отключен
Обновил идею секретного ключа:
Я думаю, что в вашей карте вы должны предложить игроку "залогиниться", т.е. ввести его постоянный пароль. После этого мы каким-то образом преобразовываем наш виртуальный пароль (допустим, у нас ещё имеется "имя текущей игры") и генерируем секретный ключ, с помощью которого потом можно будет расшифровать данные.
Старый 04.12.2010, 13:35
DioD

offline
Опыт: 45,134
Активность:
хочу отметить что офцально объявлено о том, что цифровая подпись банка будет доступна в 120 версии на уровне нативок.
уже сейчас северная америка может логинится на публик тест риалм, остальные по традиции сосут леденцы.
Старый 04.12.2010, 15:32
ScorpioT1000
Работаем
offline
Опыт: отключен
пруф или звездолёт )
Старый 04.12.2010, 15:59
DioD

offline
Опыт: 45,134
Активность:
Старый 04.12.2010, 16:03
ScorpioT1000
Работаем
offline
Опыт: отключен
ок, правда так как-то смутно всё, да и юзер же сможет изменить её, не так ли?)
Старый 04.12.2010, 16:14
DioD

offline
Опыт: 45,134
Активность:
если изменить фаил банка то цифровая подпись отваливается, только хз как это будет реализовано, так как у всех должна быть возможность писать в банк и проверять целостность банка, возможно сам сервер батлы будет проверять целостность банков или банки будут храниться где-то в другом месте.
Старый 04.12.2010, 16:36
Toadcop

offline
Опыт: 54,313
Активность:
на сервере баттлы банки от пива должны хранится m-| чё непонятного то... (вообще не понятно поему изначяльно не так.) на аккаунт вешаются банки и всё...
Старый 04.12.2010, 17:04
ScorpioT1000
Работаем
offline
Опыт: отключен
вобще неясно тогда зачем они локалдату делали :) типа кеша из вар3 ?
Старый 04.12.2010, 17:13
Toadcop

offline
Опыт: 54,313
Активность:
это то норм для сингла а вот для мульта надо на баттле хранить вестимо (учитывая что ихния хрень хостит игры) короче клиника. у них было не мало "неправильных решений" это одно из них офк. через года 3 думаю ск2 будет играбельный сейчас пока всё "бета"... (да я тоадкэп -.-)
Старый 04.12.2010, 17:29
ScorpioT1000
Работаем
offline
Опыт: отключен
Старый 04.12.2010, 18:01
DioD

offline
Опыт: 45,134
Активность:
у буржуев подобная тема была кстати, они дефлейт алгоритм от зип архивов реализовали.
Старый 04.12.2010, 18:05
ScorpioT1000
Работаем
offline
Опыт: отключен
ты так говоришь - буржуи, будто есть только "россия" и "буржуи" ) явно там не целым стадом они собрались и разработали)
Старый 04.12.2010, 18:08
KorvinGump

offline
Опыт: 3,634
Активность:
Хочу сказать спасибо за либу. Использовал её в своей последней карте Grass TD в связке с UserTypes. Получилось очень даже неплохо. Все остальные либы по шифрованию у меня работали с багами. Не знаю с чем это было связано, либо ошибки в либах, либо шифровал неправильно, но разбираться в исходном коде по шифрованию - это убийство кучи времени. Твоя либа, даже спустя 3.5 года после релиза до сих пор работает отлично. Респект за это:).
Старый 23.03.2014, 21:23
ScorpioT1000
Работаем
offline
Опыт: отключен
^_^ хоть кому-то пригодилась)
Старый 25.03.2014, 22:02

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 12:00.