15 changes: 12 additions & 3 deletions build/android/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ LOCAL_MODULE := vorbis
LOCAL_SRC_FILES := deps/libvorbis-libogg-android/libs/$(TARGET_LIBDIR)/libvorbis.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := gmp
LOCAL_SRC_FILES := deps/gmp/usr/lib/libgmp.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := ssl
LOCAL_SRC_FILES := deps/openssl/libssl.a
Expand All @@ -49,7 +54,6 @@ LOCAL_MODULE := crypto
LOCAL_SRC_FILES := deps/openssl/libcrypto.a
include $(PREBUILT_STATIC_LIBRARY)


include $(CLEAR_VARS)
LOCAL_MODULE := minetest

Expand Down Expand Up @@ -97,6 +101,7 @@ LOCAL_C_INCLUDES := \
deps/curl/include \
deps/openal-soft/jni/OpenAL/include \
deps/libvorbis-libogg-android/jni/include \
deps/gmp/usr/include \
deps/leveldb/include \
deps/sqlite/

Expand Down Expand Up @@ -203,13 +208,15 @@ LOCAL_SRC_FILES := \
jni/src/version.cpp \
jni/src/voxel.cpp \
jni/src/voxelalgorithms.cpp \
jni/src/util/auth.cpp \
jni/src/util/base64.cpp \
jni/src/util/directiontables.cpp \
jni/src/util/numeric.cpp \
jni/src/util/pointedthing.cpp \
jni/src/util/serialize.cpp \
jni/src/util/sha1.cpp \
jni/src/util/string.cpp \
jni/src/util/srp.cpp \
jni/src/util/timetaker.cpp \
jni/src/unittest/test.cpp \
jni/src/unittest/test_collision.cpp \
Expand Down Expand Up @@ -238,6 +245,8 @@ LOCAL_SRC_FILES := \
jni/src/client/clientlauncher.cpp \
jni/src/client/tile.cpp

# intentionally kept out (we already build openssl itself): jni/src/util/sha256.c

# Network
LOCAL_SRC_FILES += \
jni/src/network/connection.cpp \
Expand Down Expand Up @@ -283,7 +292,7 @@ LOCAL_SRC_FILES += \
jni/src/script/lua_api/l_vmanip.cpp \
jni/src/script/scripting_game.cpp \
jni/src/script/scripting_mainmenu.cpp

#freetype2 support
LOCAL_SRC_FILES += \
jni/src/cguittfont/xCGUITTFont.cpp
Expand Down Expand Up @@ -334,7 +343,7 @@ LOCAL_SRC_FILES += \
# json
LOCAL_SRC_FILES += jni/src/json/jsoncpp.cpp

LOCAL_SHARED_LIBRARIES := openal ogg vorbis
LOCAL_SHARED_LIBRARIES := openal ogg vorbis gmp
LOCAL_STATIC_LIBRARIES := Irrlicht freetype curl ssl crypto android_native_app_glue $(PROFILER_LIBS)

ifeq ($(HAVE_LEVELDB), 1)
Expand Down
28 changes: 28 additions & 0 deletions cmake/Modules/FindGMP.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

option(ENABLE_SYSTEM_GMP "Use GMP from system" TRUE)
mark_as_advanced(GMP_LIBRARY GMP_INCLUDE_DIR)
set(USE_SYSTEM_GMP FALSE)

if(ENABLE_SYSTEM_GMP)
find_library(GMP_LIBRARY NAMES libgmp.so)
find_path(GMP_INCLUDE_DIR NAMES gmp.h)

if(GMP_LIBRARY AND GMP_INCLUDE_DIR)
message (STATUS "Using GMP provided by system.")
set(USE_SYSTEM_GMP TRUE)
else()
message (STATUS "Detecting GMP from system failed.")
endif()
else()
message (STATUS "Detecting GMP from system disabled! (ENABLE_SYSTEM_GMP=0)")
endif()

if(NOT USE_SYSTEM_GMP)
message(STATUS "Using bundled mini-gmp library.")
set(GMP_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/gmp)
set(GMP_LIBRARY gmp)
add_subdirectory(gmp)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GMP DEFAULT_MSG GMP_LIBRARY GMP_INCLUDE_DIR)
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ endif(ENABLE_FREETYPE)

find_package(Lua REQUIRED)

find_package(GMP REQUIRED)

option(ENABLE_LEVELDB "Enable LevelDB backend" TRUE)
set(USE_LEVELDB FALSE)
Expand Down Expand Up @@ -446,6 +447,7 @@ include_directories(
${SOUND_INCLUDE_DIRS}
${SQLITE3_INCLUDE_DIR}
${LUA_INCLUDE_DIR}
${GMP_INCLUDE_DIR}
${JSON_INCLUDE_DIR}
${PROJECT_SOURCE_DIR}/script
)
Expand Down Expand Up @@ -479,6 +481,7 @@ if(BUILD_CLIENT)
${SOUND_LIBRARIES}
${SQLITE3_LIBRARY}
${LUA_LIBRARY}
${GMP_LIBRARY}
${JSON_LIBRARY}
${OPENGLES2_LIBRARIES}
${PLATFORM_LIBS}
Expand Down Expand Up @@ -532,6 +535,7 @@ if(BUILD_SERVER)
${JSON_LIBRARY}
${GETTEXT_LIBRARY}
${LUA_LIBRARY}
${GMP_LIBRARY}
${PLATFORM_LIBS}
)
set_target_properties(${PROJECT_NAME}server PROPERTIES
Expand Down
134 changes: 122 additions & 12 deletions src/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <sstream>
#include <IFileSystem.h>
#include "jthread/jmutexautolock.h"
#include "util/auth.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should auth.cpp/h and srp.c/h really be in util?? They do take on larger roles than utility functions, you know.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so you mean in src itself? Its so cramped there..., and the file is also included by l_util.cpp. network isn't good either because its not low level network related (like networkpacket) nor spanning a wide range of topics (like clientpackethandler).

#include "util/directiontables.h"
#include "util/pointedthing.h"
#include "util/serialize.h"
#include "util/string.h"
#include "util/srp.h"
#include "client.h"
#include "network/clientopcodes.h"
#include "filesys.h"
Expand Down Expand Up @@ -255,6 +257,8 @@ Client::Client(
m_highlighted_pos(0,0,0),
m_map_seed(0),
m_password(password),
m_chosen_auth_mech(AUTH_MECHANISM_NONE),
m_auth_data(NULL),
m_access_denied(false),
m_itemdef_received(false),
m_nodedef_received(false),
Expand Down Expand Up @@ -404,10 +408,13 @@ void Client::step(float dtime)
memset(pName, 0, PLAYERNAME_SIZE * sizeof(char));
memset(pPassword, 0, PASSWORD_SIZE * sizeof(char));

std::string hashed_password = translatePassword(myplayer->getName(), m_password);
snprintf(pName, PLAYERNAME_SIZE, "%s", myplayer->getName());
snprintf(pPassword, PASSWORD_SIZE, "%s", m_password.c_str());
snprintf(pPassword, PASSWORD_SIZE, "%s", hashed_password.c_str());

sendLegacyInit(pName, pPassword);
if (LATEST_PROTOCOL_VERSION >= 25)
sendInit(myplayer->getName());
}

// Not connected, return
Expand Down Expand Up @@ -943,6 +950,39 @@ void Client::interact(u8 action, const PointedThing& pointed)
Send(&pkt);
}

void Client::deleteAuthData()
{
if (!m_auth_data)
return;

switch (m_chosen_auth_mech) {
case AUTH_MECHANISM_FIRST_SRP:
break;
case AUTH_MECHANISM_SRP:
case AUTH_MECHANISM_LEGACY_PASSWORD:
srp_user_delete((SRPUser *) m_auth_data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the code has no spaces between the cast and the expression being casted.

m_auth_data = NULL;
break;
case AUTH_MECHANISM_NONE:
break;
}
}


AuthMechanism Client::choseAuthMech(const u32 mechs)
{
if (mechs & AUTH_MECHANISM_SRP)
return AUTH_MECHANISM_SRP;

if (mechs & AUTH_MECHANISM_FIRST_SRP)
return AUTH_MECHANISM_FIRST_SRP;

if (mechs & AUTH_MECHANISM_LEGACY_PASSWORD)
return AUTH_MECHANISM_LEGACY_PASSWORD;

return AUTH_MECHANISM_NONE;
}

void Client::sendLegacyInit(const char* playerName, const char* playerPassword)
{
NetworkPacket pkt(TOSERVER_INIT_LEGACY,
Expand All @@ -956,6 +996,70 @@ void Client::sendLegacyInit(const char* playerName, const char* playerPassword)
Send(&pkt);
}

void Client::sendInit(const std::string &playerName)
{
NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size()));

// TODO (later) actually send supported compression modes
pkt << (u8) SER_FMT_VER_HIGHEST_READ << (u8) 42;
pkt << (u16) CLIENT_PROTOCOL_VERSION_MIN << (u16) CLIENT_PROTOCOL_VERSION_MAX;
pkt << playerName;

Send(&pkt);
}

void Client::startAuth(AuthMechanism chosen_auth_mechanism)
{
m_chosen_auth_mech = chosen_auth_mechanism;

switch (chosen_auth_mechanism) {
case AUTH_MECHANISM_FIRST_SRP: {
// send srp verifier to server
NetworkPacket resp_pkt(TOSERVER_FIRST_SRP, 0);
char *salt, *bytes_v;
std::size_t len_salt, len_v;
salt = NULL;
getSRPVerifier(getPlayerName(), m_password,
&salt, &len_salt, &bytes_v, &len_v);
resp_pkt
<< std::string((char*)salt, len_salt)
<< std::string((char*)bytes_v, len_v)
<< (u8)((m_password == "") ? 1 : 0);
free(salt);
free(bytes_v);
Send(&resp_pkt);
break;
}
case AUTH_MECHANISM_SRP:
case AUTH_MECHANISM_LEGACY_PASSWORD: {
u8 based_on = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does based_on do and why is it = 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consult networkprotocol.h. It includes documentation of all packets ever used by minetest.


if (chosen_auth_mechanism == AUTH_MECHANISM_LEGACY_PASSWORD) {
m_password = translatePassword(getPlayerName(), m_password);
based_on = 0;
}

std::string playername_u = lowercase(getPlayerName());
m_auth_data = srp_user_new(SRP_SHA256, SRP_NG_2048,
getPlayerName().c_str(), playername_u.c_str(),
(const unsigned char *) m_password.c_str(),
m_password.length(), NULL, NULL);
char *bytes_A = 0;
size_t len_A = 0;
srp_user_start_authentication((struct SRPUser *) m_auth_data,
NULL, NULL, 0, (unsigned char **) &bytes_A, &len_A);

NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_A, 0);
resp_pkt << std::string(bytes_A, len_A) << based_on;
free(bytes_A);
Send(&resp_pkt);
break;
}
case AUTH_MECHANISM_NONE:
break; // not handled in this method
}
}

void Client::sendDeletedBlocks(std::vector<v3s16> &blocks)
{
NetworkPacket pkt(TOSERVER_DELETEDBLOCKS, 1 + sizeof(v3s16) * blocks.size());
Expand Down Expand Up @@ -1066,24 +1170,30 @@ void Client::sendChangePassword(const std::string &oldpassword,
const std::string &newpassword)
{
Player *player = m_env.getLocalPlayer();
if(player == NULL)
if (player == NULL)
return;

std::string playername = player->getName();
std::string oldpwd = translatePassword(playername, oldpassword);
std::string newpwd = translatePassword(playername, newpassword);
if (m_proto_ver >= 25) {
// get into sudo mode and then send new password to server
m_password = oldpassword;
m_new_password = newpassword;
startAuth(choseAuthMech(m_sudo_auth_methods));
} else {
std::string oldpwd = translatePassword(playername, oldpassword);
std::string newpwd = translatePassword(playername, newpassword);

NetworkPacket pkt(TOSERVER_PASSWORD_LEGACY, 2 * PASSWORD_SIZE);
NetworkPacket pkt(TOSERVER_PASSWORD_LEGACY, 2 * PASSWORD_SIZE);

for(u8 i = 0; i < PASSWORD_SIZE; i++) {
pkt << (u8) (i < oldpwd.length() ? oldpwd[i] : 0);
}
for (u8 i = 0; i < PASSWORD_SIZE; i++) {
pkt << (u8) (i < oldpwd.length() ? oldpwd[i] : 0);
}

for(u8 i = 0; i < PASSWORD_SIZE; i++) {
pkt << (u8) (i < newpwd.length() ? newpwd[i] : 0);
for (u8 i = 0; i < PASSWORD_SIZE; i++) {
pkt << (u8) (i < newpwd.length() ? newpwd[i] : 0);
}
Send(&pkt);
}

Send(&pkt);
}


Expand Down
29 changes: 29 additions & 0 deletions src/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
void handleCommand_Deprecated(NetworkPacket* pkt);
void handleCommand_Hello(NetworkPacket* pkt);
void handleCommand_AuthAccept(NetworkPacket* pkt);
void handleCommand_AcceptSudoMode(NetworkPacket* pkt);
void handleCommand_DenySudoMode(NetworkPacket* pkt);
void handleCommand_InitLegacy(NetworkPacket* pkt);
void handleCommand_AccessDenied(NetworkPacket* pkt);
void handleCommand_RemoveNode(NetworkPacket* pkt);
Expand Down Expand Up @@ -391,6 +393,7 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
void handleCommand_OverrideDayNightRatio(NetworkPacket* pkt);
void handleCommand_LocalPlayerAnimations(NetworkPacket* pkt);
void handleCommand_EyeOffset(NetworkPacket* pkt);
void handleCommand_SrpBytesSandB(NetworkPacket* pkt);

void ProcessData(NetworkPacket *pkt);

Expand Down Expand Up @@ -542,11 +545,21 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
// Send the item number 'item' as player item to the server
void sendPlayerItem(u16 item);

void deleteAuthData();
// helper method shared with clientpackethandler
static AuthMechanism choseAuthMech(const u32 mechs);

void sendLegacyInit(const char* playerName, const char* playerPassword);
void sendInit(const std::string &playerName);
void startAuth(AuthMechanism chosen_auth_mechanism);
void sendDeletedBlocks(std::vector<v3s16> &blocks);
void sendGotBlocks(v3s16 block);
void sendRemovedSounds(std::vector<s32> &soundList);

// Helper function
inline std::string getPlayerName()
{ return m_env.getLocalPlayer()->getName(); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be something more like getLocalPlayerName to be more descriptive??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think both are ok, but I'll change it, as it makes searching easier.


float m_packetcounter_timer;
float m_connection_reinit_timer;
float m_avg_rtt_timer;
Expand All @@ -569,6 +582,8 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
IrrlichtDevice *m_device;
// Server serialization version
u8 m_server_ser_ver;
// Used version of the protocol with server
u8 m_proto_ver;
u16 m_playeritem;
bool m_inventory_updated;
Inventory *m_inventory_from_server;
Expand All @@ -584,9 +599,23 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
//s32 m_daynight_i;
//u32 m_daynight_ratio;
std::queue<std::wstring> m_chat_queue;

// The authentication methods we can use to enter sudo mode (=change password)
u32 m_sudo_auth_methods;

// The seed returned by the server in TOCLIENT_INIT is stored here
u64 m_map_seed;

// Auth data
std::string m_playername;
std::string m_password;
// If set, this will be sent (and cleared) upon a TOCLIENT_ACCEPT_SUDO_MODE
std::string m_new_password;
// Usable by auth mechanisms.
AuthMechanism m_chosen_auth_mech;
void * m_auth_data;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would've personally implemented this a bit differently. Here we have a decent case for making AuthMechanism its own virtual base class (read: interface) with each auth mechanism an implementation of this. It would store the SRPData or whatever inside of this object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could move some things there, but not all. auth_data of course, and m_authstate, but packet handlers better stay in their files. I don't know of any methods that would fit there, except for initialisation and deinitialisation.



bool m_access_denied;
std::string m_access_denied_reason;
std::queue<ClientEvent> m_client_event_queue;
Expand Down
2 changes: 1 addition & 1 deletion src/client/clientlauncher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
else
playername = menudata.name;

password = translatePassword(playername, menudata.password);
password = menudata.password;

g_settings->set("name", playername);

Expand Down
63 changes: 58 additions & 5 deletions src/clientiface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "emerge.h"
#include "serverobject.h" // TODO this is used for cleanup of only
#include "log.h"
#include "util/srp.h"

const char *ClientInterface::statenames[] = {
"Invalid",
Expand Down Expand Up @@ -427,10 +428,12 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
//intentionally do nothing
break;
case CS_Created:
switch(event)
{
case CSE_Init:
m_state = CS_InitSent;
switch (event) {
case CSE_Hello:
m_state = CS_HelloSent;
break;
case CSE_InitLegacy:
m_state = CS_AwaitingInit2;
break;
case CSE_Disconnect:
m_state = CS_Disconnecting;
Expand All @@ -447,7 +450,32 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
case CS_Denied:
/* don't do anything if in denied state */
break;
case CS_InitSent:
case CS_HelloSent:
switch(event)
{
case CSE_AuthAccept:
m_state = CS_AwaitingInit2;
if ((chosen_mech == AUTH_MECHANISM_SRP)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I question if details such as authentication choosing and deleting the verifier should be here in this state transition function, or elsewhere

|| (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
srp_verifier_delete((SRPVerifier *) auth_data);
chosen_mech = AUTH_MECHANISM_NONE;
break;
case CSE_Disconnect:
m_state = CS_Disconnecting;
break;
case CSE_SetDenied:
m_state = CS_Denied;
if ((chosen_mech == AUTH_MECHANISM_SRP)
|| (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
srp_verifier_delete((SRPVerifier *) auth_data);
chosen_mech = AUTH_MECHANISM_NONE;
break;
default:
myerror << "HelloSent: Invalid client state transition! " << event;
throw ClientStateError(myerror.str());
}
break;
case CS_AwaitingInit2:
switch(event)
{
case CSE_GotInit2:
Expand Down Expand Up @@ -514,13 +542,38 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
case CSE_Disconnect:
m_state = CS_Disconnecting;
break;
case CSE_SudoSuccess:
m_state = CS_SudoMode;
if ((chosen_mech == AUTH_MECHANISM_SRP)
|| (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
srp_verifier_delete((SRPVerifier *) auth_data);
chosen_mech = AUTH_MECHANISM_NONE;
break;
/* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
default:
myerror << "Active: Invalid client state transition! " << event;
throw ClientStateError(myerror.str());
break;
}
break;
case CS_SudoMode:
switch(event)
{
case CSE_SetDenied:
m_state = CS_Denied;
break;
case CSE_Disconnect:
m_state = CS_Disconnecting;
break;
case CSE_SudoLeave:
m_state = CS_Active;
break;
default:
myerror << "Active: Invalid client state transition! " << event;
throw ClientStateError(myerror.str());
break;
}
break;
case CS_Disconnecting:
/* we are already disconnecting */
break;
Expand Down
230 changes: 136 additions & 94 deletions src/clientiface.h

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/cmake_config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#cmakedefine01 USE_FREETYPE
#cmakedefine01 USE_LEVELDB
#cmakedefine01 USE_LUAJIT
#cmakedefine01 USE_SYSTEM_GMP
#cmakedefine01 USE_REDIS
#cmakedefine01 HAVE_ENDIAN_H

Expand Down
4 changes: 4 additions & 0 deletions src/gmp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
add_library(gmp mini-gmp.c)

target_link_libraries(gmp)

4,130 changes: 4,130 additions & 0 deletions src/gmp/mini-gmp.c

Large diffs are not rendered by default.

256 changes: 256 additions & 0 deletions src/gmp/mini-gmp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
/* mini-gmp, a minimalistic implementation of a GNU GMP subset.
Copyright 2011, 2012, 2013 Free Software Foundation, Inc.
This file is part of the GNU MP Library.
The GNU MP Library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
The GNU MP Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */

/* About mini-gmp: This is a minimal implementation of a subset of the
GMP interface. It is intended for inclusion into applications which
have modest bignums needs, as a fallback when the real GMP library
is not installed.
This file defines the public interface. */

#ifndef __MINI_GMP_H__
#define __MINI_GMP_H__

/* For size_t */
#include <stddef.h>

#if defined (__cplusplus)
extern "C" {
#endif

void mp_set_memory_functions (void *(*) (size_t),
void *(*) (void *, size_t, size_t),
void (*) (void *, size_t));

void mp_get_memory_functions (void *(**) (size_t),
void *(**) (void *, size_t, size_t),
void (**) (void *, size_t));

typedef unsigned long mp_limb_t;
typedef long mp_size_t;
typedef unsigned long mp_bitcnt_t;

typedef mp_limb_t *mp_ptr;
typedef const mp_limb_t *mp_srcptr;

typedef struct
{
int _mp_alloc; /* Number of *limbs* allocated and pointed
to by the _mp_d field. */
int _mp_size; /* abs(_mp_size) is the number of limbs the
last field points to. If _mp_size is
negative this is a negative number. */
mp_limb_t *_mp_d; /* Pointer to the limbs. */
} __mpz_struct;

typedef __mpz_struct mpz_t[1];

typedef __mpz_struct *mpz_ptr;
typedef const __mpz_struct *mpz_srcptr;

void mpn_copyi (mp_ptr, mp_srcptr, mp_size_t);
void mpn_copyd (mp_ptr, mp_srcptr, mp_size_t);

int mpn_cmp (mp_srcptr, mp_srcptr, mp_size_t);

mp_limb_t mpn_add_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_add_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
mp_limb_t mpn_add (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);

mp_limb_t mpn_sub_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_sub_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
mp_limb_t mpn_sub (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);

mp_limb_t mpn_mul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_addmul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);
mp_limb_t mpn_submul_1 (mp_ptr, mp_srcptr, mp_size_t, mp_limb_t);

mp_limb_t mpn_mul (mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t);
void mpn_mul_n (mp_ptr, mp_srcptr, mp_srcptr, mp_size_t);
void mpn_sqr (mp_ptr, mp_srcptr, mp_size_t);

mp_limb_t mpn_lshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);
mp_limb_t mpn_rshift (mp_ptr, mp_srcptr, mp_size_t, unsigned int);

mp_limb_t mpn_invert_3by2 (mp_limb_t, mp_limb_t);
#define mpn_invert_limb(x) mpn_invert_3by2 ((x), 0)

size_t mpn_get_str (unsigned char *, int, mp_ptr, mp_size_t);
mp_size_t mpn_set_str (mp_ptr, const unsigned char *, size_t, int);

void mpz_init (mpz_t);
void mpz_init2 (mpz_t, mp_bitcnt_t);
void mpz_clear (mpz_t);

#define mpz_odd_p(z) (((z)->_mp_size != 0) & (int) (z)->_mp_d[0])
#define mpz_even_p(z) (! mpz_odd_p (z))

int mpz_sgn (const mpz_t);
int mpz_cmp_si (const mpz_t, long);
int mpz_cmp_ui (const mpz_t, unsigned long);
int mpz_cmp (const mpz_t, const mpz_t);
int mpz_cmpabs_ui (const mpz_t, unsigned long);
int mpz_cmpabs (const mpz_t, const mpz_t);
int mpz_cmp_d (const mpz_t, double);
int mpz_cmpabs_d (const mpz_t, double);

void mpz_abs (mpz_t, const mpz_t);
void mpz_neg (mpz_t, const mpz_t);
void mpz_swap (mpz_t, mpz_t);

void mpz_add_ui (mpz_t, const mpz_t, unsigned long);
void mpz_add (mpz_t, const mpz_t, const mpz_t);
void mpz_sub_ui (mpz_t, const mpz_t, unsigned long);
void mpz_ui_sub (mpz_t, unsigned long, const mpz_t);
void mpz_sub (mpz_t, const mpz_t, const mpz_t);

void mpz_mul_si (mpz_t, const mpz_t, long int);
void mpz_mul_ui (mpz_t, const mpz_t, unsigned long int);
void mpz_mul (mpz_t, const mpz_t, const mpz_t);
void mpz_mul_2exp (mpz_t, const mpz_t, mp_bitcnt_t);

void mpz_cdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_fdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_tdiv_qr (mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_cdiv_q (mpz_t, const mpz_t, const mpz_t);
void mpz_fdiv_q (mpz_t, const mpz_t, const mpz_t);
void mpz_tdiv_q (mpz_t, const mpz_t, const mpz_t);
void mpz_cdiv_r (mpz_t, const mpz_t, const mpz_t);
void mpz_fdiv_r (mpz_t, const mpz_t, const mpz_t);
void mpz_tdiv_r (mpz_t, const mpz_t, const mpz_t);

void mpz_cdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_fdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_tdiv_q_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_cdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_fdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);
void mpz_tdiv_r_2exp (mpz_t, const mpz_t, mp_bitcnt_t);

void mpz_mod (mpz_t, const mpz_t, const mpz_t);

void mpz_divexact (mpz_t, const mpz_t, const mpz_t);

int mpz_divisible_p (const mpz_t, const mpz_t);

unsigned long mpz_cdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
unsigned long mpz_fdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
unsigned long mpz_tdiv_qr_ui (mpz_t, mpz_t, const mpz_t, unsigned long);
unsigned long mpz_cdiv_q_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_fdiv_q_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_tdiv_q_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_cdiv_r_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_fdiv_r_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_tdiv_r_ui (mpz_t, const mpz_t, unsigned long);
unsigned long mpz_cdiv_ui (const mpz_t, unsigned long);
unsigned long mpz_fdiv_ui (const mpz_t, unsigned long);
unsigned long mpz_tdiv_ui (const mpz_t, unsigned long);

unsigned long mpz_mod_ui (mpz_t, const mpz_t, unsigned long);

void mpz_divexact_ui (mpz_t, const mpz_t, unsigned long);

int mpz_divisible_ui_p (const mpz_t, unsigned long);

unsigned long mpz_gcd_ui (mpz_t, const mpz_t, unsigned long);
void mpz_gcd (mpz_t, const mpz_t, const mpz_t);
void mpz_gcdext (mpz_t, mpz_t, mpz_t, const mpz_t, const mpz_t);
void mpz_lcm_ui (mpz_t, const mpz_t, unsigned long);
void mpz_lcm (mpz_t, const mpz_t, const mpz_t);
int mpz_invert (mpz_t, const mpz_t, const mpz_t);

void mpz_sqrtrem (mpz_t, mpz_t, const mpz_t);
void mpz_sqrt (mpz_t, const mpz_t);

void mpz_pow_ui (mpz_t, const mpz_t, unsigned long);
void mpz_ui_pow_ui (mpz_t, unsigned long, unsigned long);
void mpz_powm (mpz_t, const mpz_t, const mpz_t, const mpz_t);
void mpz_powm_ui (mpz_t, const mpz_t, unsigned long, const mpz_t);

void mpz_rootrem (mpz_t, mpz_t, const mpz_t, unsigned long);
int mpz_root (mpz_t, const mpz_t, unsigned long);

void mpz_fac_ui (mpz_t, unsigned long);
void mpz_bin_uiui (mpz_t, unsigned long, unsigned long);

int mpz_tstbit (const mpz_t, mp_bitcnt_t);
void mpz_setbit (mpz_t, mp_bitcnt_t);
void mpz_clrbit (mpz_t, mp_bitcnt_t);
void mpz_combit (mpz_t, mp_bitcnt_t);

void mpz_com (mpz_t, const mpz_t);
void mpz_and (mpz_t, const mpz_t, const mpz_t);
void mpz_ior (mpz_t, const mpz_t, const mpz_t);
void mpz_xor (mpz_t, const mpz_t, const mpz_t);

mp_bitcnt_t mpz_popcount (const mpz_t);
mp_bitcnt_t mpz_hamdist (const mpz_t, const mpz_t);
mp_bitcnt_t mpz_scan0 (const mpz_t, mp_bitcnt_t);
mp_bitcnt_t mpz_scan1 (const mpz_t, mp_bitcnt_t);

int mpz_fits_slong_p (const mpz_t);
int mpz_fits_ulong_p (const mpz_t);
long int mpz_get_si (const mpz_t);
unsigned long int mpz_get_ui (const mpz_t);
double mpz_get_d (const mpz_t);
size_t mpz_size (const mpz_t);
mp_limb_t mpz_getlimbn (const mpz_t, mp_size_t);

void mpz_set_si (mpz_t, signed long int);
void mpz_set_ui (mpz_t, unsigned long int);
void mpz_set (mpz_t, const mpz_t);
void mpz_set_d (mpz_t, double);

void mpz_init_set_si (mpz_t, signed long int);
void mpz_init_set_ui (mpz_t, unsigned long int);
void mpz_init_set (mpz_t, const mpz_t);
void mpz_init_set_d (mpz_t, double);

size_t mpz_sizeinbase (const mpz_t, int);
char *mpz_get_str (char *, int, const mpz_t);
int mpz_set_str (mpz_t, const char *, int);
int mpz_init_set_str (mpz_t, const char *, int);

/* This long list taken from gmp.h. */
/* For reference, "defined(EOF)" cannot be used here. In g++ 2.95.4,
<iostream> defines EOF but not FILE. */
#if defined (FILE) \
|| defined (H_STDIO) \
|| defined (_H_STDIO) /* AIX */ \
|| defined (_STDIO_H) /* glibc, Sun, SCO */ \
|| defined (_STDIO_H_) /* BSD, OSF */ \
|| defined (__STDIO_H) /* Borland */ \
|| defined (__STDIO_H__) /* IRIX */ \
|| defined (_STDIO_INCLUDED) /* HPUX */ \
|| defined (__dj_include_stdio_h_) /* DJGPP */ \
|| defined (_FILE_DEFINED) /* Microsoft */ \
|| defined (__STDIO__) /* Apple MPW MrC */ \
|| defined (_MSL_STDIO_H) /* Metrowerks */ \
|| defined (_STDIO_H_INCLUDED) /* QNX4 */ \
|| defined (_ISO_STDIO_ISO_H) /* Sun C++ */ \
|| defined (__STDIO_LOADED) /* VMS */
size_t mpz_out_str (FILE *, int, const mpz_t);
#endif

void mpz_import (mpz_t, size_t, int, size_t, int, size_t, const void *);
void *mpz_export (void *, size_t *, int, size_t, int, size_t, const mpz_t);

#if defined (__cplusplus)
}
#endif
#endif /* __MINI_GMP_H__ */
38 changes: 33 additions & 5 deletions src/network/clientopcodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
null_command_handler, // 0x01
{ "TOCLIENT_HELLO", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_Hello }, // 0x02
{ "TOCLIENT_AUTH_ACCEPT", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_AuthAccept }, // 0x03
null_command_handler, // 0x04
null_command_handler, // 0x05
{ "TOCLIENT_ACCEPT_SUDO_MODE", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_AcceptSudoMode}, // 0x04
{ "TOCLIENT_DENY_SUDO_MODE", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DenySudoMode}, // 0x05
null_command_handler, // 0x06
null_command_handler, // 0x07
null_command_handler, // 0x08
Expand Down Expand Up @@ -108,6 +108,19 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_LOCAL_PLAYER_ANIMATIONS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_LocalPlayerAnimations }, // 0x51
{ "TOCLIENT_EYE_OFFSET", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_EyeOffset }, // 0x52
{ "TOCLIENT_DELETE_PARTICLESPAWNER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeleteParticleSpawner }, // 0x53
null_command_handler,
null_command_handler,
null_command_handler,
null_command_handler,
null_command_handler,
null_command_handler,
null_command_handler,
null_command_handler,
null_command_handler,
null_command_handler,
null_command_handler,
null_command_handler,
{ "TOCLIENT_SRP_BYTES_S_B", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_SrpBytesSandB }, // 0x60
};

const static ServerCommandFactory null_command_factory = { "TOSERVER_NULL", 0, false };
Expand All @@ -116,7 +129,7 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] =
{
null_command_factory, // 0x00
null_command_factory, // 0x01
null_command_factory, // 0x02
{ "TOSERVER_INIT", 1, false }, // 0x02
null_command_factory, // 0x03
null_command_factory, // 0x04
null_command_factory, // 0x05
Expand All @@ -129,7 +142,7 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] =
null_command_factory, // 0x0c
null_command_factory, // 0x0d
null_command_factory, // 0x0e
{ "TOSERVER_INIT", 1, false }, // 0x0F
null_command_factory, // 0x0F
{ "TOSERVER_INIT_LEGACY", 1, false }, // 0x10
{ "TOSERVER_INIT2", 1, true }, // 0x11
null_command_factory, // 0x12
Expand Down Expand Up @@ -175,11 +188,26 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] =
{ "TOSERVER_REMOVED_SOUNDS", 1, true }, // 0x3a
{ "TOSERVER_NODEMETA_FIELDS", 0, true }, // 0x3b
{ "TOSERVER_INVENTORY_FIELDS", 0, true }, // 0x3c
{ "TOSERVER_PASSWORD", 0, true }, // 0x3d
null_command_factory, // 0x3d
null_command_factory, // 0x3e
null_command_factory, // 0x3f
{ "TOSERVER_REQUEST_MEDIA", 1, true }, // 0x40
{ "TOSERVER_RECEIVED_MEDIA", 1, true }, // 0x41
{ "TOSERVER_BREATH", 0, true }, // 0x42
{ "TOSERVER_CLIENT_READY", 0, true }, // 0x43
null_command_factory, // 0x44
null_command_factory, // 0x45
null_command_factory, // 0x46
null_command_factory, // 0x47
null_command_factory, // 0x48
null_command_factory, // 0x49
null_command_factory, // 0x4a
null_command_factory, // 0x4b
null_command_factory, // 0x4c
null_command_factory, // 0x4d
null_command_factory, // 0x4e
null_command_factory, // 0x4f
{ "TOSERVER_FIRST_SRP", 1, true }, // 0x50
{ "TOSERVER_SRP_BYTES_A", 1, true }, // 0x51
{ "TOSERVER_SRP_BYTES_M", 1, true }, // 0x52
};
99 changes: 95 additions & 4 deletions src/network/clientpackethandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "strfnd.h"
#include "network/clientopcodes.h"
#include "util/serialize.h"
#include "util/srp.h"

void Client::handleCommand_Deprecated(NetworkPacket* pkt)
{
Expand All @@ -44,10 +45,16 @@ void Client::handleCommand_Hello(NetworkPacket* pkt)
return;

u8 deployed;
*pkt >> deployed;
u32 auth_mechs;
std::string username_legacy; // for case insensitivity
*pkt >> deployed >> auth_mechs >> username_legacy;

// Chose an auth method we support
AuthMechanism chosen_auth_mechanism = choseAuthMech(auth_mechs);

infostream << "Client: TOCLIENT_HELLO received with "
"deployed=" << ((int)deployed & 0xff) << std::endl;
"deployed=" << ((int)deployed & 0xff) << ", auth_mechs="
<< auth_mechs << ", chosen=" << chosen_auth_mechanism << std::endl;

if (!ser_ver_supported(deployed)) {
infostream << "Client: TOCLIENT_HELLO: Server sent "
Expand All @@ -56,14 +63,43 @@ void Client::handleCommand_Hello(NetworkPacket* pkt)
}

m_server_ser_ver = deployed;
m_proto_ver = deployed;

//TODO verify that username_legacy matches sent username, only
// differs in casing (make both uppercase and compare)
// This is only neccessary though when we actually want to add casing support

if (m_chosen_auth_mech != AUTH_MECHANISM_NONE) {
// we recieved a TOCLIENT_HELLO while auth was already going on
errorstream << "Client: TOCLIENT_HELLO while auth was already going on"
<< "(chosen_mech=" << m_chosen_auth_mech << ")." << std::endl;
if ((m_chosen_auth_mech == AUTH_MECHANISM_SRP)
|| (m_chosen_auth_mech == AUTH_MECHANISM_LEGACY_PASSWORD)) {
srp_user_delete((SRPUser *) m_auth_data);
m_auth_data = 0;
}
}

// Authenticate using that method, or abort if there wasn't any method found
if (chosen_auth_mechanism != AUTH_MECHANISM_NONE) {
startAuth(chosen_auth_mechanism);
} else {
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
m_access_denied = true;
m_access_denied_reason = "Unknown";
m_con.Disconnect();
}

// @ TODO auth to server
}

void Client::handleCommand_AuthAccept(NetworkPacket* pkt)
{
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
deleteAuthData();

v3f playerpos;
*pkt >> playerpos >> m_map_seed >> m_recommended_send_interval;
*pkt >> playerpos >> m_map_seed >> m_recommended_send_interval
>> m_sudo_auth_methods;

playerpos -= v3f(0, BS / 2, 0);

Expand All @@ -82,7 +118,28 @@ void Client::handleCommand_AuthAccept(NetworkPacket* pkt)

m_state = LC_Init;
}
void Client::handleCommand_AcceptSudoMode(NetworkPacket* pkt)
{
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
deleteAuthData();

m_password = m_new_password;

verbosestream << "Client: Recieved TOCLIENT_ACCEPT_SUDO_MODE." << std::endl;

// send packet to actually set the password
startAuth(AUTH_MECHANISM_FIRST_SRP);

// reset again
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
}
void Client::handleCommand_DenySudoMode(NetworkPacket* pkt)
{
m_chat_queue.push(L"Password change denied. Password NOT changed.");
// reset everything and be sad
deleteAuthData();
m_chosen_auth_mech = AUTH_MECHANISM_NONE;
}
void Client::handleCommand_InitLegacy(NetworkPacket* pkt)
{
if (pkt->getSize() < 1)
Expand All @@ -101,6 +158,7 @@ void Client::handleCommand_InitLegacy(NetworkPacket* pkt)
}

m_server_ser_ver = deployed;
m_proto_ver = deployed;

// Get player position
v3s16 playerpos_s16(0, BS * 2 + BS * 20, 0);
Expand Down Expand Up @@ -1105,3 +1163,36 @@ void Client::handleCommand_EyeOffset(NetworkPacket* pkt)

*pkt >> player->eye_offset_first >> player->eye_offset_third;
}

void Client::handleCommand_SrpBytesSandB(NetworkPacket* pkt)
{
if ((m_chosen_auth_mech != AUTH_MECHANISM_LEGACY_PASSWORD)
&& (m_chosen_auth_mech != AUTH_MECHANISM_SRP)) {
errorstream << "Client: Recieved SRP S_B login message,"
<< " but wasn't supposed to (chosen_mech="
<< m_chosen_auth_mech << ")." << std::endl;
return;
}

char *bytes_M = 0;
size_t len_M = 0;
SRPUser *usr = (SRPUser *) m_auth_data;
std::string s;
std::string B;
*pkt >> s >> B;

infostream << "Client: Recieved TOCLIENT_SRP_BYTES_S_B." << std::endl;

srp_user_process_challenge(usr, (const unsigned char *) s.c_str(), s.size(),
(const unsigned char *) B.c_str(), B.size(),
(unsigned char **) &bytes_M, &len_M);

if ( !bytes_M ) {
errorstream << "Client: SRP-6a S_B safety check violation!" << std::endl;
return;
}

NetworkPacket resp_pkt(TOSERVER_SRP_BYTES_M, 0);
resp_pkt << std::string(bytes_M, len_M);
Send(&resp_pkt);
}
4 changes: 3 additions & 1 deletion src/network/networkpacket.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ class NetworkPacket
u16 getPeerId() { return m_peer_id; }
u16 getCommand() { return m_command; }

// Data extractors
// Returns a c-string without copying.
// A better name for this would be getRawString()
char* getString(u32 from_offset);
// major difference to putCString(): doesn't write len into the buffer
void putRawString(const char* src, u32 len);

NetworkPacket& operator>>(std::string& dst);
Expand Down
120 changes: 90 additions & 30 deletions src/network/networkprotocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
permit translation
Add TOCLIENT_DELETE_PARTICLESPAWNER (0x53), fixing the u16 read and
reading u32
Add TOSERVER_INIT new opcode (0x02) for client presentation to server
Add TOSERVER_AUTH new opcode (0x03) for client authentication
Add new opcode TOSERVER_INIT for client presentation to server
Add new opcodes TOSERVER_FIRST_SRP, TOSERVER_SRP_BYTES_A,
TOSERVER_SRP_BYTES_M, TOCLIENT_SRP_BYTES_S_B
for the three supported auth mechanisms around srp
Add new opcodes TOCLIENT_ACCEPT_SUDO_MODE and TOCLIENT_DENY_SUDO_MODE
for sudo mode handling (auth mech generic way of changing password).
Add TOCLIENT_HELLO for presenting server to client after client
presentation
Add TOCLIENT_AUTH_ACCEPT to accept connexion from client
Add TOCLIENT_AUTH_ACCEPT to accept connection from client
*/

#define LATEST_PROTOCOL_VERSION 24
Expand All @@ -151,14 +155,31 @@ with this program; if not, write to the Free Software Foundation, Inc.,
enum ToClientCommand
{
TOCLIENT_HELLO = 0x02,
TOCLIENT_AUTH_ACCEPT = 0x03,
TOCLIENT_ACCESS_DENIED = 0x0A,
/*
u16 command
u16 reason_length
wstring reason
Sent after TOSERVER_INIT.
u8 deployed version
u32 supported auth methods
std::string username that should be used for legacy hash (for proper casing)
*/
TOCLIENT_AUTH_ACCEPT = 0x03,
/*
Message from server to accept auth.
v3s16 player's position + v3f(0,BS/2,0) floatToInt'd
u64 map seed
f1000 recommended send interval
u32 : supported auth methods for sudo mode
(where the user can change their password)
*/
TOCLIENT_ACCEPT_SUDO_MODE = 0x04,
/*
Sent to client to show it is in sudo mode now.
*/
TOCLIENT_DENY_SUDO_MODE = 0x05,
/*
Signals client that sudo mode auth failed.
*/
TOCLIENT_INIT_LEGACY = 0x10,
/*
Server's reply to TOSERVER_INIT.
Expand All @@ -173,7 +194,11 @@ enum ToClientCommand
NOTE: The position in here is deprecated; position is
explicitly sent afterwards
*/

TOCLIENT_ACCESS_DENIED = 0x0A,
/*
u8 reason
std::string custom reason (if reason == SERVER_ACCESSDENIED_CUSTOM_STRING)
*/
TOCLIENT_BLOCKDATA = 0x20, //TODO: Multiple blocks
TOCLIENT_ADDNODE = 0x21,
/*
Expand Down Expand Up @@ -589,7 +614,16 @@ enum ToClientCommand
u32 id
*/

TOCLIENT_NUM_MSG_TYPES = 0x54,
TOCLIENT_SRP_BYTES_S_B = 0x60,
/*
Belonging to AUTH_MECHANISM_LEGACY_PASSWORD and AUTH_MECHANISM_SRP.
u16 command
std::string bytes_s
std::string bytes_B
*/

TOCLIENT_NUM_MSG_TYPES = 0x61,
};

enum ToServerCommand
Expand All @@ -598,18 +632,11 @@ enum ToServerCommand
/*
Sent first after connected.
[0] u16 TOSERVER_INIT
[2] u8 SER_FMT_VER_HIGHEST_READ
[3] u8 compression_modes
*/

TOSERVER_AUTH = 0x03,
/*
Sent first after presentation (INIT).
[0] std::string player_name
[0+*] std::string password (new in some version)
[0+*+*] u16 minimum supported network protocol version (added sometime)
[0+*+*+2] u16 maximum supported network protocol version (added later than the previous one)
[4] u16 minimum supported network protocol version
[6] u16 maximum supported network protocol version
[8] std::string player name
*/

TOSERVER_INIT_LEGACY = 0x10,
Expand Down Expand Up @@ -817,15 +844,6 @@ enum ToServerCommand
u8[len] field value
*/

TOSERVER_PASSWORD = 0x3d,
/*
Sent to change password.
[0] u16 TOSERVER_PASSWORD
[2] std::string old password
[2+*] std::string new password
*/

TOSERVER_REQUEST_MEDIA = 0x40,
/*
u16 command
Expand Down Expand Up @@ -857,7 +875,49 @@ enum ToServerCommand
u8[len] full_version_string
*/

TOSERVER_NUM_MSG_TYPES = 0x44,
TOSERVER_FIRST_SRP = 0x50,
/*
Belonging to AUTH_MECHANISM_FIRST_SRP.
std::string srp salt
std::string srp verification key
u8 is_empty (=1 if password is empty, 0 otherwise)
*/

TOSERVER_SRP_BYTES_A = 0x51,
/*
Belonging to AUTH_MECHANISM_LEGACY_PASSWORD and AUTH_MECHANISM_SRP,
depending on current_login_based_on.
std::string bytes_A
u8 current_login_based_on : on which version of the password's
hash this login is based on (0 legacy hash,
or 1 directly the password)
*/

TOSERVER_SRP_BYTES_M = 0x52,
/*
Belonging to AUTH_MECHANISM_LEGACY_PASSWORD and AUTH_MECHANISM_SRP.
std::string bytes_M
*/

TOSERVER_NUM_MSG_TYPES = 0x53,
};

enum AuthMechanism
{
// reserved
AUTH_MECHANISM_NONE = 0,

// SRP based on the legacy hash
AUTH_MECHANISM_LEGACY_PASSWORD = 1 << 0,

// SRP based on the srp verification key
AUTH_MECHANISM_SRP = 1 << 1,

// Establishes a srp verification key, for first login and password changing
AUTH_MECHANISM_FIRST_SRP = 1 << 2,
};

enum AccessDeniedCode {
Expand Down
40 changes: 34 additions & 6 deletions src/network/serveropcodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] =
{
null_command_handler, // 0x00 (never use this)
null_command_handler, // 0x01
{ "TOSERVER_INIT", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_Init }, // 0x02
{ "TOSERVER_AUTH", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_Auth }, // 0x03
{ "TOSERVER_INIT", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_Init }, // 0x02
null_command_handler, // 0x03
null_command_handler, // 0x04
null_command_handler, // 0x05
null_command_handler, // 0x06
Expand Down Expand Up @@ -85,13 +85,28 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] =
{ "TOSERVER_REMOVED_SOUNDS", TOSERVER_STATE_INGAME, &Server::handleCommand_RemovedSounds }, // 0x3a
{ "TOSERVER_NODEMETA_FIELDS", TOSERVER_STATE_INGAME, &Server::handleCommand_NodeMetaFields }, // 0x3b
{ "TOSERVER_INVENTORY_FIELDS", TOSERVER_STATE_INGAME, &Server::handleCommand_InventoryFields }, // 0x3c
{ "TOSERVER_PASSWORD", TOSERVER_STATE_INGAME, &Server::handleCommand_Password }, // 0x3d
null_command_handler, // 0x3d
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't remove for compat

null_command_handler, // 0x3e
null_command_handler, // 0x3f
{ "TOSERVER_REQUEST_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_RequestMedia }, // 0x40
{ "TOSERVER_RECEIVED_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_ReceivedMedia }, // 0x41
{ "TOSERVER_BREATH", TOSERVER_STATE_INGAME, &Server::handleCommand_Breath }, // 0x42
{ "TOSERVER_CLIENT_READY", TOSERVER_STATE_STARTUP, &Server::handleCommand_ClientReady }, // 0x43
null_command_handler, // 0x44
null_command_handler, // 0x45
null_command_handler, // 0x46
null_command_handler, // 0x47
null_command_handler, // 0x48
null_command_handler, // 0x49
null_command_handler, // 0x4a
null_command_handler, // 0x4b
null_command_handler, // 0x4c
null_command_handler, // 0x4d
null_command_handler, // 0x4e
null_command_handler, // 0x4f
{ "TOSERVER_FIRST_SRP", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_FirstSrp }, // 0x50
{ "TOSERVER_SRP_BYTES_A", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_SrpBytesA }, // 0x51
{ "TOSERVER_SRP_BYTES_M", TOSERVER_STATE_NOT_CONNECTED, &Server::handleCommand_SrpBytesM }, // 0x52
};

const static ClientCommandFactory null_command_factory = { "TOCLIENT_NULL", 0, false };
Expand All @@ -100,10 +115,10 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
{
null_command_factory, // 0x00
null_command_factory, // 0x01
{ "TOCLIENT_HELLO", 0, true }, // 0x02
null_command_factory, // 0x02
{ "TOCLIENT_AUTH_ACCEPT", 0, true }, // 0x03
null_command_factory, // 0x04
null_command_factory, // 0x05
{ "TOCLIENT_ACCEPT_SUDO_MODE", 0, true }, // 0x04
{ "TOCLIENT_DENY_SUDO_MODE", 0, true }, // 0x05
null_command_factory, // 0x06
null_command_factory, // 0x07
null_command_factory, // 0x08
Expand Down Expand Up @@ -182,4 +197,17 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] =
{ "TOCLIENT_LOCAL_PLAYER_ANIMATIONS", 0, true }, // 0x51
{ "TOCLIENT_EYE_OFFSET", 0, true }, // 0x52
{ "TOCLIENT_DELETE_PARTICLESPAWNER", 0, true }, // 0x53
null_command_factory,
null_command_factory,
null_command_factory,
null_command_factory,
null_command_factory,
null_command_factory,
null_command_factory,
null_command_factory,
null_command_factory,
null_command_factory,
null_command_factory,
null_command_factory,
{ "TOSERVER_SRP_BYTES_S_B", 0, true }, // 0x60
};
472 changes: 348 additions & 124 deletions src/network/serverpackethandler.cpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/script/lua_api/l_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "tool.h"
#include "filesys.h"
#include "settings.h"
#include "util/auth.h"

// debug(...)
// Writes a line to dstream
Expand Down
38 changes: 38 additions & 0 deletions src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2537,6 +2537,13 @@ void Server::RespawnPlayer(u16 peer_id)
playersao->setPos(pos);
}
}
void Server::DenySudoAccess(u16 peer_id)
{
DSTACK(__FUNCTION_NAME);

NetworkPacket pkt(TOCLIENT_DENY_SUDO_MODE, 0, peer_id);
Send(&pkt);
}

void Server::DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason)
{
Expand All @@ -2558,6 +2565,37 @@ void Server::DenyAccess_Legacy(u16 peer_id, const std::wstring &reason)
m_con.DisconnectPeer(peer_id);
}

void Server::acceptAuth(u16 peer_id, bool forSudoMode)
{
DSTACK(__FUNCTION_NAME);

if (!forSudoMode) {
RemoteClient* client = getClient(peer_id, CS_Invalid);

NetworkPacket resp_pkt(TOCLIENT_AUTH_ACCEPT, 1 + 6 + 8 + 4, peer_id);

// Right now, the auth mechs don't change between login and sudo mode.
u32 sudo_auth_mechs = client->allowed_auth_mechs;
client->allowed_sudo_mechs = sudo_auth_mechs;

resp_pkt << v3f(0,0,0) << (u64) m_env->getServerMap().getSeed()
<< g_settings->getFloat("dedicated_server_step")
<< sudo_auth_mechs;

Send(&resp_pkt);
m_clients.event(peer_id, CSE_AuthAccept);
} else {
NetworkPacket resp_pkt(TOCLIENT_ACCEPT_SUDO_MODE, 1 + 6 + 8 + 4, peer_id);

// We only support SRP right now
u32 sudo_auth_mechs = AUTH_MECHANISM_FIRST_SRP;

resp_pkt << sudo_auth_mechs;
Send(&resp_pkt);
m_clients.event(peer_id, CSE_SudoSuccess);
}
}

void Server::DeleteClient(u16 peer_id, ClientDeletionReason reason)
{
DSTACK(__FUNCTION_NAME);
Expand Down
6 changes: 5 additions & 1 deletion src/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ class Server : public con::PeerHandler, public MapEventReceiver,
void handleCommand_Null(NetworkPacket* pkt) {};
void handleCommand_Deprecated(NetworkPacket* pkt);
void handleCommand_Init(NetworkPacket* pkt);
void handleCommand_Auth(NetworkPacket* pkt);
void handleCommand_Init_Legacy(NetworkPacket* pkt);
void handleCommand_Init2(NetworkPacket* pkt);
void handleCommand_RequestMedia(NetworkPacket* pkt);
Expand All @@ -213,6 +212,9 @@ class Server : public con::PeerHandler, public MapEventReceiver,
void handleCommand_RemovedSounds(NetworkPacket* pkt);
void handleCommand_NodeMetaFields(NetworkPacket* pkt);
void handleCommand_InventoryFields(NetworkPacket* pkt);
void handleCommand_FirstSrp(NetworkPacket* pkt);
void handleCommand_SrpBytesA(NetworkPacket* pkt);
void handleCommand_SrpBytesM(NetworkPacket* pkt);

void ProcessData(NetworkPacket *pkt);

Expand Down Expand Up @@ -360,7 +362,9 @@ class Server : public con::PeerHandler, public MapEventReceiver,
void peerAdded(con::Peer *peer);
void deletingPeer(con::Peer *peer, bool timeout);

void DenySudoAccess(u16 peer_id);
void DenyAccess(u16 peer_id, AccessDeniedCode reason, const std::string &custom_reason="");
void acceptAuth(u16 peer_id, bool forSudoMode);
void DenyAccess_Legacy(u16 peer_id, const std::wstring &reason);
bool getClientConInfo(u16 peer_id, con::rtt_stat_type type,float* retval);
bool getClientInfo(u16 peer_id,ClientState* state, u32* uptime,
Expand Down
3 changes: 3 additions & 0 deletions src/util/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
set(UTIL_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/auth.cpp
${CMAKE_CURRENT_SOURCE_DIR}/base64.cpp
${CMAKE_CURRENT_SOURCE_DIR}/directiontables.cpp
${CMAKE_CURRENT_SOURCE_DIR}/numeric.cpp
${CMAKE_CURRENT_SOURCE_DIR}/pointedthing.cpp
${CMAKE_CURRENT_SOURCE_DIR}/serialize.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sha1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/sha256.c
${CMAKE_CURRENT_SOURCE_DIR}/string.cpp
${CMAKE_CURRENT_SOURCE_DIR}/srp.cpp
${CMAKE_CURRENT_SOURCE_DIR}/timetaker.cpp
PARENT_SCOPE)

126 changes: 126 additions & 0 deletions src/util/auth.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
Minetest
Copyright (C) 2015 est31 <MTest31@outlook.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <algorithm>
#include <string>
#include "auth.h"
#include "base64.h"
#include "sha1.h"
#include "srp.h"
#include "string.h"

// Get an sha-1 hash of the player's name combined with
// the password entered. That's what the server uses as
// their password. (Exception : if the password field is
// blank, we send a blank password - this is for backwards
// compatibility with password-less players).
std::string translatePassword(const std::string &name,
const std::string &password)
{
if (password.length() == 0)
return "";

std::string slt = name + password;
SHA1 sha1;
sha1.addBytes(slt.c_str(), slt.length());
unsigned char *digest = sha1.getDigest();
std::string pwd = base64_encode(digest, 20);
free(digest);
return pwd;
}

void getSRPVerifier(const std::string &name,
const std::string &password, char **salt, size_t *salt_len,
char **bytes_v, size_t *len_v)
{
std::string n_name = lowercase(name);
srp_create_salted_verification_key(SRP_SHA256, SRP_NG_2048,
n_name.c_str(), (const unsigned char *)password.c_str(),
password.size(), (unsigned char **)salt, salt_len,
(unsigned char **)bytes_v, len_v, NULL, NULL);
}

// Get a db-ready SRP verifier
// The salt param is only modifyable by this method so that you can free it
// if it was allocated. You shouldn't use it for other purposes, as you will
// need the contents of salt_len too.
inline static std::string getSRPVerifier(const std::string &name,
const std::string &password, char ** salt, size_t salt_len)
{
char * bytes_v = NULL;
size_t len_v;
getSRPVerifier(name, password, salt, &salt_len,
&bytes_v, &len_v);
std::string ret_val = encodeSRPVerifier(std::string(bytes_v, len_v),
std::string(*salt, salt_len));
free(bytes_v);
return ret_val;
}

// Get a db-ready SRP verifier
std::string getSRPVerifier(const std::string &name,
const std::string &password)
{
char * salt = NULL;
std::string ret_val = getSRPVerifier(name,
password, &salt, 0);
free(salt);
return ret_val;
}

// Get a db-ready SRP verifier
std::string getSRPVerifier(const std::string &name,
const std::string &password, const std::string &salt)
{
// The implementation won't change the salt if its set,
// therefore we can cast.
char *salt_cstr = (char *)salt.c_str();
return getSRPVerifier(name, password,
&salt_cstr, salt.size());
}

// Make a SRP verifier db-ready
std::string encodeSRPVerifier(const std::string &verifier,
const std::string &salt)
{
std::ostringstream ret_str;
ret_str << "#1#"
<< base64_encode((unsigned char*) salt.c_str(), salt.size()) << "#"
<< base64_encode((unsigned char*) verifier.c_str(), verifier.size());
return ret_str.str();
}

bool decodeSRPVerifier(const std::string &enc_pwd,
std::string *salt, std::string *bytes_v)
{
std::vector<std::string> pwd_components = str_split(enc_pwd, '#');

if ((pwd_components.size() != 4)
|| (pwd_components[1] != "1") // 1 means srp
|| !base64_is_valid(pwd_components[2])
|| !base64_is_valid(pwd_components[3]))
return false;

std::string salt_str = base64_decode(pwd_components[2]);
std::string bytes_v_str = base64_decode(pwd_components[3]);
*salt = salt_str;
*bytes_v = bytes_v_str;
return true;

}
37 changes: 37 additions & 0 deletions src/util/auth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
Minetest
Copyright (C) 2015 est31 <MTest31@outlook.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef AUTH_H
#define AUTH_H

std::string translatePassword(const std::string &name,
const std::string &password);
void getSRPVerifier(const std::string &name,
const std::string &password, char **salt, size_t *salt_len,
char **bytes_v, size_t *len_v);
std::string getSRPVerifier(const std::string &name,
const std::string &password);
std::string getSRPVerifier(const std::string &name,
const std::string &password, const std::string &salt);
std::string encodeSRPVerifier(const std::string &verifier,
const std::string &salt);
bool decodeSRPVerifier(const std::string &enc_pwd,
std::string *salt, std::string *bytes_v);

#endif
428 changes: 428 additions & 0 deletions src/util/md32_common.h

Large diffs are not rendered by default.

154 changes: 154 additions & 0 deletions src/util/sha2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/* crypto/sha/sha.h */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* "This product includes cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/

#ifndef HEADER_SHA_H
# define HEADER_SHA_H

# include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

# if defined(OPENSSL_NO_SHA) || (defined(OPENSSL_NO_SHA0) && defined(OPENSSL_NO_SHA1))
# error SHA is disabled.
# endif

# if defined(OPENSSL_FIPS)
# define FIPS_SHA_SIZE_T size_t
# endif

/*
Compat stuff from OpenSSL land
*/

/* crypto.h */

# define fips_md_init(alg) fips_md_init_ctx(alg, alg)

# define fips_md_init_ctx(alg, cx) \
int alg##_Init(cx##_CTX *c)
# define fips_cipher_abort(alg) while(0)

/*-
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* ! SHA_LONG has to be at least 32 bits wide. If it's wider, then !
* ! SHA_LONG_LOG2 has to be defined along. !
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*/

# if defined(__LP32__)
# define SHA_LONG unsigned long
# elif defined(__ILP64__)
# define SHA_LONG unsigned long
# define SHA_LONG_LOG2 3
# else
# define SHA_LONG unsigned int
# endif

# define SHA_LBLOCK 16
# define SHA_CBLOCK (SHA_LBLOCK*4)/* SHA treats input data as a
* contiguous array of 32 bit wide
* big-endian values. */
# define SHA_LAST_BLOCK (SHA_CBLOCK-8)
# define SHA_DIGEST_LENGTH 20

typedef struct SHAstate_st {
SHA_LONG h0, h1, h2, h3, h4;
SHA_LONG Nl, Nh;
SHA_LONG data[SHA_LBLOCK];
unsigned int num;
} SHA_CTX;

# define SHA256_CBLOCK (SHA_LBLOCK*4)/* SHA-256 treats input data as a
* contiguous array of 32 bit wide
* big-endian values. */
# define SHA224_DIGEST_LENGTH 28
# define SHA256_DIGEST_LENGTH 32

typedef struct SHA256state_st {
SHA_LONG h[8];
SHA_LONG Nl, Nh;
SHA_LONG data[SHA_LBLOCK];
unsigned int num, md_len;
} SHA256_CTX;

# ifndef OPENSSL_NO_SHA256
# ifdef OPENSSL_FIPS
int private_SHA224_Init(SHA256_CTX *c);
int private_SHA256_Init(SHA256_CTX *c);
# endif
int SHA224_Init(SHA256_CTX *c);
int SHA224_Update(SHA256_CTX *c, const void *data, size_t len);
int SHA224_Final(unsigned char *md, SHA256_CTX *c);
unsigned char *SHA224(const unsigned char *d, size_t n, unsigned char *md);
int SHA256_Init(SHA256_CTX *c);
int SHA256_Update(SHA256_CTX *c, const void *data, size_t len);
int SHA256_Final(unsigned char *md, SHA256_CTX *c);
unsigned char *SHA256(const unsigned char *d, size_t n, unsigned char *md);
void SHA256_Transform(SHA256_CTX *c, const unsigned char *data);
# endif

# define SHA384_DIGEST_LENGTH 48
# define SHA512_DIGEST_LENGTH 64

#ifdef __cplusplus
}
#endif

#endif
404 changes: 404 additions & 0 deletions src/util/sha256.c

Large diffs are not rendered by default.

1,029 changes: 1,029 additions & 0 deletions src/util/srp.cpp

Large diffs are not rendered by default.

171 changes: 171 additions & 0 deletions src/util/srp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Secure Remote Password 6a implementation
* https://github.com/est31/csrp-gmp
*
* The MIT License (MIT)
*
* Copyright (c) 2010, 2013 Tom Cocagne, 2015 est31 <MTest31@outlook.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/

/*
*
* Purpose: This is a direct implementation of the Secure Remote Password
* Protocol version 6a as described by
* http://srp.stanford.edu/design.html
*
* Author: tom.cocagne@gmail.com (Tom Cocagne)
*
* Dependencies: LibGMP
*
* Usage: Refer to test_srp.c for a demonstration
*
* Notes:
* This library allows multiple combinations of hashing algorithms and
* prime number constants. For authentication to succeed, the hash and
* prime number constants must match between
* srp_create_salted_verification_key(), srp_user_new(),
* and srp_verifier_new(). A recommended approach is to determine the
* desired level of security for an application and globally define the
* hash and prime number constants to the predetermined values.
*
* As one might suspect, more bits means more security. As one might also
* suspect, more bits also means more processing time. The test_srp.c
* program can be easily modified to profile various combinations of
* hash & prime number pairings.
*/

#ifndef SRP_H
#define SRP_H


struct SRPVerifier;
struct SRPUser;

typedef enum
{
SRP_NG_1024,
SRP_NG_2048,
SRP_NG_4096,
SRP_NG_8192,
SRP_NG_CUSTOM
} SRP_NGType;

typedef enum
{
/*SRP_SHA1,*/
/*SRP_SHA224,*/
SRP_SHA256,
/*SRP_SHA384,
SRP_SHA512*/
} SRP_HashAlgorithm;

/* Out: bytes_v, len_v
*
* The caller is responsible for freeing the memory allocated for bytes_v
*
* The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type.
* If provided, they must contain ASCII text of the hexidecimal notation.
*
* If bytes_s == NULL, it is filled with random data. The caller is responsible for freeing.
*/
void srp_create_salted_verification_key( SRP_HashAlgorithm alg,
SRP_NGType ng_type, const char *username_for_verifier,
const unsigned char *password, size_t len_password,
unsigned char **bytes_s, size_t *len_s,
unsigned char **bytes_v, size_t *len_v,
const char * n_hex, const char *g_hex );

/* Out: bytes_B, len_B.
*
* On failure, bytes_B will be set to NULL and len_B will be set to 0
*
* The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type
*
* If bytes_b == NULL, random data is used for b.
*/
struct SRPVerifier* srp_verifier_new(SRP_HashAlgorithm alg, SRP_NGType ng_type,
const char *username,
const unsigned char *bytes_s, size_t len_s,
const unsigned char *bytes_v, size_t len_v,
const unsigned char *bytes_A, size_t len_A,
const unsigned char *bytes_b, size_t len_b,
unsigned char** bytes_B, size_t *len_B,
const char* n_hex, const char* g_hex);


void srp_verifier_delete( struct SRPVerifier* ver );


int srp_verifier_is_authenticated( struct SRPVerifier* ver );


const char * srp_verifier_get_username( struct SRPVerifier* ver );

/* key_length may be null */
const unsigned char* srp_verifier_get_session_key( struct SRPVerifier* ver,
size_t *key_length );


size_t srp_verifier_get_session_key_length(struct SRPVerifier* ver);


/* user_M must be exactly srp_verifier_get_session_key_length() bytes in size */
void srp_verifier_verify_session( struct SRPVerifier* ver,
const unsigned char* user_M, unsigned char** bytes_HAMK );

/*******************************************************************************/

/* The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type */
struct SRPUser *srp_user_new(SRP_HashAlgorithm alg, SRP_NGType ng_type,
const char *username, const char *username_for_verifier,
const unsigned char *bytes_password, size_t len_password,
const char *n_hex, const char *g_hex);

void srp_user_delete(struct SRPUser * usr);

int srp_user_is_authenticated(struct SRPUser * usr);


const char* srp_user_get_username(struct SRPUser * usr);

/* key_length may be null */
const unsigned char* srp_user_get_session_key(struct SRPUser* usr, size_t* key_length);

size_t srp_user_get_session_key_length(struct SRPUser* usr);

/* Output: username, bytes_A, len_A. If you don't want it get written, set username to NULL.
* If bytes_a == NULL, random data is used for a. */
void srp_user_start_authentication(struct SRPUser* usr, char** username,
const unsigned char* bytes_a, size_t len_a,
unsigned char** bytes_A, size_t* len_A);

/* Output: bytes_M, len_M (len_M may be null and will always be
* srp_user_get_session_key_length() bytes in size) */
void srp_user_process_challenge(struct SRPUser *usr,
const unsigned char *bytes_s, size_t len_s,
const unsigned char *bytes_B, size_t len_B,
unsigned char **bytes_M, size_t *len_M);

/* bytes_HAMK must be exactly srp_user_get_session_key_length() bytes in size */
void srp_user_verify_session(struct SRPUser* usr, const unsigned char* bytes_HAMK);

#endif /* Include Guard */
23 changes: 0 additions & 23 deletions src/util/string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "numeric.h"
#include "log.h"

#include "sha1.h"
#include "base64.h"
#include "hex.h"
#include "../porting.h"

#include <algorithm>
#include <sstream>
#include <iomanip>
#include <map>
Expand Down Expand Up @@ -176,26 +173,6 @@ std::string wide_to_narrow(const std::wstring &wcs)

#endif

// Get an sha-1 hash of the player's name combined with
// the password entered. That's what the server uses as
// their password. (Exception : if the password field is
// blank, we send a blank password - this is for backwards
// compatibility with password-less players).
std::string translatePassword(const std::string &playername,
const std::string &password)
{
if (password.length() == 0)
return "";

std::string slt = playername + password;
SHA1 sha1;
sha1.addBytes(slt.c_str(), slt.length());
unsigned char *digest = sha1.getDigest();
std::string pwd = base64_encode(digest, 20);
free(digest);
return pwd;
}

std::string urlencode(std::string str)
{
// Encodes non-unreserved URI characters by a percent sign
Expand Down
3 changes: 1 addition & 2 deletions src/util/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ wchar_t *narrow_to_wide_c(const char *str);

std::wstring narrow_to_wide(const std::string &mbs);
std::string wide_to_narrow(const std::wstring &wcs);
std::string translatePassword(const std::string &playername,
const std::string &password);

std::string urlencode(std::string str);
std::string urldecode(std::string str);
u32 readFlagString(std::string str, const FlagDesc *flagdesc, u32 *flagmask);
Expand Down
2 changes: 1 addition & 1 deletion util/travis/before_install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ sudo apt-get install p7zip-full
if [[ $PLATFORM == "Linux" ]]; then
sudo apt-get install libirrlicht-dev cmake libbz2-dev libpng12-dev \
libjpeg-dev libxxf86vm-dev libgl1-mesa-dev libsqlite3-dev \
libhiredis-dev libogg-dev libvorbis-dev libopenal-dev gettext
libhiredis-dev libogg-dev libgmp-dev libvorbis-dev libopenal-dev gettext
# Linking to LevelDB is broken, use a custom build
wget http://sfan5.pf-control.de/libleveldb-1.18-ubuntu12.04.7z
sudo 7z x -o/usr libleveldb-1.18-ubuntu12.04.7z
Expand Down