adding authentification to khanagat [Send login & password with crypted method]

This commit is contained in:
AleaJactaEst 2019-12-02 23:34:04 +01:00
parent 5c4b468da8
commit 06430e84ff
22 changed files with 1107 additions and 45 deletions

View file

@ -0,0 +1,49 @@
# Build
Before build and launch client, we need build godot-cpp (lib to connect c++ code to godot engine) and build crypt (c++ module use to authentification with khaganat)
## Build godot-cpp
### Initialize
Load git submodule (godot-cpp & godot_header)
```
git submodule update --init --recursive
```
### Build on 64bits
```
godot --gdnative-generate-json-api godot-cpp/godot_headers/api.json
scons -C godot-cpp platform=linux generate_bindings=yes custom_api_file=godot_headers/api.json bits=64
```
### Build on 32bits
```
godot --gdnative-generate-json-api godot-cpp/godot_headers/api.json
scons -C godot-cpp platform=linux generate_bindings=yes custom_api_file=godot_headers/api.json bits=32
```
## Build crypt
### Build on 64bits
```
scons -C crypt platform=linux bits=64
```
### Build on 32bits
```
scons -C crypt platform=linux bits=32
```
## Build client khaganat
TODO
## Launch client khaganat
TODO

6
TODO Normal file
View file

@ -0,0 +1,6 @@
* Create a global scons configuration to launch all build
* Build project with godot command line (perhaps with scons)
* Disable login button when we have launch a login (or show other dialog with message wait [buton cancel if we want abort login])
* Execute next step - UDP module to communicate with khaganat
* Configuration panel to define all connexion parameter
* Path : check version and patch all file (we need generate path file for godot and method to reload data)

View file

@ -19,12 +19,12 @@ class connexion:
var _url_login = ""
var _url_register = ""
var _valid_certificate = true
func _init():
print("Load connexion config");
#var message = load("res://assets/Scripts/Models/nel_login_message.gd")
var config_file = ConfigFile.new()
# /home/<account>/.local/share/godot/app_userdata/Khanat/connexion.cfg
var err = config_file.load("user://connexion.cfg")
if err:
@ -33,7 +33,7 @@ class connexion:
config_file.set_value("register", "url", "http://149.91.80.160/ams/index.php?page=register")
config_file.set_value("global", "valid_certificate", false)
config_file.save("user://connexion.cfg")
self._url_login = config_file.get_value( "login", "url", "http://172.17.0.3/login/r2_login.php")
self._url_register = config_file.get_value( "register", "url", "http://172.17.0.3/login/r2_login.php")
self._valid_certificate = config_file.get_value( "global", "valid_certificate", false)
@ -41,9 +41,9 @@ class connexion:
func get_url_login():
return self._url_login
func get_url_register():
return self._url_register
func get_valid_certificate():
return self._valid_certificate

View file

@ -14,12 +14,34 @@ class nel_login_message:
self._cp = cp;
self._lg = lg;
func get_request_string():
var request_string = "cmd=" + self._cmd;
func crypt_password(salt):
var ret = ""
var crypt = preload("res://crypt.gdns").new()
var crypted = crypt.encrypt(self._password, salt)
#print("[nel_login_message] crypted:" + str(crypted))
ret = self._password + " <-> " + salt + " <-> " + crypted + " <->"
#print("[nel_login_message] ret:" + str(ret))
return crypted
func get_request_salt():
# cmd = self.url + "?cmd=ask&cp=2&login=" + self.login + "&lg=" + self.LanguageCode
var request_string = "cmd=ask"
if self._cp != "":
request_string += "&cp=" + self._cp;
if self._login != "":
request_string += "&login=" + self._login;
if self._lg != "":
request_string += "&lg=" + self._lg;
return request_string;
func get_request_string(salt):
var request_string = "cmd=login"
if self._login != "":
request_string += "&login=" + self._login;
if self._password != "":
request_string += "&password=" + self._password;
request_string += "&password=" + self.crypt_password(salt);
if self._clientApplication != "":
request_string += "&clientApplication=" + self._clientApplication;
if self._cp != "":

View file

@ -16,7 +16,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class url_encoding:
func _init():
pass

16
crypt.gdnlib Normal file
View file

@ -0,0 +1,16 @@
[general]
singleton=false
load_once=true
symbol_prefix="godot_"
reloadable=true
[entry]
X11.64="res://crypt/bin/libgodot-cpp.linux.debug.64.so"
X11.32="res://crypt/bin/libgodot-cpp.linux.debug.32.so"
[dependencies]
X11.64=[ ]
X11.32=[ ]

8
crypt.gdns Normal file
View file

@ -0,0 +1,8 @@
[gd_resource type="NativeScript" load_steps=2 format=2]
[ext_resource path="res://crypt.gdnlib" type="GDNativeLibrary" id=1]
[resource]
class_name = "GDCrypt"
library = ExtResource( 1 )

2
crypt/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
bin/
.sconsign.dblite

150
crypt/SConstruct Normal file
View file

@ -0,0 +1,150 @@
#!python
import os, subprocess, platform, sys
# Local dependency paths, adapt them to your setup
godot_headers_path = "../godot-cpp/godot_headers/"
cpp_bindings_path = "../godot-cpp/"
cpp_library = "godot-cpp"
if not os.path.exists( 'bin' ):
os.mkdir( 'bin' )
def add_sources(sources, dir, extension):
for f in os.listdir(dir):
if f.endswith('.' + extension):
sources.append(dir + '/' + f)
# Try to detect the host platform automatically
# This is used if no `platform` argument is passed
if sys.platform.startswith('linux'):
host_platform = 'linux'
elif sys.platform == 'darwin':
host_platform = 'osx'
elif sys.platform == 'win32':
host_platform = 'windows'
else:
raise ValueError('Could not detect platform automatically, please specify with platform=<platform>')
opts = Variables([], ARGUMENTS)
opts.Add(EnumVariable('platform', 'Target platform', host_platform,
allowed_values=('linux', 'osx', 'windows'),
ignorecase=2))
opts.Add(EnumVariable('bits', 'Target platform bits', 'default', ('default', '32', '64')))
opts.Add(BoolVariable('use_llvm', 'Use the LLVM compiler - only effective when targeting Linux', False))
opts.Add(BoolVariable('use_mingw', 'Use the MinGW compiler - only effective on Windows', False))
# Must be the same setting as used for cpp_bindings
opts.Add(EnumVariable('target', 'Compilation target', 'debug',
allowed_values=('debug', 'release'),
ignorecase=2))
opts.Add(PathVariable('headers_dir', 'Path to the directory containing Godot headers', godot_headers_path, PathVariable.PathIsDir))
opts.Add(PathVariable('target_path', 'The path where the lib is installed.', 'bin'))
opts.Add(PathVariable('target_name', 'The library name.', 'libgdcrypt', PathVariable.PathAccept))
unknown = opts.UnknownVariables()
if unknown:
print("Unknown variables:" + unknown.keys())
Exit(1)
env = Environment()
opts.Update(env)
Help(opts.GenerateHelpText(env))
# sys.stderr.write("**** %s\n" % (cpp_library))
# This makes sure to keep the session environment variables on Windows
# This way, you can run SCons in a Visual Studio 2017 prompt and it will find all the required tools
if env['platform'] == 'windows':
if env['bits'] == '64':
env = Environment(TARGET_ARCH='amd64')
elif env['bits'] == '32':
env = Environment(TARGET_ARCH='x86')
else:
print("Warning: bits argument not specified, target arch is=" + env['TARGET_ARCH'])
opts.Update(env)
is64 = False
if (env['platform'] == 'osx' or env['TARGET_ARCH'] == 'amd64' or env['TARGET_ARCH'] == 'emt64' or env['TARGET_ARCH'] == 'x86_64'):
is64 = True
if env['bits'] == 'default':
env['bits'] = '64' if is64 else '32'
if env['platform'] == 'linux':
if env['use_llvm']:
env['CXX'] = 'clang++'
env.Append(CCFLAGS=['-fPIC', '-g', '-std=c++14', '-Wwrite-strings'])
env.Append(LINKFLAGS=["-Wl,-R,'$$ORIGIN'"])
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
if env['bits'] == '64':
env.Append(CCFLAGS=['-m64'])
env.Append(LINKFLAGS=['-m64'])
elif env['bits'] == '32':
env.Append(CCFLAGS=['-m32'])
env.Append(LINKFLAGS=['-m32'])
elif env['platform'] == 'osx':
if env['bits'] == '32':
raise ValueError('Only 64-bit builds are supported for the macOS target.')
env.Append(CCFLAGS=['-g', '-std=c++14', '-arch', 'x86_64'])
env.Append(LINKFLAGS=['-arch', 'x86_64', '-framework', 'Cocoa', '-Wl,-undefined,dynamic_lookup'])
if env['target'] == 'debug':
env.Append(CCFLAGS=['-Og'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['-O3'])
elif env['platform'] == 'windows':
if host_platform == 'windows' and not env['use_mingw']:
# MSVC
env.Append(LINKFLAGS=['/WX'])
if env['target'] == 'debug':
env.Append(CCFLAGS=['/EHsc', '/D_DEBUG', '/MDd'])
elif env['target'] == 'release':
env.Append(CCFLAGS=['/O2', '/EHsc', '/DNDEBUG', '/MD'])
else:
# MinGW
if env['bits'] == '64':
env['CXX'] = 'x86_64-w64-mingw32-g++'
elif env['bits'] == '32':
env['CXX'] = 'i686-w64-mingw32-g++'
env.Append(CCFLAGS=['-g', '-O3', '-std=c++14', '-Wwrite-strings'])
env.Append(LINKFLAGS=['--static', '-Wl,--no-undefined', '-static-libgcc', '-static-libstdc++'])
env.Append(CPPPATH=['.', env['headers_dir'], 'include', 'include/gen', 'include/core'])
# source to compile
sources = []
add_sources(sources, 'src', 'cpp')
#add_sources(sources, 'src/gen', 'cpp')
# make sure our binding library is properly includes
env.Append(CPPPATH=['.', godot_headers_path, cpp_bindings_path + 'include/', cpp_bindings_path + 'include/core/', cpp_bindings_path + 'include/gen/'])
env.Append(LIBPATH=[cpp_bindings_path + 'bin/'])
libgodot = '{}.{}.{}.{}'.format(cpp_library, env['platform'], env['target'], env['bits'])
env.Append(LIBS=[libgodot])
# static = env.Command('libstdc++.a', None, Action('ln -s `g++ -print-file-name=libstdc++.a` $TARGET'));
# tweak this if you want to use different folders, or more folders, to store your source code in.
env.Append(CPPPATH=['src/'])
sources = Glob('src/*.cpp')
library = env.SharedLibrary(target=os.path.join(env['target_path'], 'libgodot-cpp.{}.{}.{}'.format(env['platform'], env['target'], env['bits'])), source=sources)
Default(library)
# Generates help for the -h scons option.
Help(opts.GenerateHelpText(env))

0
crypt/src/.gdignore Normal file
View file

1
crypt/src/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.os

34
crypt/src/gdcrypt.cpp Normal file
View file

@ -0,0 +1,34 @@
/*
Build :
scons platform=linux bits=64
*/
#include "gdcrypt.h"
#include "sha512crypt.h"
using namespace godot;
void GDCrypt::_register_methods() {
register_method("encrypt", &GDCrypt::encrypt);
}
GDCrypt::GDCrypt() {
}
GDCrypt::~GDCrypt() {
// add your cleanup here
}
void GDCrypt::_init() {
// initialize any variables here
}
String GDCrypt::encrypt(String key, String salt) {
String out = "";
char * res = sha512_crypt (key.ascii().get_data(), salt.ascii().get_data());
out = res;
return out;
}

25
crypt/src/gdcrypt.h Normal file
View file

@ -0,0 +1,25 @@
#ifndef GDCRYPT_H
#define GDCRYPT_H
#include <Godot.hpp>
#include <Reference.hpp>
namespace godot {
class GDCrypt : public Reference {
GODOT_CLASS(GDCrypt, Reference)
public:
static void _register_methods();
GDCrypt();
~GDCrypt();
void _init(); // our initializer called by Godot
String encrypt(String key, String salt);
};
}
#endif

16
crypt/src/gdlibrary.cpp Normal file
View file

@ -0,0 +1,16 @@
#include "gdcrypt.h"
extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
godot::Godot::gdnative_init(o);
}
extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
godot::Godot::gdnative_terminate(o);
}
extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
godot::Godot::nativescript_init(handle);
godot::register_class<godot::GDCrypt>();
}

622
crypt/src/sha512crypt.cpp Normal file
View file

@ -0,0 +1,622 @@
/* SHA512-based Unix crypt implementation.
Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>. */
#include <endian.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/types.h>
/* Structure to save state of computation between the single steps. */
struct sha512_ctx
{
uint64_t H[8];
uint64_t total[2];
uint64_t buflen;
char buffer[256]; /* NB: always correctly aligned for uint64_t. */
};
#if __BYTE_ORDER == __LITTLE_ENDIAN
# define SWAP(n) \
(((n) << 56) \
| (((n) & 0xff00) << 40) \
| (((n) & 0xff0000) << 24) \
| (((n) & 0xff000000) << 8) \
| (((n) >> 8) & 0xff000000) \
| (((n) >> 24) & 0xff0000) \
| (((n) >> 40) & 0xff00) \
| ((n) >> 56))
#else
# define SWAP(n) (n)
#endif
/* This array contains the bytes used to pad the buffer to the next
64-byte boundary. (FIPS 180-2:5.1.2) */
static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ... */ };
/* Constants for SHA512 from FIPS 180-2:4.2.3. */
static const uint64_t K[80] =
{
UINT64_C (0x428a2f98d728ae22), UINT64_C (0x7137449123ef65cd),
UINT64_C (0xb5c0fbcfec4d3b2f), UINT64_C (0xe9b5dba58189dbbc),
UINT64_C (0x3956c25bf348b538), UINT64_C (0x59f111f1b605d019),
UINT64_C (0x923f82a4af194f9b), UINT64_C (0xab1c5ed5da6d8118),
UINT64_C (0xd807aa98a3030242), UINT64_C (0x12835b0145706fbe),
UINT64_C (0x243185be4ee4b28c), UINT64_C (0x550c7dc3d5ffb4e2),
UINT64_C (0x72be5d74f27b896f), UINT64_C (0x80deb1fe3b1696b1),
UINT64_C (0x9bdc06a725c71235), UINT64_C (0xc19bf174cf692694),
UINT64_C (0xe49b69c19ef14ad2), UINT64_C (0xefbe4786384f25e3),
UINT64_C (0x0fc19dc68b8cd5b5), UINT64_C (0x240ca1cc77ac9c65),
UINT64_C (0x2de92c6f592b0275), UINT64_C (0x4a7484aa6ea6e483),
UINT64_C (0x5cb0a9dcbd41fbd4), UINT64_C (0x76f988da831153b5),
UINT64_C (0x983e5152ee66dfab), UINT64_C (0xa831c66d2db43210),
UINT64_C (0xb00327c898fb213f), UINT64_C (0xbf597fc7beef0ee4),
UINT64_C (0xc6e00bf33da88fc2), UINT64_C (0xd5a79147930aa725),
UINT64_C (0x06ca6351e003826f), UINT64_C (0x142929670a0e6e70),
UINT64_C (0x27b70a8546d22ffc), UINT64_C (0x2e1b21385c26c926),
UINT64_C (0x4d2c6dfc5ac42aed), UINT64_C (0x53380d139d95b3df),
UINT64_C (0x650a73548baf63de), UINT64_C (0x766a0abb3c77b2a8),
UINT64_C (0x81c2c92e47edaee6), UINT64_C (0x92722c851482353b),
UINT64_C (0xa2bfe8a14cf10364), UINT64_C (0xa81a664bbc423001),
UINT64_C (0xc24b8b70d0f89791), UINT64_C (0xc76c51a30654be30),
UINT64_C (0xd192e819d6ef5218), UINT64_C (0xd69906245565a910),
UINT64_C (0xf40e35855771202a), UINT64_C (0x106aa07032bbd1b8),
UINT64_C (0x19a4c116b8d2d0c8), UINT64_C (0x1e376c085141ab53),
UINT64_C (0x2748774cdf8eeb99), UINT64_C (0x34b0bcb5e19b48a8),
UINT64_C (0x391c0cb3c5c95a63), UINT64_C (0x4ed8aa4ae3418acb),
UINT64_C (0x5b9cca4f7763e373), UINT64_C (0x682e6ff3d6b2b8a3),
UINT64_C (0x748f82ee5defb2fc), UINT64_C (0x78a5636f43172f60),
UINT64_C (0x84c87814a1f0ab72), UINT64_C (0x8cc702081a6439ec),
UINT64_C (0x90befffa23631e28), UINT64_C (0xa4506cebde82bde9),
UINT64_C (0xbef9a3f7b2c67915), UINT64_C (0xc67178f2e372532b),
UINT64_C (0xca273eceea26619c), UINT64_C (0xd186b8c721c0c207),
UINT64_C (0xeada7dd6cde0eb1e), UINT64_C (0xf57d4f7fee6ed178),
UINT64_C (0x06f067aa72176fba), UINT64_C (0x0a637dc5a2c898a6),
UINT64_C (0x113f9804bef90dae), UINT64_C (0x1b710b35131c471b),
UINT64_C (0x28db77f523047d84), UINT64_C (0x32caab7b40c72493),
UINT64_C (0x3c9ebe0a15c9bebc), UINT64_C (0x431d67c49c100d4c),
UINT64_C (0x4cc5d4becb3e42b6), UINT64_C (0x597f299cfc657e2a),
UINT64_C (0x5fcb6fab3ad6faec), UINT64_C (0x6c44198c4a475817)
};
/* Process LEN bytes of BUFFER, accumulating context into CTX.
It is assumed that LEN % 128 == 0. */
static void
sha512_process_block (const void *buffer, size_t len, struct sha512_ctx *ctx)
{
const uint64_t *words = (uint64_t *)buffer;
size_t nwords = len / sizeof (uint64_t);
uint64_t a = ctx->H[0];
uint64_t b = ctx->H[1];
uint64_t c = ctx->H[2];
uint64_t d = ctx->H[3];
uint64_t e = ctx->H[4];
uint64_t f = ctx->H[5];
uint64_t g = ctx->H[6];
uint64_t h = ctx->H[7];
/* First increment the byte count. FIPS 180-2 specifies the possible
length of the file up to 2^128 bits. Here we only compute the
number of bytes. Do a double word increment. */
ctx->total[0] += len;
if (ctx->total[0] < len)
++ctx->total[1];
/* Process all bytes in the buffer with 128 bytes in each round of
the loop. */
while (nwords > 0)
{
uint64_t W[80];
uint64_t a_save = a;
uint64_t b_save = b;
uint64_t c_save = c;
uint64_t d_save = d;
uint64_t e_save = e;
uint64_t f_save = f;
uint64_t g_save = g;
uint64_t h_save = h;
/* Operators defined in FIPS 180-2:4.1.2. */
#define Ch(x, y, z) ((x & y) ^ (~x & z))
#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define S0(x) (CYCLIC (x, 28) ^ CYCLIC (x, 34) ^ CYCLIC (x, 39))
#define S1(x) (CYCLIC (x, 14) ^ CYCLIC (x, 18) ^ CYCLIC (x, 41))
#define R0(x) (CYCLIC (x, 1) ^ CYCLIC (x, 8) ^ (x >> 7))
#define R1(x) (CYCLIC (x, 19) ^ CYCLIC (x, 61) ^ (x >> 6))
/* It is unfortunate that C does not provide an operator for
cyclic rotation. Hope the C compiler is smart enough. */
#define CYCLIC(w, s) ((w >> s) | (w << (64 - s)))
/* Compute the message schedule according to FIPS 180-2:6.3.2 step 2. */
for (unsigned int t = 0; t < 16; ++t)
{
W[t] = SWAP (*words);
++words;
}
for (unsigned int t = 16; t < 80; ++t)
W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16];
/* The actual computation according to FIPS 180-2:6.3.2 step 3. */
for (unsigned int t = 0; t < 80; ++t)
{
uint64_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t];
uint64_t T2 = S0 (a) + Maj (a, b, c);
h = g;
g = f;
f = e;
e = d + T1;
d = c;
c = b;
b = a;
a = T1 + T2;
}
/* Add the starting values of the context according to FIPS 180-2:6.3.2
step 4. */
a += a_save;
b += b_save;
c += c_save;
d += d_save;
e += e_save;
f += f_save;
g += g_save;
h += h_save;
/* Prepare for the next round. */
nwords -= 16;
}
/* Put checksum in context given as argument. */
ctx->H[0] = a;
ctx->H[1] = b;
ctx->H[2] = c;
ctx->H[3] = d;
ctx->H[4] = e;
ctx->H[5] = f;
ctx->H[6] = g;
ctx->H[7] = h;
}
/* Initialize structure containing state of computation.
(FIPS 180-2:5.3.3) */
static void
sha512_init_ctx (struct sha512_ctx *ctx)
{
ctx->H[0] = UINT64_C (0x6a09e667f3bcc908);
ctx->H[1] = UINT64_C (0xbb67ae8584caa73b);
ctx->H[2] = UINT64_C (0x3c6ef372fe94f82b);
ctx->H[3] = UINT64_C (0xa54ff53a5f1d36f1);
ctx->H[4] = UINT64_C (0x510e527fade682d1);
ctx->H[5] = UINT64_C (0x9b05688c2b3e6c1f);
ctx->H[6] = UINT64_C (0x1f83d9abfb41bd6b);
ctx->H[7] = UINT64_C (0x5be0cd19137e2179);
ctx->total[0] = ctx->total[1] = 0;
ctx->buflen = 0;
}
/* Process the remaining bytes in the internal buffer and the usual
prolog according to the standard and write the result to RESBUF.
IMPORTANT: On some systems it is required that RESBUF is correctly
aligned for a 32 bits value. */
static void *
sha512_finish_ctx (struct sha512_ctx *ctx, void *resbuf)
{
/* Take yet unprocessed bytes into account. */
uint64_t bytes = ctx->buflen;
size_t pad;
/* Now count remaining bytes. */
ctx->total[0] += bytes;
if (ctx->total[0] < bytes)
++ctx->total[1];
pad = bytes >= 112 ? 128 + 112 - bytes : 112 - bytes;
memcpy (&ctx->buffer[bytes], fillbuf, pad);
/* Put the 128-bit file length in *bits* at the end of the buffer. */
*(uint64_t *) &ctx->buffer[bytes + pad + 8] = SWAP (ctx->total[0] << 3);
*(uint64_t *) &ctx->buffer[bytes + pad] = SWAP ((ctx->total[1] << 3) |
(ctx->total[0] >> 61));
/* Process last bytes. */
sha512_process_block (ctx->buffer, bytes + pad + 16, ctx);
/* Put result from CTX in first 64 bytes following RESBUF. */
for (unsigned int i = 0; i < 8; ++i)
((uint64_t *) resbuf)[i] = SWAP (ctx->H[i]);
return resbuf;
}
static void
sha512_process_bytes (const void *buffer, size_t len, struct sha512_ctx *ctx)
{
/* When we already have some bits in our internal buffer concatenate
both inputs first. */
if (ctx->buflen != 0)
{
size_t left_over = ctx->buflen;
size_t add = 256 - left_over > len ? len : 256 - left_over;
memcpy (&ctx->buffer[left_over], buffer, add);
ctx->buflen += add;
if (ctx->buflen > 128)
{
sha512_process_block (ctx->buffer, ctx->buflen & ~127, ctx);
ctx->buflen &= 127;
/* The regions in the following copy operation cannot overlap. */
memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~127],
ctx->buflen);
}
buffer = (const char *) buffer + add;
len -= add;
}
/* Process available complete blocks. */
if (len >= 128)
{
#if !_STRING_ARCH_unaligned
/* To check alignment gcc has an appropriate operator. Other
compilers don't. */
# if __GNUC__ >= 2
# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__ (uint64_t) != 0)
# else
# define UNALIGNED_P(p) (((uintptr_t) p) % sizeof (uint64_t) != 0)
# endif
if (UNALIGNED_P (buffer))
while (len > 128)
{
sha512_process_block (memcpy (ctx->buffer, buffer, 128), 128,
ctx);
buffer = (const char *) buffer + 128;
len -= 128;
}
else
#endif
{
sha512_process_block (buffer, len & ~127, ctx);
buffer = (const char *) buffer + (len & ~127);
len &= 127;
}
}
/* Move remaining bytes into internal buffer. */
if (len > 0)
{
size_t left_over = ctx->buflen;
memcpy (&ctx->buffer[left_over], buffer, len);
left_over += len;
if (left_over >= 128)
{
sha512_process_block (ctx->buffer, 128, ctx);
left_over -= 128;
memcpy (ctx->buffer, &ctx->buffer[128], left_over);
}
ctx->buflen = left_over;
}
}
/* Define our magic string to mark salt for SHA512 "encryption"
replacement. */
static const char sha512_salt_prefix[] = "$6$";
/* Prefix for optional rounds specification. */
static const char sha512_rounds_prefix[] = "rounds=";
/* Maximum salt string length. */
#define SALT_LEN_MAX 16
/* Default number of rounds if not explicitly specified. */
#define ROUNDS_DEFAULT 5000
/* Minimum number of rounds. */
#define ROUNDS_MIN 1000
/* Maximum number of rounds. */
#define ROUNDS_MAX 999999999
/* Table with characters for base64 transformation. */
static const char b64t[65] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
static char *
sha512_crypt_r (const char *key, const char *salt, char *buffer, int buflen)
{
unsigned char alt_result[64]
__attribute__ ((__aligned__ (__alignof__ (uint64_t))));
unsigned char temp_result[64]
__attribute__ ((__aligned__ (__alignof__ (uint64_t))));
struct sha512_ctx ctx;
struct sha512_ctx alt_ctx;
size_t salt_len;
size_t key_len;
size_t cnt;
char *cp;
char *copied_key = NULL;
char *copied_salt = NULL;
char *p_bytes;
char *s_bytes;
/* Default number of rounds. */
size_t rounds = ROUNDS_DEFAULT;
bool rounds_custom = false;
/* Find beginning of salt string. The prefix should normally always
be present. Just in case it is not. */
if (strncmp (sha512_salt_prefix, salt, sizeof (sha512_salt_prefix) - 1) == 0)
/* Skip salt prefix. */
salt += sizeof (sha512_salt_prefix) - 1;
if (strncmp (salt, sha512_rounds_prefix, sizeof (sha512_rounds_prefix) - 1)
== 0)
{
const char *num = salt + sizeof (sha512_rounds_prefix) - 1;
char *endp;
unsigned long int srounds = strtoul (num, &endp, 10);
if (*endp == '$')
{
salt = endp + 1;
rounds = MAX (ROUNDS_MIN, MIN (srounds, ROUNDS_MAX));
rounds_custom = true;
}
}
salt_len = MIN (strcspn (salt, "$"), SALT_LEN_MAX);
key_len = strlen (key);
if ((key - (char *) 0) % __alignof__ (uint64_t) != 0)
{
char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t));
key = copied_key = (char *)
memcpy (tmp + __alignof__ (uint64_t)
- (tmp - (char *) 0) % __alignof__ (uint64_t),
key, key_len);
}
if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0)
{
char *tmp = (char *) alloca (salt_len + __alignof__ (uint64_t));
salt = copied_salt = (char *)
memcpy (tmp + __alignof__ (uint64_t)
- (tmp - (char *) 0) % __alignof__ (uint64_t),
salt, salt_len);
}
/* Prepare for the real work. */
sha512_init_ctx (&ctx);
/* Add the key string. */
sha512_process_bytes (key, key_len, &ctx);
/* The last part is the salt string. This must be at most 16
characters and it ends at the first `$' character (for
compatibility with existing implementations). */
sha512_process_bytes (salt, salt_len, &ctx);
/* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The
final result will be added to the first context. */
sha512_init_ctx (&alt_ctx);
/* Add key. */
sha512_process_bytes (key, key_len, &alt_ctx);
/* Add salt. */
sha512_process_bytes (salt, salt_len, &alt_ctx);
/* Add key again. */
sha512_process_bytes (key, key_len, &alt_ctx);
/* Now get result of this (64 bytes) and add it to the other
context. */
sha512_finish_ctx (&alt_ctx, alt_result);
/* Add for any character in the key one byte of the alternate sum. */
for (cnt = key_len; cnt > 64; cnt -= 64)
sha512_process_bytes (alt_result, 64, &ctx);
sha512_process_bytes (alt_result, cnt, &ctx);
/* Take the binary representation of the length of the key and for every
1 add the alternate sum, for every 0 the key. */
for (cnt = key_len; cnt > 0; cnt >>= 1)
if ((cnt & 1) != 0)
sha512_process_bytes (alt_result, 64, &ctx);
else
sha512_process_bytes (key, key_len, &ctx);
/* Create intermediate result. */
sha512_finish_ctx (&ctx, alt_result);
/* Start computation of P byte sequence. */
sha512_init_ctx (&alt_ctx);
/* For every character in the password add the entire password. */
for (cnt = 0; cnt < key_len; ++cnt)
sha512_process_bytes (key, key_len, &alt_ctx);
/* Finish the digest. */
sha512_finish_ctx (&alt_ctx, temp_result);
/* Create byte sequence P. */
cp = p_bytes = (char *)alloca (key_len);
for (cnt = key_len; cnt >= 64; cnt -= 64)
cp = (char *)mempcpy (cp, temp_result, 64);
memcpy (cp, temp_result, cnt);
/* Start computation of S byte sequence. */
sha512_init_ctx (&alt_ctx);
/* For every character in the password add the entire password. */
for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
sha512_process_bytes (salt, salt_len, &alt_ctx);
/* Finish the digest. */
sha512_finish_ctx (&alt_ctx, temp_result);
/* Create byte sequence S. */
cp = s_bytes = (char *)alloca (salt_len);
for (cnt = salt_len; cnt >= 64; cnt -= 64)
cp = (char *)mempcpy ( cp, temp_result, 64);
memcpy (cp, temp_result, cnt);
/* Repeatedly run the collected hash value through SHA512 to burn
CPU cycles. */
for (cnt = 0; cnt < rounds; ++cnt)
{
/* New context. */
sha512_init_ctx (&ctx);
/* Add key or last result. */
if ((cnt & 1) != 0)
sha512_process_bytes (p_bytes, key_len, &ctx);
else
sha512_process_bytes (alt_result, 64, &ctx);
/* Add salt for numbers not divisible by 3. */
if (cnt % 3 != 0)
sha512_process_bytes (s_bytes, salt_len, &ctx);
/* Add key for numbers not divisible by 7. */
if (cnt % 7 != 0)
sha512_process_bytes (p_bytes, key_len, &ctx);
/* Add key or last result. */
if ((cnt & 1) != 0)
sha512_process_bytes (alt_result, 64, &ctx);
else
sha512_process_bytes (p_bytes, key_len, &ctx);
/* Create intermediate result. */
sha512_finish_ctx (&ctx, alt_result);
}
/* Now we can construct the result string. It consists of three
parts. */
cp = __stpncpy (buffer, sha512_salt_prefix, MAX (0, buflen));
buflen -= sizeof (sha512_salt_prefix) - 1;
if (rounds_custom)
{
int n = snprintf (cp, MAX (0, buflen), "%s%zu$",
sha512_rounds_prefix, rounds);
cp += n;
buflen -= n;
}
cp = __stpncpy (cp, salt, MIN ((size_t) MAX (0, buflen), salt_len));
buflen -= MIN ((size_t) MAX (0, buflen), salt_len);
if (buflen > 0)
{
*cp++ = '$';
--buflen;
}
#define b64_from_24bit(B2, B1, B0, N) \
do { \
unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
int n = (N); \
while (n-- > 0 && buflen > 0) \
{ \
*cp++ = b64t[w & 0x3f]; \
--buflen; \
w >>= 6; \
} \
} while (0)
b64_from_24bit (alt_result[0], alt_result[21], alt_result[42], 4);
b64_from_24bit (alt_result[22], alt_result[43], alt_result[1], 4);
b64_from_24bit (alt_result[44], alt_result[2], alt_result[23], 4);
b64_from_24bit (alt_result[3], alt_result[24], alt_result[45], 4);
b64_from_24bit (alt_result[25], alt_result[46], alt_result[4], 4);
b64_from_24bit (alt_result[47], alt_result[5], alt_result[26], 4);
b64_from_24bit (alt_result[6], alt_result[27], alt_result[48], 4);
b64_from_24bit (alt_result[28], alt_result[49], alt_result[7], 4);
b64_from_24bit (alt_result[50], alt_result[8], alt_result[29], 4);
b64_from_24bit (alt_result[9], alt_result[30], alt_result[51], 4);
b64_from_24bit (alt_result[31], alt_result[52], alt_result[10], 4);
b64_from_24bit (alt_result[53], alt_result[11], alt_result[32], 4);
b64_from_24bit (alt_result[12], alt_result[33], alt_result[54], 4);
b64_from_24bit (alt_result[34], alt_result[55], alt_result[13], 4);
b64_from_24bit (alt_result[56], alt_result[14], alt_result[35], 4);
b64_from_24bit (alt_result[15], alt_result[36], alt_result[57], 4);
b64_from_24bit (alt_result[37], alt_result[58], alt_result[16], 4);
b64_from_24bit (alt_result[59], alt_result[17], alt_result[38], 4);
b64_from_24bit (alt_result[18], alt_result[39], alt_result[60], 4);
b64_from_24bit (alt_result[40], alt_result[61], alt_result[19], 4);
b64_from_24bit (alt_result[62], alt_result[20], alt_result[41], 4);
b64_from_24bit (0, 0, alt_result[63], 2);
if (buflen <= 0)
{
errno = ERANGE;
buffer = NULL;
}
else
*cp = '\0'; /* Terminate the string. */
/* Clear the buffer for the intermediate result so that people
attaching to processes or reading core dumps cannot get any
information. We do it in this way to clear correct_words[]
inside the SHA512 implementation as well. */
sha512_init_ctx (&ctx);
sha512_finish_ctx (&ctx, alt_result);
memset (temp_result, '\0', sizeof (temp_result));
memset (p_bytes, '\0', key_len);
memset (s_bytes, '\0', salt_len);
memset (&ctx, '\0', sizeof (ctx));
memset (&alt_ctx, '\0', sizeof (alt_ctx));
if (copied_key != NULL)
memset (copied_key, '\0', key_len);
if (copied_salt != NULL)
memset (copied_salt, '\0', salt_len);
return buffer;
}
/* This entry point is equivalent to the `crypt' function in Unix
libcs. */
char *
sha512_crypt (const char *key, const char *salt)
{
/* We don't want to have an arbitrary limit in the size of the
password. We can compute an upper bound for the size of the
result in advance and so we can prepare the buffer we pass to
`sha512_crypt_r'. */
static char *buffer = NULL;
static int buflen = 0;
int needed = (sizeof (sha512_salt_prefix) - 1
+ sizeof (sha512_rounds_prefix) + 9 + 1
+ strlen (salt) + 1 + 86 + 1);
if (buflen < needed)
{
char *new_buffer = (char *) realloc (buffer, needed);
if (new_buffer == NULL)
return NULL;
buffer = new_buffer;
buflen = needed;
}
return sha512_crypt_r (key, salt, buffer, buflen);
}

6
crypt/src/sha512crypt.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef SHA512CRYPT_H
#define SHA512CRYPT_H
char * sha512_crypt (const char *key, const char *salt);
#endif

View file

@ -18,3 +18,4 @@ ss_reflections_enabled = true
ssao_enabled = true
ssao_quality = 1
glow_bloom = 0.2

View file

@ -23,7 +23,7 @@ var old_scene = null
var parent_scene = null
var current_map = null
var current_start_position = "start_position"
var current_state = "login"
var font_size= 14
@ -31,7 +31,7 @@ var font_size= 14
func _ready():
var root = get_tree().get_root()
# current_scene = root.get_child(root.get_child_count() -1)
change_title()
get_tree().get_root().connect("size_changed", self, "on_window_size_changed")
@ -43,15 +43,15 @@ func _ready():
#### change title ####
func on_window_size_changed():
change_title()
func change_title():
var title = "Khanat"
var title = "Khanat"
if has_node( WINDOW_TITLE_INPUT ):
var title_node = get_node( WINDOW_TITLE_INPUT )
if title_node and not title_node.text.strip_edges() == "":
title = title_node.text.strip_edges()
title += " (" + String(OS.get_window_size().x) + "x" + String(OS.get_window_size().y) + ")"
OS.set_window_title( title )
########
@ -68,25 +68,25 @@ func load_scene( scene_path ):
if loader == null: # check for errors
return false
return true
func change_level( p_next_state, p_next_scene_path, p_parent_next_scene = null, p_old_scene = null, p_start_position = "start_position" ):
if not load_scene( p_next_scene_path ):
print( "Erreur lors du chargement de la scene: "+str(p_next_scene_path) )
return
character.hide()
# get_node("background_loader/center_container").rect_min_size = get_viewport().size
progress_texture.rect_min_size = get_viewport().size
get_node("background_loader").show()
self.current_start_position = p_start_position
parent_scene = p_parent_next_scene
old_scene = p_old_scene
set_process(true)
if old_scene:
unload_scene( old_scene )
@ -94,7 +94,7 @@ func change_level( p_next_state, p_next_scene_path, p_parent_next_scene = null,
self.current_state = p_next_state
########
func _process( time ):
########
#### LOADER
@ -108,7 +108,7 @@ func _process( time ):
return
var t = OS.get_ticks_msec()
while OS.get_ticks_msec() < t + time_max: # use "time_max" to control how much time we block this thread
while OS.get_ticks_msec() < t + time_max: # use "time_max" to control how much time we block this thread
# poll your loader
var err = loader.poll()
# update_progress()
@ -127,7 +127,7 @@ func _process( time ):
loader = null
break
########
func _input( event ):
if current_state == "game" and event is InputEventKey and not event.is_echo():
@ -138,43 +138,43 @@ func _input( event ):
elif event.is_action_pressed("test_change_map_3"):
global.change_level( "game", "res://game_scene/game_scene.tscn", null, current_map )
func update_progress():
var progress = (float(loader.get_stage()) / loader.get_stage_count()) * (progress_texture.max_value-progress_texture.min_value)
progress_texture.value = progress_texture.min_value+progress
func set_new_scene( scene_resource ):
func set_new_scene( scene_resource ):
progress_texture.value = 0
var scene = scene_resource.instance()
# current_scene = scene_resource.instance()
if parent_scene:
parent_scene.add_child(scene)
else:
get_tree().get_root().add_child(scene)
print( "scene: "+str(scene.name) )
print( "start position: " + str(self.current_start_position ) )
if scene.has_node( self.current_start_position ):
print( "OK" )
character.update( scene.get_node( self.current_start_position ) )
current_map = scene
get_node("background_loader").hide()
character.show()
func _on_login_scene_character_creation_finished():
self.change_level( "game", "res://game_scene/game_scene.tscn", null, get_tree().get_root().get_node("login_scene") )
func _on_logout_button_pressed():
self.change_level( "login", "res://login_scene/login_scene.tscn", null, current_map )
get_tree().paused = false

@ -1 +1 @@
Subproject commit e4ad265339f17042a86227bfb44f9d5d7dee5ba4
Subproject commit 123d9f0e9264dcc7206888fc96419b32feef00c8

View file

@ -3,6 +3,8 @@ extends Control
signal login_button_pressed
signal register_button_pressed
var _username
var _password
func _on_login_button_pressed():
emit_signal( "login_button_pressed" )
@ -12,16 +14,51 @@ func _on_play_button_pressed():
var username = get_node("h_box_container/v_box_container/margin_container/login_box/email_box/email_edit").get_text();
var password = get_node("h_box_container/v_box_container/margin_container/login_box/password_box/password_edit").get_text();
if username != null and username != "" and password != null and password != "":
do_request(username, password)
do_request_salt(username, password)
func _on_play_without_connexion_pressed():
emit_signal( "login_button_pressed" )
# Step get salt
func do_request_salt(username, password):
#var message = load("res://assets/Scripts/Models/nel_login_message.gd")
var connexion = load("res://assets/Scripts/Config/connexion.gd").connexion.new()
#if message:
_username = username
_password = password
var message = load("res://assets/Scripts/Models/nel_login_message.gd").nel_login_message.new("https-login", _username, _password, "Lirria", "2", "en")
#message = message.nel_login_message.new("https-login", _username, _password, "Lirria", "2", "en")
var url_login = connexion.get_url_login();
$HTTPSalt.request(url_login + "?" + message.get_request_salt());
#$HTTPRequest.request(url_login + "?" + message.get_request_salt());
print("[login_menu] URL:" + url_login + "?" + message.get_request_salt());
func _on_HTTPSalt_request_completed(result, response_code, headers, body):
if response_code != 200 || ProjectSettings.get_setting("kaghanat/debug_mode"):
emit_signal( "login_button_pressed" )
else:
var text = str2var(body.get_string_from_utf8())
var s = body.get_string_from_utf8().split(":")
print("[login_menu:_on_HTTPSalt_request_completed] return:'" + str(text) + "'")
if(s[0] == "1"):
print("[login_menu] salt:'" + str(s[1]) + "'")
var message = load("res://assets/Scripts/Models/nel_login_message.gd").nel_login_message.new("https-login", _username, _password, "Lirria", "2", "en")
var connexion = load("res://assets/Scripts/Config/connexion.gd").connexion.new()
var url_login = connexion.get_url_login();
print("[login_menu] URL:" + url_login + "?" + message.get_request_string(str(s[1])));
$HTTPRequest.request(url_login + "?" + message.get_request_string(str(s[1])));
else:
get_node("error_dialog/v_box_container/label").text = "Impossible de se connecter"
get_node("error_dialog").popup_centered()
# Step Login
func do_request(username, password):
var message = load("res://assets/Scripts/Models/nel_login_message.gd")
var connexion = load("res://assets/Scripts/Config/connexion_config.gd")
var connexion = load("res://assets/Scripts/Config/connexion.gd").connexion.new()
if message:
var url_login
message = message.nel_login_message.new("https-login", username, password, "Lirria", "2", "en")
@ -34,13 +71,44 @@ func _on_HTTPRequest_request_completed(result, response_code, headers, body):
if response_code != 200 || ProjectSettings.get_setting("kaghanat/debug_mode"):
emit_signal( "login_button_pressed" )
else:
var s = body.get_string_from_utf8().split(":")
if(s[0] != "0"):
var server_info_script = load("res://assets/Scripts/Models/nel_server_info.gd");
var server_info = server_info_script.nel_server_info.new(body.get_string_from_utf8());
emit_signal( "login_button_pressed" )
# No error so login was successful.
var text = str2var(body.get_string_from_utf8())
var lines = body.get_string_from_utf8().split("\n")
if lines.size() != 2:
get_node("error_dialog/v_box_container/label").text = "Impossible de se connecter (bad return)"
get_node("error_dialog").popup_centered()
return
var line1 = lines[0].split("#")
var line2 = lines[1].split("#")
#print("[login_menu:_on_HTTPRequest_request_completed] return:'" + str(text) + "'" + str(lines.size()) + "'" + str(line1.size()) + "'" + str(line2.size()))
if line1[0] != "1":
get_node("error_dialog/v_box_container/label").text = "Impossible de se connecter (return :" + str(line1[0]) + ")"
get_node("error_dialog").popup_centered()
return
if line1.size() < 5:
get_node("error_dialog/v_box_container/label").text = "Impossible de se connecter (bad return 1st line, size:" + str(line1.size()) + ")"
get_node("error_dialog").popup_centered()
return
if line2.size() != 3:
get_node("error_dialog/v_box_container/label").text = "Impossible de se connecter (bad return 2nd line, size:" + str(line2.size()) + ")"
get_node("error_dialog").popup_centered()
return
var server_info_script = load("res://assets/Scripts/Models/nel_server_info.gd");
print("[login_menu] " + str(body.get_string_from_utf8()))
var state = line1[0]
var cookie = line1[1]
var fsaddr = line1[2]
var ringmainurl = line1[3]
var fartp = line1[4]
var stat = "0"
if line1.size() >= 6:
stat = line1[5]
var r2serverversion = line2[0]
var r2backuppatchurl = line2[1]
var r2patchurl = line2[2]
print("[login_menu:_on_HTTPRequest_request_completed] state:" + state + ", cookie:" + cookie + ", fsaddr:" + fsaddr + ", ringmainurl:" + ringmainurl + ", fartp:" + fartp + ", stat:" + stat + ", r2serverversion:" + r2serverversion + ", r2backuppatchurl:" + r2backuppatchurl + ", r2patchurl:" + r2patchurl)
var server_info = server_info_script.nel_server_info.new(body.get_string_from_utf8());
emit_signal( "login_button_pressed" )
func _make_post_request(url, data_to_send, use_ssl):
# Convert data to json string:
@ -54,3 +122,5 @@ func _on_register_button_pressed():
emit_signal( "register_button_pressed" )
func _on_error_dialog_button_pressed():
get_node("error_dialog").hide()

View file

@ -22,6 +22,8 @@ anchor_bottom = 1.0
theme = ExtResource( 1 )
script = ExtResource( 2 )
[node name="HTTPSalt" type="HTTPRequest" parent="."]
[node name="HTTPRequest" type="HTTPRequest" parent="."]
[node name="background" type="TextureRect" parent="."]
@ -185,7 +187,38 @@ rect_min_size = Vector2( 128, 0 )
size_flags_horizontal = 10
custom_fonts/font = SubResource( 3 )
text = "Tester sans se connecter"
[node name="error_dialog" type="PopupDialog" parent="."]
margin_right = 400.0
margin_bottom = 150.0
size_flags_horizontal = 7
size_flags_vertical = 7
popup_exclusive = true
[node name="v_box_container" type="VBoxContainer" parent="error_dialog"]
margin_right = 400.0
margin_bottom = 150.0
size_flags_horizontal = 7
size_flags_vertical = 7
alignment = 1
[node name="label" type="Label" parent="error_dialog/v_box_container"]
margin_right = 400.0
margin_bottom = 17.0
text = "Error detected"
align = 1
valign = 1
[node name="button" type="Button" parent="error_dialog/v_box_container"]
margin_right = 16.0
margin_bottom = 33.0
size_flags_horizontal = 4
size_flags_vertical = 4
text = "Ok"
[connection signal="request_completed" from="HTTPSalt" to="." method="_on_HTTPSalt_request_completed"]
[connection signal="request_completed" from="HTTPRequest" to="." method="_on_HTTPRequest_request_completed"]
[connection signal="pressed" from="h_box_container/v_box_container/margin_container/login_box/email_box/email_label_box/register_button" to="." method="_on_register_button_pressed"]
[connection signal="pressed" from="h_box_container/v_box_container/margin_container/login_box/h_box_container/play_button" to="." method="_on_play_button_pressed"]
[connection signal="pressed" from="h_box_container/v_box_container/margin_container/login_box/h_box_container/play_without_connexion" to="." method="_on_play_without_connexion_pressed"]
[connection signal="pressed" from="error_dialog/v_box_container/button" to="." method="_on_error_dialog_button_pressed"]

View file

@ -15,6 +15,7 @@ func _ready():
$license_menu.hide()
func _on_login_menu_login_button_pressed():
print("[login_scene] Launch game")
$login_menu.hide()
$character_selection_menu.show()