diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/util/areastore.cpp | 299 | ||||
-rw-r--r-- | src/util/areastore.h | 204 | ||||
-rw-r--r-- | src/util/auth.cpp | 107 | ||||
-rw-r--r-- | src/util/auth.h | 35 | ||||
-rw-r--r-- | src/util/basic_macros.h | 53 | ||||
-rw-r--r-- | src/util/container.h | 171 | ||||
-rw-r--r-- | src/util/numeric.cpp | 11 | ||||
-rw-r--r-- | src/util/numeric.h | 19 | ||||
-rw-r--r-- | src/util/serialize.cpp | 73 | ||||
-rw-r--r-- | src/util/serialize.h | 251 | ||||
-rw-r--r-- | src/util/srp.cpp | 693 | ||||
-rw-r--r-- | src/util/srp.h | 91 | ||||
-rw-r--r-- | src/util/strfnd.h | 82 | ||||
-rw-r--r-- | src/util/string.h | 81 | ||||
-rw-r--r-- | src/util/thread.h | 64 |
16 files changed, 1599 insertions, 636 deletions
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 33900a43a..0e7cbad07 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -1,4 +1,5 @@ set(UTIL_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/areastore.cpp ${CMAKE_CURRENT_SOURCE_DIR}/auth.cpp ${CMAKE_CURRENT_SOURCE_DIR}/base64.cpp ${CMAKE_CURRENT_SOURCE_DIR}/directiontables.cpp diff --git a/src/util/areastore.cpp b/src/util/areastore.cpp new file mode 100644 index 000000000..58f08a8c2 --- /dev/null +++ b/src/util/areastore.cpp @@ -0,0 +1,299 @@ +/* +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 "util/areastore.h" +#include "util/serialize.h" +#include "util/container.h" + +#if USE_SPATIAL + #include <spatialindex/SpatialIndex.h> + #include <spatialindex/RTree.h> + #include <spatialindex/Point.h> +#endif + +#define AST_SMALLER_EQ_AS(p, q) (((p).X <= (q).X) && ((p).Y <= (q).Y) && ((p).Z <= (q).Z)) + +#define AST_OVERLAPS_IN_DIMENSION(amine, amaxe, b, d) \ + (!(((amine).d > (b)->maxedge.d) || ((amaxe).d < (b)->minedge.d))) + +#define AST_CONTAINS_PT(a, p) (AST_SMALLER_EQ_AS((a)->minedge, (p)) && \ + AST_SMALLER_EQ_AS((p), (a)->maxedge)) + +#define AST_CONTAINS_AREA(amine, amaxe, b) \ + (AST_SMALLER_EQ_AS((amine), (b)->minedge) \ + && AST_SMALLER_EQ_AS((b)->maxedge, (amaxe))) + +#define AST_AREAS_OVERLAP(amine, amaxe, b) \ + (AST_OVERLAPS_IN_DIMENSION((amine), (amaxe), (b), X) && \ + AST_OVERLAPS_IN_DIMENSION((amine), (amaxe), (b), Y) && \ + AST_OVERLAPS_IN_DIMENSION((amine), (amaxe), (b), Z)) + + +AreaStore *AreaStore::getOptimalImplementation() +{ +#if USE_SPATIAL + return new SpatialAreaStore(); +#else + return new VectorAreaStore(); +#endif +} + +const Area *AreaStore::getArea(u32 id) const +{ + AreaMap::const_iterator it = areas_map.find(id); + if (it == areas_map.end()) + return NULL; + return &it->second; +} + +void AreaStore::serialize(std::ostream &os) const +{ + writeU8(os, 0); // Serialisation version + + // TODO: Compression? + writeU16(os, areas_map.size()); + for (AreaMap::const_iterator it = areas_map.begin(); + it != areas_map.end(); ++it) { + const Area &a = it->second; + writeV3S16(os, a.minedge); + writeV3S16(os, a.maxedge); + writeU16(os, a.data.size()); + os.write(a.data.data(), a.data.size()); + } +} + +void AreaStore::deserialize(std::istream &is) +{ + u8 ver = readU8(is); + if (ver != 0) + throw SerializationError("Unknown AreaStore " + "serialization version!"); + + u16 num_areas = readU16(is); + for (u32 i = 0; i < num_areas; ++i) { + Area a; + a.minedge = readV3S16(is); + a.maxedge = readV3S16(is); + u16 data_len = readU16(is); + char *data = new char[data_len]; + is.read(data, data_len); + a.data = std::string(data, data_len); + insertArea(&a); + } +} + +void AreaStore::invalidateCache() +{ + if (m_cache_enabled) { + m_res_cache.invalidate(); + } +} + +void AreaStore::setCacheParams(bool enabled, u8 block_radius, size_t limit) +{ + m_cache_enabled = enabled; + m_cacheblock_radius = MYMAX(block_radius, 16); + m_res_cache.setLimit(MYMAX(limit, 20)); + invalidateCache(); +} + +void AreaStore::cacheMiss(void *data, const v3s16 &mpos, std::vector<Area *> *dest) +{ + AreaStore *as = (AreaStore *)data; + u8 r = as->m_cacheblock_radius; + + // get the points at the edges of the mapblock + v3s16 minedge(mpos.X * r, mpos.Y * r, mpos.Z * r); + v3s16 maxedge( + minedge.X + r - 1, + minedge.Y + r - 1, + minedge.Z + r - 1); + + as->getAreasInArea(dest, minedge, maxedge, true); + + /* infostream << "Cache miss with " << dest->size() << " areas, between (" + << minedge.X << ", " << minedge.Y << ", " << minedge.Z + << ") and (" + << maxedge.X << ", " << maxedge.Y << ", " << maxedge.Z + << ")" << std::endl; // */ +} + +void AreaStore::getAreasForPos(std::vector<Area *> *result, v3s16 pos) +{ + if (m_cache_enabled) { + v3s16 mblock = getContainerPos(pos, m_cacheblock_radius); + const std::vector<Area *> *pre_list = m_res_cache.lookupCache(mblock); + + size_t s_p_l = pre_list->size(); + for (size_t i = 0; i < s_p_l; i++) { + Area *b = (*pre_list)[i]; + if (AST_CONTAINS_PT(b, pos)) { + result->push_back(b); + } + } + } else { + return getAreasForPosImpl(result, pos); + } +} + + +//// +// VectorAreaStore +//// + + +bool VectorAreaStore::insertArea(Area *a) +{ + if (a->id == U32_MAX) + a->id = getNextId(); + std::pair<AreaMap::iterator, bool> res = + areas_map.insert(std::make_pair(a->id, *a)); + if (!res.second) + // ID is not unique + return false; + m_areas.push_back(&res.first->second); + invalidateCache(); + return true; +} + +bool VectorAreaStore::removeArea(u32 id) +{ + AreaMap::iterator it = areas_map.find(id); + if (it == areas_map.end()) + return false; + Area *a = &it->second; + for (std::vector<Area *>::iterator v_it = m_areas.begin(); + v_it != m_areas.end(); ++v_it) { + if (*v_it == a) { + m_areas.erase(v_it); + break; + } + } + areas_map.erase(it); + invalidateCache(); + return true; +} + +void VectorAreaStore::getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos) +{ + for (size_t i = 0; i < m_areas.size(); ++i) { + Area *b = m_areas[i]; + if (AST_CONTAINS_PT(b, pos)) { + result->push_back(b); + } + } +} + +void VectorAreaStore::getAreasInArea(std::vector<Area *> *result, + v3s16 minedge, v3s16 maxedge, bool accept_overlap) +{ + for (size_t i = 0; i < m_areas.size(); ++i) { + Area *b = m_areas[i]; + if (accept_overlap ? AST_AREAS_OVERLAP(minedge, maxedge, b) : + AST_CONTAINS_AREA(minedge, maxedge, b)) { + result->push_back(b); + } + } +} + +#if USE_SPATIAL + +static inline SpatialIndex::Region get_spatial_region(const v3s16 minedge, + const v3s16 maxedge) +{ + const double p_low[] = {(double)minedge.X, + (double)minedge.Y, (double)minedge.Z}; + const double p_high[] = {(double)maxedge.X, (double)maxedge.Y, + (double)maxedge.Z}; + return SpatialIndex::Region(p_low, p_high, 3); +} + +static inline SpatialIndex::Point get_spatial_point(const v3s16 pos) +{ + const double p[] = {(double)pos.X, (double)pos.Y, (double)pos.Z}; + return SpatialIndex::Point(p, 3); +} + + +bool SpatialAreaStore::insertArea(Area *a) +{ + if (a->id == U32_MAX) + a->id = getNextId(); + if (!areas_map.insert(std::make_pair(a->id, *a)).second) + // ID is not unique + return false; + m_tree->insertData(0, NULL, get_spatial_region(a->minedge, a->maxedge), a->id); + invalidateCache(); + return true; +} + +bool SpatialAreaStore::removeArea(u32 id) +{ + std::map<u32, Area>::iterator itr = areas_map.find(id); + if (itr != areas_map.end()) { + Area *a = &itr->second; + bool result = m_tree->deleteData(get_spatial_region(a->minedge, + a->maxedge), id); + areas_map.erase(itr); + invalidateCache(); + return result; + } else { + return false; + } +} + +void SpatialAreaStore::getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos) +{ + VectorResultVisitor visitor(result, this); + m_tree->pointLocationQuery(get_spatial_point(pos), visitor); +} + +void SpatialAreaStore::getAreasInArea(std::vector<Area *> *result, + v3s16 minedge, v3s16 maxedge, bool accept_overlap) +{ + VectorResultVisitor visitor(result, this); + if (accept_overlap) { + m_tree->intersectsWithQuery(get_spatial_region(minedge, maxedge), + visitor); + } else { + m_tree->containsWhatQuery(get_spatial_region(minedge, maxedge), visitor); + } +} + +SpatialAreaStore::~SpatialAreaStore() +{ + delete m_tree; +} + +SpatialAreaStore::SpatialAreaStore() +{ + m_storagemanager = + SpatialIndex::StorageManager::createNewMemoryStorageManager(); + SpatialIndex::id_type id; + m_tree = SpatialIndex::RTree::createNewRTree( + *m_storagemanager, + .7, // Fill factor + 100, // Index capacity + 100, // Leaf capacity + 3, // dimension :) + SpatialIndex::RTree::RV_RSTAR, + id); +} + +#endif diff --git a/src/util/areastore.h b/src/util/areastore.h new file mode 100644 index 000000000..bebecfd78 --- /dev/null +++ b/src/util/areastore.h @@ -0,0 +1,204 @@ +/* +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 AREA_STORE_H_ +#define AREA_STORE_H_ + +#include "irr_v3d.h" +#include "noise.h" // for PcgRandom +#include <map> +#include <list> +#include <vector> +#include <istream> +#include "util/container.h" +#include "util/numeric.h" +#ifndef ANDROID + #include "cmake_config.h" +#endif +#if USE_SPATIAL + #include <spatialindex/SpatialIndex.h> + #include "util/serialize.h" +#endif + + +struct Area { + Area() : id(U32_MAX) {} + Area(const v3s16 &mine, const v3s16 &maxe) : + id(U32_MAX), minedge(mine), maxedge(maxe) + { + sortBoxVerticies(minedge, maxedge); + } + + u32 id; + v3s16 minedge, maxedge; + std::string data; +}; + + +class AreaStore { +public: + AreaStore() : + m_cache_enabled(true), + m_cacheblock_radius(64), + m_res_cache(1000, &cacheMiss, this), + m_next_id(0) + {} + + virtual ~AreaStore() {} + + static AreaStore *getOptimalImplementation(); + + virtual void reserve(size_t count) {}; + size_t size() const { return areas_map.size(); } + + /// Add an area to the store. + /// Updates the area's ID if it hasn't already been set. + /// @return Whether the area insertion was successful. + virtual bool insertArea(Area *a) = 0; + + /// Removes an area from the store by ID. + /// @return Whether the area was in the store and removed. + virtual bool removeArea(u32 id) = 0; + + /// Finds areas that the passed position is contained in. + /// Stores output in passed vector. + void getAreasForPos(std::vector<Area *> *result, v3s16 pos); + + /// Finds areas that are completely contained inside the area defined + /// by the passed edges. If @p accept_overlap is true this finds any + /// areas that intersect with the passed area at any point. + virtual void getAreasInArea(std::vector<Area *> *result, + v3s16 minedge, v3s16 maxedge, bool accept_overlap) = 0; + + /// Sets cache parameters. + void setCacheParams(bool enabled, u8 block_radius, size_t limit); + + /// Returns a pointer to the area coresponding to the passed ID, + /// or NULL if it doesn't exist. + const Area *getArea(u32 id) const; + + /// Serializes the store's areas to a binary ostream. + void serialize(std::ostream &is) const; + + /// Deserializes the Areas from a binary istream. + /// This does not currently clear the AreaStore before adding the + /// areas, making it possible to deserialize multiple serialized + /// AreaStores. + void deserialize(std::istream &is); + +protected: + /// Invalidates the getAreasForPos cache. + /// Call after adding or removing an area. + void invalidateCache(); + + /// Implementation of getAreasForPos. + /// getAreasForPos calls this if the cache is disabled. + virtual void getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos) = 0; + + /// Returns the next area ID and increments it. + u32 getNextId() { return m_next_id++; } + + // Note: This can't be an unordered_map, since all + // references would be invalidated on rehash. + typedef std::map<u32, Area> AreaMap; + AreaMap areas_map; + +private: + /// Called by the cache when a value isn't found in the cache. + static void cacheMiss(void *data, const v3s16 &mpos, std::vector<Area *> *dest); + + bool m_cache_enabled; + /// Range, in nodes, of the getAreasForPos cache. + /// If you modify this, call invalidateCache() + u8 m_cacheblock_radius; + LRUCache<v3s16, std::vector<Area *> > m_res_cache; + + u32 m_next_id; +}; + + +class VectorAreaStore : public AreaStore { +public: + virtual void reserve(size_t count) { m_areas.reserve(count); } + virtual bool insertArea(Area *a); + virtual bool removeArea(u32 id); + virtual void getAreasInArea(std::vector<Area *> *result, + v3s16 minedge, v3s16 maxedge, bool accept_overlap); + +protected: + virtual void getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos); + +private: + std::vector<Area *> m_areas; +}; + + +#if USE_SPATIAL + +class SpatialAreaStore : public AreaStore { +public: + SpatialAreaStore(); + virtual ~SpatialAreaStore(); + + virtual bool insertArea(Area *a); + virtual bool removeArea(u32 id); + virtual void getAreasInArea(std::vector<Area *> *result, + v3s16 minedge, v3s16 maxedge, bool accept_overlap); + +protected: + virtual void getAreasForPosImpl(std::vector<Area *> *result, v3s16 pos); + +private: + SpatialIndex::ISpatialIndex *m_tree; + SpatialIndex::IStorageManager *m_storagemanager; + + class VectorResultVisitor : public SpatialIndex::IVisitor { + public: + VectorResultVisitor(std::vector<Area *> *result, SpatialAreaStore *store) : + m_store(store), + m_result(result) + {} + ~VectorResultVisitor() {} + + virtual void visitNode(const SpatialIndex::INode &in) {} + + virtual void visitData(const SpatialIndex::IData &in) + { + u32 id = in.getIdentifier(); + + std::map<u32, Area>::iterator itr = m_store->areas_map.find(id); + assert(itr != m_store->areas_map.end()); + m_result->push_back(&itr->second); + } + + virtual void visitData(std::vector<const SpatialIndex::IData *> &v) + { + for (size_t i = 0; i < v.size(); i++) + visitData(*(v[i])); + } + + private: + SpatialAreaStore *m_store; + std::vector<Area *> *m_result; + }; +}; + +#endif // USE_SPATIAL + +#endif // AREA_STORE_H_ diff --git a/src/util/auth.cpp b/src/util/auth.cpp index df8940e87..912987259 100644 --- a/src/util/auth.cpp +++ b/src/util/auth.cpp @@ -1,6 +1,6 @@ /* Minetest -Copyright (C) 2015 est31 <MTest31@outlook.com> +Copyright (C) 2015, 2016 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 @@ -24,13 +24,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "sha1.h" #include "srp.h" #include "string.h" +#include "debug.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, +std::string translate_password(const std::string &name, const std::string &password) { if (password.length() == 0) @@ -45,82 +46,92 @@ std::string translatePassword(const std::string &name, return pwd; } -void getSRPVerifier(const std::string &name, +// Call lower level SRP code to generate a verifier with the +// given pointers. Contains the preparations, call parameters +// and error checking common to all srp verifier generation code. +// See docs of srp_create_salted_verification_key for more info. +static inline void gen_srp_v(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, + SRP_Result res = 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); + FATAL_ERROR_IF(res != SRP_OK, "Couldn't create salted SRP verifier"); } -// Get a db-ready SRP verifier -// If the salt param is NULL, one is automatically generated. -// Please free() it afterwards. 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) +/// Creates a verification key with given salt and password. +std::string generate_srp_verifier(const std::string &name, + const std::string &password, const std::string &salt) { - 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)); + size_t salt_len = salt.size(); + // The API promises us that the salt doesn't + // get modified if &salt_ptr isn't NULL. + char *salt_ptr = (char *)salt.c_str(); + + char *bytes_v = NULL; + size_t verifier_len = 0; + gen_srp_v(name, password, &salt_ptr, &salt_len, &bytes_v, &verifier_len); + std::string verifier = std::string(bytes_v, verifier_len); free(bytes_v); - return ret_val; + return verifier; } -// Get a db-ready SRP verifier -std::string getSRPVerifier(const std::string &name, - const std::string &password) +/// Creates a verification key and salt with given password. +void generate_srp_verifier_and_salt(const std::string &name, + const std::string &password, std::string *verifier, + std::string *salt) { - char * salt = NULL; - std::string ret_val = getSRPVerifier(name, - password, &salt, 0); - free(salt); - return ret_val; + char *bytes_v = NULL; + size_t verifier_len; + char *salt_ptr = NULL; + size_t salt_len; + gen_srp_v(name, password, &salt_ptr, &salt_len, &bytes_v, &verifier_len); + *verifier = std::string(bytes_v, verifier_len); + *salt = std::string(salt_ptr, salt_len); + free(bytes_v); + free(salt_ptr); } -// Get a db-ready SRP verifier -std::string getSRPVerifier(const std::string &name, - const std::string &password, const std::string &salt) +/// Gets an SRP verifier, generating a salt, +/// and encodes it as DB-ready string. +std::string get_encoded_srp_verifier(const std::string &name, + const std::string &password) { - // 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()); + std::string verifier; + std::string salt; + generate_srp_verifier_and_salt(name, password, &verifier, &salt); + return encode_srp_verifier(verifier, salt); } -// Make a SRP verifier db-ready -std::string encodeSRPVerifier(const std::string &verifier, +/// Converts the passed SRP verifier into a DB-ready format. +std::string encode_srp_verifier(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()); + << 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) +/// Reads the DB-formatted SRP verifier and gets the verifier +/// and salt components. +bool decode_srp_verifier_and_salt(const std::string &encoded, + std::string *verifier, std::string *salt) { - std::vector<std::string> pwd_components = str_split(enc_pwd, '#'); + std::vector<std::string> components = str_split(encoded, '#'); - if ((pwd_components.size() != 4) - || (pwd_components[1] != "1") // 1 means srp - || !base64_is_valid(pwd_components[2]) - || !base64_is_valid(pwd_components[3])) + if ((components.size() != 4) + || (components[1] != "1") // 1 means srp + || !base64_is_valid(components[2]) + || !base64_is_valid(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; + *salt = base64_decode(components[2]); + *verifier = base64_decode(components[3]); return true; } diff --git a/src/util/auth.h b/src/util/auth.h index 36d8c20a4..1fd6ab453 100644 --- a/src/util/auth.h +++ b/src/util/auth.h @@ -1,6 +1,6 @@ /* Minetest -Copyright (C) 2015 est31 <MTest31@outlook.com> +Copyright (C) 2015, 2016 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 @@ -20,18 +20,31 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef AUTH_H #define AUTH_H -std::string translatePassword(const std::string &name, +/// Gets the base64 encoded legacy password db entry. +std::string translate_password(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, + +/// Creates a verification key with given salt and password. +std::string generate_srp_verifier(const std::string &name, const std::string &password, const std::string &salt); -std::string encodeSRPVerifier(const std::string &verifier, + +/// Creates a verification key and salt with given password. +void generate_srp_verifier_and_salt(const std::string &name, + const std::string &password, std::string *verifier, + std::string *salt); + +/// Gets an SRP verifier, generating a salt, +/// and encodes it as DB-ready string. +std::string get_encoded_srp_verifier(const std::string &name, + const std::string &password); + +/// Converts the passed SRP verifier into a DB-ready format. +std::string encode_srp_verifier(const std::string &verifier, const std::string &salt); -bool decodeSRPVerifier(const std::string &enc_pwd, + +/// Reads the DB-formatted SRP verifier and gets the verifier +/// and salt components. +bool decode_srp_verifier_and_salt(const std::string &encoded, std::string *salt, std::string *bytes_v); -#endif
\ No newline at end of file +#endif diff --git a/src/util/basic_macros.h b/src/util/basic_macros.h new file mode 100644 index 000000000..c100b4f25 --- /dev/null +++ b/src/util/basic_macros.h @@ -0,0 +1,53 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.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 BASICMACROS_HEADER +#define BASICMACROS_HEADER + +#include <algorithm> + +#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) + +#define MYMIN(a, b) ((a) < (b) ? (a) : (b)) + +#define MYMAX(a, b) ((a) > (b) ? (a) : (b)) + +#define CONTAINS(c, v) (std::find((c).begin(), (c).end(), (v)) != (c).end()) + +// To disable copy constructors and assignment operations for some class +// 'Foobar', add the macro DISABLE_CLASS_COPY(Foobar) as a private member. +// Note this also disables copying for any classes derived from 'Foobar' as well +// as classes having a 'Foobar' member. +#define DISABLE_CLASS_COPY(C) \ + C(const C &); \ + C &operator=(const C &) + +#ifndef _MSC_VER + #define UNUSED_ATTRIBUTE __attribute__ ((unused)) +#else + #define UNUSED_ATTRIBUTE +#endif + +// Fail compilation if condition expr is not met. +// Note that 'msg' must follow the format of a valid identifier, e.g. +// STATIC_ASSERT(sizeof(foobar_t) == 40), foobar_t_is_wrong_size); +#define STATIC_ASSERT(expr, msg) \ + UNUSED_ATTRIBUTE typedef char msg[!!(expr) * 2 - 1] + +#endif diff --git a/src/util/container.h b/src/util/container.h index 267d54c16..7f66b89ac 100644 --- a/src/util/container.h +++ b/src/util/container.h @@ -22,9 +22,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "../irrlichttypes.h" #include "../exceptions.h" -#include "../jthread/jmutex.h" -#include "../jthread/jmutexautolock.h" -#include "../jthread/jsemaphore.h" +#include "../threading/mutex.h" +#include "../threading/mutex_auto_lock.h" +#include "../threading/semaphore.h" #include <list> #include <vector> #include <map> @@ -81,111 +81,47 @@ template<typename Key, typename Value> class MutexedMap { public: - MutexedMap() - { - } + MutexedMap() {} void set(const Key &name, const Value &value) { - JMutexAutoLock lock(m_mutex); - + MutexAutoLock lock(m_mutex); m_values[name] = value; } - bool get(const Key &name, Value *result) + bool get(const Key &name, Value *result) const { - JMutexAutoLock lock(m_mutex); - - typename std::map<Key, Value>::iterator n; - n = m_values.find(name); - - if(n == m_values.end()) + MutexAutoLock lock(m_mutex); + typename std::map<Key, Value>::const_iterator n = + m_values.find(name); + if (n == m_values.end()) return false; - - if(result != NULL) + if (result) *result = n->second; - return true; } - std::vector<Value> getValues() + std::vector<Value> getValues() const { + MutexAutoLock lock(m_mutex); std::vector<Value> result; - for(typename std::map<Key, Value>::iterator - i = m_values.begin(); - i != m_values.end(); ++i){ - result.push_back(i->second); + for (typename std::map<Key, Value>::const_iterator + it = m_values.begin(); + it != m_values.end(); ++it){ + result.push_back(it->second); } return result; } - void clear () - { - m_values.clear(); - } + void clear() { m_values.clear(); } private: std::map<Key, Value> m_values; - JMutex m_mutex; + mutable Mutex m_mutex; }; -/* -Generates ids for comparable values. -Id=0 is reserved for "no value". -Is fast at: -- Returning value by id (very fast) -- Returning id by value -- Generating a new id for a value - -Is not able to: -- Remove an id/value pair (is possible to implement but slow) -*/ -template<typename T> -class MutexedIdGenerator -{ -public: - MutexedIdGenerator() - { - } - - // Returns true if found - bool getValue(u32 id, T &value) - { - if(id == 0) - return false; - JMutexAutoLock lock(m_mutex); - if(m_id_to_value.size() < id) - return false; - value = m_id_to_value[id-1]; - return true; - } - - // If id exists for value, returns the id. - // Otherwise generates an id for the value. - u32 getId(const T &value) - { - JMutexAutoLock lock(m_mutex); - typename std::map<T, u32>::iterator n; - n = m_value_to_id.find(value); - if(n != m_value_to_id.end()) - return n->second; - m_id_to_value.push_back(value); - u32 new_id = m_id_to_value.size(); - m_value_to_id.insert(value, new_id); - return new_id; - } - -private: - JMutex m_mutex; - // Values are stored here at id-1 position (id 1 = [0]) - std::vector<T> m_id_to_value; - std::map<T, u32> m_value_to_id; -}; - -/* -Thread-safe FIFO queue (well, actually a FILO also) -*/ +// Thread-safe Double-ended queue template<typename T> class MutexedQueue @@ -194,19 +130,18 @@ public: template<typename Key, typename U, typename Caller, typename CallerData> friend class RequestQueue; - MutexedQueue() - { - } - bool empty() + MutexedQueue() {} + bool empty() const { - JMutexAutoLock lock(m_mutex); - return (m_queue.size() == 0); + MutexAutoLock lock(m_mutex); + return m_queue.empty(); } + void push_back(T t) { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); m_queue.push_back(t); - m_size.Post(); + m_signal.post(); } /* this version of pop_front returns a empty element of T on timeout. @@ -214,37 +149,35 @@ public: */ T pop_frontNoEx(u32 wait_time_max_ms) { - if (m_size.Wait(wait_time_max_ms)) { - JMutexAutoLock lock(m_mutex); + if (m_signal.wait(wait_time_max_ms)) { + MutexAutoLock lock(m_mutex); T t = m_queue.front(); m_queue.pop_front(); return t; - } - else { + } else { return T(); } } T pop_front(u32 wait_time_max_ms) { - if (m_size.Wait(wait_time_max_ms)) { - JMutexAutoLock lock(m_mutex); + if (m_signal.wait(wait_time_max_ms)) { + MutexAutoLock lock(m_mutex); T t = m_queue.front(); m_queue.pop_front(); return t; - } - else { + } else { throw ItemNotFoundException("MutexedQueue: queue is empty"); } } T pop_frontNoEx() { - m_size.Wait(); + m_signal.wait(); - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); T t = m_queue.front(); m_queue.pop_front(); @@ -253,14 +186,13 @@ public: T pop_back(u32 wait_time_max_ms=0) { - if (m_size.Wait(wait_time_max_ms)) { - JMutexAutoLock lock(m_mutex); + if (m_signal.wait(wait_time_max_ms)) { + MutexAutoLock lock(m_mutex); T t = m_queue.back(); m_queue.pop_back(); return t; - } - else { + } else { throw ItemNotFoundException("MutexedQueue: queue is empty"); } } @@ -268,25 +200,24 @@ public: /* this version of pop_back returns a empty element of T on timeout. * Make sure default constructor of T creates a recognizable "empty" element */ - T pop_backNoEx(u32 wait_time_max_ms=0) + T pop_backNoEx(u32 wait_time_max_ms) { - if (m_size.Wait(wait_time_max_ms)) { - JMutexAutoLock lock(m_mutex); + if (m_signal.wait(wait_time_max_ms)) { + MutexAutoLock lock(m_mutex); T t = m_queue.back(); m_queue.pop_back(); return t; - } - else { + } else { return T(); } } T pop_backNoEx() { - m_size.Wait(); + m_signal.wait(); - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); T t = m_queue.back(); m_queue.pop_back(); @@ -294,19 +225,13 @@ public: } protected: - JMutex & getMutex() - { - return m_mutex; - } + Mutex &getMutex() { return m_mutex; } - std::deque<T> & getQueue() - { - return m_queue; - } + std::deque<T> &getQueue() { return m_queue; } std::deque<T> m_queue; - JMutex m_mutex; - JSemaphore m_size; + mutable Mutex m_mutex; + Semaphore m_signal; }; template<typename K, typename V> diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp index 3fd1c9cf9..42ebd9022 100644 --- a/src/util/numeric.cpp +++ b/src/util/numeric.cpp @@ -23,17 +23,17 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "../constants.h" // BS, MAP_BLOCKSIZE #include "../noise.h" // PseudoRandom, PcgRandom -#include "../jthread/jmutexautolock.h" +#include "../threading/mutex_auto_lock.h" #include <string.h> #include <iostream> std::map<u16, std::vector<v3s16> > FacePositionCache::m_cache; -JMutex FacePositionCache::m_cache_mutex; +Mutex FacePositionCache::m_cache_mutex; // Calculate the borders of a "d-radius" cube // TODO: Make it work without mutex and data races, probably thread-local std::vector<v3s16> FacePositionCache::getFacePositions(u16 d) { - JMutexAutoLock cachelock(m_cache_mutex); + MutexAutoLock cachelock(m_cache_mutex); if (m_cache.find(d) != m_cache.end()) return m_cache[d]; @@ -244,7 +244,10 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 cosangle = dforward / blockpos_adj.getLength(); // If block is not in the field of view, skip it - if(cosangle < cos(camera_fov / 2)) + // HOTFIX: use sligthly increased angle (+10%) to fix too agressive + // culling. Somebody have to find out whats wrong with the math here. + // Previous value: camera_fov / 2 + if(cosangle < cos(camera_fov * 0.55)) return false; return true; diff --git a/src/util/numeric.h b/src/util/numeric.h index 9fe08434f..615327864 100644 --- a/src/util/numeric.h +++ b/src/util/numeric.h @@ -20,15 +20,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef UTIL_NUMERIC_HEADER #define UTIL_NUMERIC_HEADER +#include "basic_macros.h" #include "../irrlichttypes.h" #include "../irr_v2d.h" #include "../irr_v3d.h" #include "../irr_aabb3d.h" -#include "../jthread/jmutex.h" +#include "../threading/mutex.h" #include <list> #include <map> #include <vector> -#include <algorithm> /* @@ -42,7 +42,7 @@ public: private: static void generateFacePosition(u16 d); static std::map<u16, std::vector<v3s16> > m_cache; - static JMutex m_cache_mutex; + static Mutex m_cache_mutex; }; class IndentationRaiser @@ -166,9 +166,6 @@ inline v3s16 arealim(v3s16 p, s16 d) return p; } -#define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) -#define CONTAINS(c, v) (std::find((c).begin(), (c).end(), (v)) != (c).end()) - // The naive swap performs better than the xor version #define SWAP(t, x, y) do { \ t temp = x; \ @@ -279,12 +276,6 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 camera_fov, f32 range, f32 *distance_ptr=NULL); /* - Some helper stuff -*/ -#define MYMIN(a,b) ((a)<(b)?(a):(b)) -#define MYMAX(a,b) ((a)>(b)?(a):(b)) - -/* Returns nearest 32-bit integer for given floating point number. <cmath> and <math.h> in VC++ don't provide round(). */ @@ -319,9 +310,9 @@ inline v3f intToFloat(v3s16 p, f32 d) } // Random helper. Usually d=BS -inline core::aabbox3d<f32> getNodeBox(v3s16 p, float d) +inline aabb3f getNodeBox(v3s16 p, float d) { - return core::aabbox3d<f32>( + return aabb3f( (float)p.X * d - 0.5*d, (float)p.Y * d - 0.5*d, (float)p.Z * d - 0.5*d, diff --git a/src/util/serialize.cpp b/src/util/serialize.cpp index c0168776e..99cb990f1 100644 --- a/src/util/serialize.cpp +++ b/src/util/serialize.cpp @@ -28,6 +28,77 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <iomanip> #include <vector> +SerializationError eof_ser_err("Attempted read past end of data"); + +//// +//// BufReader +//// + +bool BufReader::getStringNoEx(std::string *val) +{ + u16 num_chars; + if (!getU16NoEx(&num_chars)) + return false; + + if (pos + num_chars > size) { + pos -= sizeof(num_chars); + return false; + } + + val->assign((const char *)data + pos, num_chars); + pos += num_chars; + + return true; +} + +bool BufReader::getWideStringNoEx(std::wstring *val) +{ + u16 num_chars; + if (!getU16NoEx(&num_chars)) + return false; + + if (pos + num_chars * 2 > size) { + pos -= sizeof(num_chars); + return false; + } + + for (size_t i = 0; i != num_chars; i++) { + val->push_back(readU16(data + pos)); + pos += 2; + } + + return true; +} + +bool BufReader::getLongStringNoEx(std::string *val) +{ + u32 num_chars; + if (!getU32NoEx(&num_chars)) + return false; + + if (pos + num_chars > size) { + pos -= sizeof(num_chars); + return false; + } + + val->assign((const char *)data + pos, num_chars); + pos += num_chars; + + return true; +} + +bool BufReader::getRawDataNoEx(void *val, size_t len) +{ + if (pos + len > size) + return false; + + memcpy(val, data + pos, len); + pos += len; + + return true; +} + + //// //// String //// @@ -158,7 +229,7 @@ std::string deSerializeLongString(std::istream &is) Buffer<char> buf2(s_size); is.read(&buf2[0], s_size); - if (is.gcount() != s_size) + if ((u32)is.gcount() != s_size) throw SerializationError("deSerializeLongString: couldn't read all chars"); s.reserve(s_size); diff --git a/src/util/serialize.h b/src/util/serialize.h index bf0d9c863..36324a675 100644 --- a/src/util/serialize.h +++ b/src/util/serialize.h @@ -21,14 +21,27 @@ with this program; if not, write to the Free Software Foundation, Inc., #define UTIL_SERIALIZE_HEADER #include "../irrlichttypes_bloated.h" +#include "../exceptions.h" // for SerializationError #include "../debug.h" // for assert + #include "config.h" #if HAVE_ENDIAN_H -#include <endian.h> -#include <string.h> // for memcpy + #ifdef _WIN32 + #define __BYTE_ORDER 0 + #define __LITTLE_ENDIAN 0 + #define __BIG_ENDIAN 1 + #elif defined(__MACH__) && defined(__APPLE__) + #include <machine/endian.h> + #elif defined(__FreeBSD__) + #include <sys/endian.h> + #else + #include <endian.h> + #endif #endif +#include <string.h> // for memcpy #include <iostream> #include <string> +#include <vector> #define FIXEDPOINT_FACTOR 1000.0f @@ -405,4 +418,238 @@ bool serializeStructToString(std::string *out, bool deSerializeStringToStruct(std::string valstr, std::string format, void *out, size_t olen); +//// +//// BufReader +//// + +extern SerializationError eof_ser_err; + +#define MAKE_BUFREADER_GETNOEX_FXN(T, N, S) \ + inline bool get ## N ## NoEx(T *val) \ + { \ + if (pos + S > size) \ + return false; \ + *val = read ## N(data + pos); \ + pos += S; \ + return true; \ + } + +#define MAKE_BUFREADER_GET_FXN(T, N) \ + inline T get ## N() \ + { \ + T val; \ + if (!get ## N ## NoEx(&val)) \ + throw eof_ser_err; \ + return val; \ + } + +class BufReader { +public: + BufReader(const u8 *data_, size_t size_) : + data(data_), + size(size_), + pos(0) + { + } + + MAKE_BUFREADER_GETNOEX_FXN(u8, U8, 1); + MAKE_BUFREADER_GETNOEX_FXN(u16, U16, 2); + MAKE_BUFREADER_GETNOEX_FXN(u32, U32, 4); + MAKE_BUFREADER_GETNOEX_FXN(u64, U64, 8); + MAKE_BUFREADER_GETNOEX_FXN(s8, S8, 1); + MAKE_BUFREADER_GETNOEX_FXN(s16, S16, 2); + MAKE_BUFREADER_GETNOEX_FXN(s32, S32, 4); + MAKE_BUFREADER_GETNOEX_FXN(s64, S64, 8); + MAKE_BUFREADER_GETNOEX_FXN(f32, F1000, 4); + MAKE_BUFREADER_GETNOEX_FXN(v2s16, V2S16, 4); + MAKE_BUFREADER_GETNOEX_FXN(v3s16, V3S16, 6); + MAKE_BUFREADER_GETNOEX_FXN(v2s32, V2S32, 8); + MAKE_BUFREADER_GETNOEX_FXN(v3s32, V3S32, 12); + MAKE_BUFREADER_GETNOEX_FXN(v2f, V2F1000, 8); + MAKE_BUFREADER_GETNOEX_FXN(v3f, V3F1000, 12); + MAKE_BUFREADER_GETNOEX_FXN(video::SColor, ARGB8, 4); + + bool getStringNoEx(std::string *val); + bool getWideStringNoEx(std::wstring *val); + bool getLongStringNoEx(std::string *val); + bool getRawDataNoEx(void *data, size_t len); + + MAKE_BUFREADER_GET_FXN(u8, U8); + MAKE_BUFREADER_GET_FXN(u16, U16); + MAKE_BUFREADER_GET_FXN(u32, U32); + MAKE_BUFREADER_GET_FXN(u64, U64); + MAKE_BUFREADER_GET_FXN(s8, S8); + MAKE_BUFREADER_GET_FXN(s16, S16); + MAKE_BUFREADER_GET_FXN(s32, S32); + MAKE_BUFREADER_GET_FXN(s64, S64); + MAKE_BUFREADER_GET_FXN(f32, F1000); + MAKE_BUFREADER_GET_FXN(v2s16, V2S16); + MAKE_BUFREADER_GET_FXN(v3s16, V3S16); + MAKE_BUFREADER_GET_FXN(v2s32, V2S32); + MAKE_BUFREADER_GET_FXN(v3s32, V3S32); + MAKE_BUFREADER_GET_FXN(v2f, V2F1000); + MAKE_BUFREADER_GET_FXN(v3f, V3F1000); + MAKE_BUFREADER_GET_FXN(video::SColor, ARGB8); + MAKE_BUFREADER_GET_FXN(std::string, String); + MAKE_BUFREADER_GET_FXN(std::wstring, WideString); + MAKE_BUFREADER_GET_FXN(std::string, LongString); + + inline void getRawData(void *val, size_t len) + { + if (!getRawDataNoEx(val, len)) + throw eof_ser_err; + } + + inline size_t remaining() + { + assert(pos <= size); + return size - pos; + } + + const u8 *data; + size_t size; + size_t pos; +}; + +#undef MAKE_BUFREADER_GET_FXN +#undef MAKE_BUFREADER_GETNOEX_FXN + + +//// +//// Vector-based write routines +//// + +inline void putU8(std::vector<u8> *dest, u8 val) +{ + dest->push_back((val >> 0) & 0xFF); +} + +inline void putU16(std::vector<u8> *dest, u16 val) +{ + dest->push_back((val >> 8) & 0xFF); + dest->push_back((val >> 0) & 0xFF); +} + +inline void putU32(std::vector<u8> *dest, u32 val) +{ + dest->push_back((val >> 24) & 0xFF); + dest->push_back((val >> 16) & 0xFF); + dest->push_back((val >> 8) & 0xFF); + dest->push_back((val >> 0) & 0xFF); +} + +inline void putU64(std::vector<u8> *dest, u64 val) +{ + dest->push_back((val >> 56) & 0xFF); + dest->push_back((val >> 48) & 0xFF); + dest->push_back((val >> 40) & 0xFF); + dest->push_back((val >> 32) & 0xFF); + dest->push_back((val >> 24) & 0xFF); + dest->push_back((val >> 16) & 0xFF); + dest->push_back((val >> 8) & 0xFF); + dest->push_back((val >> 0) & 0xFF); +} + +inline void putS8(std::vector<u8> *dest, s8 val) +{ + putU8(dest, val); +} + +inline void putS16(std::vector<u8> *dest, s16 val) +{ + putU16(dest, val); +} + +inline void putS32(std::vector<u8> *dest, s32 val) +{ + putU32(dest, val); +} + +inline void putS64(std::vector<u8> *dest, s64 val) +{ + putU64(dest, val); +} + +inline void putF1000(std::vector<u8> *dest, f32 val) +{ + putS32(dest, val * FIXEDPOINT_FACTOR); +} + +inline void putV2S16(std::vector<u8> *dest, v2s16 val) +{ + putS16(dest, val.X); + putS16(dest, val.Y); +} + +inline void putV3S16(std::vector<u8> *dest, v3s16 val) +{ + putS16(dest, val.X); + putS16(dest, val.Y); + putS16(dest, val.Z); +} + +inline void putV2S32(std::vector<u8> *dest, v2s32 val) +{ + putS32(dest, val.X); + putS32(dest, val.Y); +} + +inline void putV3S32(std::vector<u8> *dest, v3s32 val) +{ + putS32(dest, val.X); + putS32(dest, val.Y); + putS32(dest, val.Z); +} + +inline void putV2F1000(std::vector<u8> *dest, v2f val) +{ + putF1000(dest, val.X); + putF1000(dest, val.Y); +} + +inline void putV3F1000(std::vector<u8> *dest, v3f val) +{ + putF1000(dest, val.X); + putF1000(dest, val.Y); + putF1000(dest, val.Z); +} + +inline void putARGB8(std::vector<u8> *dest, video::SColor val) +{ + putU32(dest, val.color); +} + +inline void putString(std::vector<u8> *dest, const std::string &val) +{ + if (val.size() > STRING_MAX_LEN) + throw SerializationError("String too long"); + + putU16(dest, val.size()); + dest->insert(dest->end(), val.begin(), val.end()); +} + +inline void putWideString(std::vector<u8> *dest, const std::wstring &val) +{ + if (val.size() > WIDE_STRING_MAX_LEN) + throw SerializationError("String too long"); + + putU16(dest, val.size()); + for (size_t i = 0; i != val.size(); i++) + putU16(dest, val[i]); +} + +inline void putLongString(std::vector<u8> *dest, const std::string &val) +{ + if (val.size() > LONG_STRING_MAX_LEN) + throw SerializationError("String too long"); + + putU32(dest, val.size()); + dest->insert(dest->end(), val.begin(), val.end()); +} + +inline void putRawData(std::vector<u8> *dest, const void *src, size_t len) +{ + dest->insert(dest->end(), (u8 *)src, (u8 *)src + len); +} + #endif diff --git a/src/util/srp.cpp b/src/util/srp.cpp index 94426db92..0d3c938a3 100644 --- a/src/util/srp.cpp +++ b/src/util/srp.cpp @@ -26,12 +26,14 @@ * */ +// clang-format off #ifdef WIN32 #include <windows.h> #include <wincrypt.h> #else #include <time.h> #endif +// clang-format on #include <stdlib.h> #include <string.h> @@ -69,124 +71,137 @@ static int g_initialized = 0; static unsigned int g_rand_idx; static unsigned char g_rand_buff[RAND_BUFF_MAX]; -typedef struct +void *(*srp_alloc)(size_t) = &malloc; +void *(*srp_realloc)(void *, size_t) = &realloc; +void (*srp_free)(void *) = &free; + +// clang-format off +void srp_set_memory_functions( + void *(*new_srp_alloc)(size_t), + void *(*new_srp_realloc)(void *, size_t), + void (*new_srp_free)(void *)) { + srp_alloc = new_srp_alloc; + srp_realloc = new_srp_realloc; + srp_free = new_srp_free; +} +// clang-format on + +typedef struct { mpz_t N; mpz_t g; } NGConstant; -struct NGHex -{ - const char* n_hex; - const char* g_hex; +struct NGHex { + const char *n_hex; + const char *g_hex; }; /* All constants here were pulled from Appendix A of RFC 5054 */ static struct NGHex global_Ng_constants[] = { - { /* 1024 */ - "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496" - "EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8E" - "F4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA" - "9AFD5138FE8376435B9FC61D2FC0EB06E3", - "2" - }, - { /* 2048 */ - "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4" - "A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60" - "95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF" - "747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907" - "8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861" - "60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB" - "FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", - "2" - }, - { /* 4096 */ - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" - "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" - "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" - "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" - "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" - "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" - "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" - "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" - "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" - "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" - "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" - "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" - "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" - "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" - "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" - "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" - "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" - "FFFFFFFFFFFFFFFF", - "5" - }, - { /* 8192 */ - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" - "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" - "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" - "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" - "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" - "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" - "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" - "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" - "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" - "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" - "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" - "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" - "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" - "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" - "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" - "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" - "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" - "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" - "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" - "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" - "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" - "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" - "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" - "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" - "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" - "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" - "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA" - "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C" - "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" - "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886" - "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6" - "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5" - "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268" - "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6" - "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" - "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", - "13" - }, - {0,0} /* null sentinel */ + {/* 1024 */ + "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" + "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" + "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" + "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" + "FD5138FE8376435B9FC61D2FC0EB06E3", + "2"}, + {/* 2048 */ + "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC319294" + "3DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310D" + "CD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FB" + "D5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF74" + "7359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A" + "436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D" + "5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E73" + "03CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6" + "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F" + "9E4AFF73", + "2"}, + {/* 4096 */ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" + "FFFFFFFFFFFFFFFF", + "5"}, + {/* 8192 */ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" + "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" + "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" + "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" + "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" + "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" + "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" + "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" + "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" + "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" + "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" + "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" + "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" + "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" + "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" + "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" + "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" + "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" + "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" + "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" + "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" + "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA" + "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C" + "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" + "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886" + "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6" + "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5" + "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268" + "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6" + "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", + "13"}, + {0, 0} /* null sentinel */ }; - static void delete_ng(NGConstant *ng) { if (ng) { mpz_clear(ng->N); mpz_clear(ng->g); - free(ng); + srp_free(ng); } } -static NGConstant *new_ng( SRP_NGType ng_type, const char *n_hex, const char *g_hex ) +static NGConstant *new_ng(SRP_NGType ng_type, const char *n_hex, const char *g_hex) { - NGConstant *ng = (NGConstant *) malloc(sizeof(NGConstant)); + NGConstant *ng = (NGConstant *)srp_alloc(sizeof(NGConstant)); + + if (!ng) return 0; + mpz_init(ng->N); mpz_init(ng->g); - if (!ng) - return 0; - if (ng_type != SRP_NG_CUSTOM) { - n_hex = global_Ng_constants[ ng_type ].n_hex; - g_hex = global_Ng_constants[ ng_type ].g_hex; + n_hex = global_Ng_constants[ng_type].n_hex; + g_hex = global_Ng_constants[ng_type].g_hex; } int rv = 0; @@ -201,17 +216,13 @@ static NGConstant *new_ng( SRP_NGType ng_type, const char *n_hex, const char *g_ return ng; } - -typedef union -{ - SHA_CTX sha; +typedef union { + SHA_CTX sha; SHA256_CTX sha256; - //SHA512_CTX sha512; + // SHA512_CTX sha512; } HashCTX; - -struct SRPVerifier -{ +struct SRPVerifier { SRP_HashAlgorithm hash_alg; NGConstant *ng; @@ -224,9 +235,7 @@ struct SRPVerifier unsigned char session_key[SHA512_DIGEST_LENGTH]; }; - -struct SRPUser -{ +struct SRPUser { SRP_HashAlgorithm hash_alg; NGConstant *ng; @@ -247,19 +256,23 @@ struct SRPUser unsigned char session_key[SHA512_DIGEST_LENGTH]; }; - +// clang-format off static int hash_init(SRP_HashAlgorithm alg, HashCTX *c) { switch (alg) { #ifdef CSRP_USE_SHA1 case SRP_SHA1: return SHA1_Init(&c->sha); #endif - /*case SRP_SHA224: return SHA224_Init(&c->sha256);*/ + /* + case SRP_SHA224: return SHA224_Init(&c->sha256); + */ #ifdef CSRP_USE_SHA256 case SRP_SHA256: return SHA256_Init(&c->sha256); #endif - /*case SRP_SHA384: return SHA384_Init(&c->sha512); - case SRP_SHA512: return SHA512_Init(&c->sha512);*/ + /* + case SRP_SHA384: return SHA384_Init(&c->sha512); + case SRP_SHA512: return SHA512_Init(&c->sha512); + */ default: return -1; }; } @@ -269,12 +282,16 @@ static int hash_update( SRP_HashAlgorithm alg, HashCTX *c, const void *data, siz #ifdef CSRP_USE_SHA1 case SRP_SHA1: return SHA1_Update(&c->sha, data, len); #endif - /*case SRP_SHA224: return SHA224_Update(&c->sha256, data, len);*/ + /* + case SRP_SHA224: return SHA224_Update(&c->sha256, data, len); + */ #ifdef CSRP_USE_SHA256 case SRP_SHA256: return SHA256_Update(&c->sha256, data, len); #endif - /*case SRP_SHA384: return SHA384_Update( &c->sha512, data, len ); - case SRP_SHA512: return SHA512_Update( &c->sha512, data, len );*/ + /* + case SRP_SHA384: return SHA384_Update(&c->sha512, data, len); + case SRP_SHA512: return SHA512_Update(&c->sha512, data, len); + */ default: return -1; }; } @@ -284,12 +301,16 @@ static int hash_final( SRP_HashAlgorithm alg, HashCTX *c, unsigned char *md ) #ifdef CSRP_USE_SHA1 case SRP_SHA1: return SHA1_Final(md, &c->sha); #endif - /*case SRP_SHA224: return SHA224_Final(md, &c->sha256);*/ + /* + case SRP_SHA224: return SHA224_Final(md, &c->sha256); + */ #ifdef CSRP_USE_SHA256 case SRP_SHA256: return SHA256_Final(md, &c->sha256); #endif - /*case SRP_SHA384: return SHA384_Final(md, &c->sha512); - case SRP_SHA512: return SHA512_Final(md, &c->sha512);*/ + /* + case SRP_SHA384: return SHA384_Final(md, &c->sha512); + case SRP_SHA512: return SHA512_Final(md, &c->sha512); + */ default: return -1; }; } @@ -299,12 +320,16 @@ static unsigned char *hash(SRP_HashAlgorithm alg, const unsigned char *d, size_t #ifdef CSRP_USE_SHA1 case SRP_SHA1: return SHA1(d, n, md); #endif - /*case SRP_SHA224: return SHA224( d, n, md );*/ + /* + case SRP_SHA224: return SHA224( d, n, md ); + */ #ifdef CSRP_USE_SHA256 case SRP_SHA256: return SHA256(d, n, md); #endif - /*case SRP_SHA384: return SHA384( d, n, md ); - case SRP_SHA512: return SHA512( d, n, md );*/ + /* + case SRP_SHA384: return SHA384( d, n, md ); + case SRP_SHA512: return SHA512( d, n, md ); + */ default: return 0; }; } @@ -314,19 +339,24 @@ static size_t hash_length(SRP_HashAlgorithm alg) #ifdef CSRP_USE_SHA1 case SRP_SHA1: return SHA_DIGEST_LENGTH; #endif - /*case SRP_SHA224: return SHA224_DIGEST_LENGTH;*/ + /* + case SRP_SHA224: return SHA224_DIGEST_LENGTH; + */ #ifdef CSRP_USE_SHA256 case SRP_SHA256: return SHA256_DIGEST_LENGTH; #endif - /*case SRP_SHA384: return SHA384_DIGEST_LENGTH; - case SRP_SHA512: return SHA512_DIGEST_LENGTH;*/ + /* + case SRP_SHA384: return SHA384_DIGEST_LENGTH; + case SRP_SHA512: return SHA512_DIGEST_LENGTH; + */ default: return -1; }; } +// clang-format on inline static int mpz_num_bytes(const mpz_t op) { - return (mpz_sizeinbase (op, 2) + 7) / 8; + return (mpz_sizeinbase(op, 2) + 7) / 8; } inline static void mpz_to_bin(const mpz_t op, unsigned char *to) @@ -340,72 +370,77 @@ inline static void mpz_from_bin(const unsigned char *s, size_t len, mpz_t ret) } // set op to (op1 * op2) mod d, using tmp for the calculation -inline static void mpz_mulm(mpz_t op, const mpz_t op1, const mpz_t op2, const mpz_t d, mpz_t tmp) +inline static void mpz_mulm( + mpz_t op, const mpz_t op1, const mpz_t op2, const mpz_t d, mpz_t tmp) { mpz_mul(tmp, op1, op2); mpz_mod(op, tmp, d); } // set op to (op1 + op2) mod d, using tmp for the calculation -inline static void mpz_addm( mpz_t op, const mpz_t op1, const mpz_t op2, const mpz_t d, mpz_t tmp ) +inline static void mpz_addm( + mpz_t op, const mpz_t op1, const mpz_t op2, const mpz_t d, mpz_t tmp) { mpz_add(tmp, op1, op2); mpz_mod(op, tmp, d); } // set op to (op1 - op2) mod d, using tmp for the calculation -inline static void mpz_subm(mpz_t op, const mpz_t op1, const mpz_t op2, const mpz_t d, mpz_t tmp) +inline static void mpz_subm( + mpz_t op, const mpz_t op1, const mpz_t op2, const mpz_t d, mpz_t tmp) { mpz_sub(tmp, op1, op2); mpz_mod(op, tmp, d); } -static int H_nn(mpz_t result, SRP_HashAlgorithm alg, const mpz_t N, const mpz_t n1, const mpz_t n2) +static SRP_Result H_nn( + mpz_t result, SRP_HashAlgorithm alg, const mpz_t N, const mpz_t n1, const mpz_t n2) { unsigned char buff[SHA512_DIGEST_LENGTH]; size_t len_N = mpz_num_bytes(N); size_t len_n1 = mpz_num_bytes(n1); size_t len_n2 = mpz_num_bytes(n2); size_t nbytes = len_N + len_N; - unsigned char *bin = (unsigned char *) malloc(nbytes); - if (!bin) - return 0; + unsigned char *bin = (unsigned char *)srp_alloc(nbytes); + if (!bin) return SRP_ERR; if (len_n1 > len_N || len_n2 > len_N) { - free(bin); - return 0; + srp_free(bin); + return SRP_ERR; } memset(bin, 0, nbytes); mpz_to_bin(n1, bin + (len_N - len_n1)); mpz_to_bin(n2, bin + (len_N + len_N - len_n2)); - hash( alg, bin, nbytes, buff ); - free(bin); + hash(alg, bin, nbytes, buff); + srp_free(bin); mpz_from_bin(buff, hash_length(alg), result); - return 1; + return SRP_OK; } -static int H_ns(mpz_t result, SRP_HashAlgorithm alg, const unsigned char *n, size_t len_n, const unsigned char *bytes, size_t len_bytes) +static SRP_Result H_ns(mpz_t result, SRP_HashAlgorithm alg, const unsigned char *n, + size_t len_n, const unsigned char *bytes, size_t len_bytes) { unsigned char buff[SHA512_DIGEST_LENGTH]; size_t nbytes = len_n + len_bytes; - unsigned char *bin = (unsigned char *) malloc(nbytes); - if (!bin) - return 0; + unsigned char *bin = (unsigned char *)srp_alloc(nbytes); + if (!bin) return SRP_ERR; memcpy(bin, n, len_n); memcpy(bin + len_n, bytes, len_bytes); hash(alg, bin, nbytes, buff); - free(bin); + srp_free(bin); mpz_from_bin(buff, hash_length(alg), result); - return 1; + return SRP_OK; } -static int calculate_x(mpz_t result, SRP_HashAlgorithm alg, const unsigned char *salt, size_t salt_len, const char *username, const unsigned char *password, size_t password_len) +static int calculate_x(mpz_t result, SRP_HashAlgorithm alg, const unsigned char *salt, + size_t salt_len, const char *username, const unsigned char *password, + size_t password_len) { unsigned char ucp_hash[SHA512_DIGEST_LENGTH]; HashCTX ctx; hash_init(alg, &ctx); - srp_dbg_data((char*) username, strlen(username), "Username for x: "); - srp_dbg_data((char*) password, password_len, "Password for x: "); + srp_dbg_data((char *)username, strlen(username), "Username for x: "); + srp_dbg_data((char *)password, password_len, "Password for x: "); hash_update(alg, &ctx, username, strlen(username)); hash_update(alg, &ctx, ":", 1); hash_update(alg, &ctx, password, password_len); @@ -415,31 +450,31 @@ static int calculate_x(mpz_t result, SRP_HashAlgorithm alg, const unsigned char return H_ns(result, alg, salt, salt_len, ucp_hash, hash_length(alg)); } -static void update_hash_n(SRP_HashAlgorithm alg, HashCTX *ctx, const mpz_t n) +static SRP_Result update_hash_n(SRP_HashAlgorithm alg, HashCTX *ctx, const mpz_t n) { size_t len = mpz_num_bytes(n); - unsigned char* n_bytes = (unsigned char *) malloc(len); - if (!n_bytes) - return; + unsigned char *n_bytes = (unsigned char *)srp_alloc(len); + if (!n_bytes) return SRP_ERR; mpz_to_bin(n, n_bytes); hash_update(alg, ctx, n_bytes, len); - free(n_bytes); + srp_free(n_bytes); + return SRP_OK; } -static void hash_num( SRP_HashAlgorithm alg, const mpz_t n, unsigned char *dest ) +static SRP_Result hash_num(SRP_HashAlgorithm alg, const mpz_t n, unsigned char *dest) { int nbytes = mpz_num_bytes(n); - unsigned char *bin = (unsigned char *) malloc(nbytes); - if(!bin) - return; + unsigned char *bin = (unsigned char *)srp_alloc(nbytes); + if (!bin) return SRP_ERR; mpz_to_bin(n, bin); hash(alg, bin, nbytes, dest); - free(bin); + srp_free(bin); + return SRP_OK; } -static void calculate_M(SRP_HashAlgorithm alg, NGConstant *ng, unsigned char *dest, - const char *I, const unsigned char *s_bytes, size_t s_len, - const mpz_t A, const mpz_t B, const unsigned char *K) +static SRP_Result calculate_M(SRP_HashAlgorithm alg, NGConstant *ng, unsigned char *dest, + const char *I, const unsigned char *s_bytes, size_t s_len, const mpz_t A, + const mpz_t B, const unsigned char *K) { unsigned char H_N[SHA512_DIGEST_LENGTH]; unsigned char H_g[SHA512_DIGEST_LENGTH]; @@ -449,13 +484,12 @@ static void calculate_M(SRP_HashAlgorithm alg, NGConstant *ng, unsigned char *de size_t i = 0; size_t hash_len = hash_length(alg); - hash_num(alg, ng->N, H_N); - hash_num(alg, ng->g, H_g); + if (!hash_num(alg, ng->N, H_N)) return SRP_ERR; + if (!hash_num(alg, ng->g, H_g)) return SRP_ERR; hash(alg, (const unsigned char *)I, strlen(I), H_I); - - for (i = 0; i < hash_len; i++ ) + for (i = 0; i < hash_len; i++) H_xor[i] = H_N[i] ^ H_g[i]; hash_init(alg, &ctx); @@ -463,54 +497,30 @@ static void calculate_M(SRP_HashAlgorithm alg, NGConstant *ng, unsigned char *de hash_update(alg, &ctx, H_xor, hash_len); hash_update(alg, &ctx, H_I, hash_len); hash_update(alg, &ctx, s_bytes, s_len); - update_hash_n(alg, &ctx, A); - update_hash_n(alg, &ctx, B); + if (!update_hash_n(alg, &ctx, A)) return SRP_ERR; + if (!update_hash_n(alg, &ctx, B)) return SRP_ERR; hash_update(alg, &ctx, K, hash_len); hash_final(alg, &ctx, dest); + return SRP_OK; } -static void calculate_H_AMK(SRP_HashAlgorithm alg, unsigned char *dest, const mpz_t A, const unsigned char *M, const unsigned char *K) +static SRP_Result calculate_H_AMK(SRP_HashAlgorithm alg, unsigned char *dest, + const mpz_t A, const unsigned char *M, const unsigned char *K) { HashCTX ctx; hash_init(alg, &ctx); - update_hash_n(alg, &ctx, A); + if (!update_hash_n(alg, &ctx, A)) return SRP_ERR; hash_update(alg, &ctx, M, hash_length(alg)); hash_update(alg, &ctx, K, hash_length(alg)); hash_final(alg, &ctx, dest); + return SRP_OK; } - -struct srp_pcgrandom { - unsigned long long int m_state; - unsigned long long int m_inc; -}; typedef struct srp_pcgrandom srp_pcgrandom; - -static unsigned long int srp_pcgrandom_next(srp_pcgrandom *r) -{ - unsigned long long int oldstate = r->m_state; - r->m_state = oldstate * 6364136223846793005ULL + r->m_inc; - - unsigned long int xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; - unsigned long int rot = oldstate >> 59u; - return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); -} - -static void srp_pcgrandom_seed(srp_pcgrandom *r, unsigned long long int state, - unsigned long long int seq) -{ - r->m_state = 0U; - r->m_inc = (seq << 1u) | 1u; - srp_pcgrandom_next(r); - r->m_state += state; - srp_pcgrandom_next(r); -} - - -static int fill_buff() +static SRP_Result fill_buff() { g_rand_idx = 0; @@ -522,54 +532,48 @@ static int fill_buff() #ifdef WIN32 - CryptAcquireContext(&wctx, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); - CryptGenRandom(wctx, sizeof(g_rand_buff), (BYTE*) g_rand_buff); - CryptReleaseContext(wctx, 0); - - return 1; + if (!CryptAcquireContext(&wctx, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + return SRP_ERR; + if (!CryptGenRandom(wctx, sizeof(g_rand_buff), (BYTE *)g_rand_buff)) return SRP_ERR; + if (!CryptReleaseContext(wctx, 0)) return SRP_ERR; #else fp = fopen("/dev/urandom", "r"); - if (fp) { - fread(g_rand_buff, sizeof(g_rand_buff), 1, fp); - fclose(fp); - } else { - srp_pcgrandom *r = (srp_pcgrandom *) malloc(sizeof(srp_pcgrandom)); - srp_pcgrandom_seed(r, time(NULL) ^ clock(), 0xda3e39cb94b95bdbULL); - size_t i = 0; - for (i = 0; i < RAND_BUFF_MAX; i++) { - g_rand_buff[i] = srp_pcgrandom_next(r); - } - } + if (!fp) return SRP_ERR; + + if (fread(g_rand_buff, sizeof(g_rand_buff), 1, fp) != 1) return SRP_ERR; + if (fclose(fp)) return SRP_ERR; #endif - return 1; + return SRP_OK; } -static void mpz_fill_random(mpz_t num) +static SRP_Result mpz_fill_random(mpz_t num) { // was call: BN_rand(num, 256, -1, 0); if (RAND_BUFF_MAX - g_rand_idx < 32) - fill_buff(); - mpz_from_bin((const unsigned char *) (&g_rand_buff[g_rand_idx]), 32, num); + if (fill_buff() != SRP_OK) return SRP_ERR; + mpz_from_bin((const unsigned char *)(&g_rand_buff[g_rand_idx]), 32, num); g_rand_idx += 32; + return SRP_OK; } -static void init_random() +static SRP_Result init_random() { - if (g_initialized) - return; - g_initialized = fill_buff(); + if (g_initialized) return SRP_OK; + SRP_Result ret = fill_buff(); + g_initialized = (ret == SRP_OK); + return ret; } #define srp_dbg_num(num, text) ; /*void srp_dbg_num(mpz_t num, char * prevtext) { int len_num = mpz_num_bytes(num); - char *bytes_num = (char*) malloc(len_num); + char *bytes_num = (char*) srp_alloc(len_num); mpz_to_bin(num, (unsigned char *) bytes_num); srp_dbg_data(bytes_num, len_num, prevtext); - free(bytes_num); + srp_free(bytes_num); }*/ @@ -579,35 +583,41 @@ static void init_random() * ***********************************************************************************************************/ -void srp_create_salted_verification_key( SRP_HashAlgorithm alg, +// clang-format off +SRP_Result 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 ) { + SRP_Result ret = SRP_OK; + mpz_t v; mpz_init(v); mpz_t x; mpz_init(x); + // clang-format on + NGConstant *ng = new_ng(ng_type, n_hex, g_hex); - if(!ng) - goto cleanup_and_exit; + if (!ng) goto error_and_exit; - init_random(); /* Only happens once */ + if (init_random() != SRP_OK) /* Only happens once */ + goto error_and_exit; if (*bytes_s == NULL) { - *len_s = 16; - if (RAND_BUFF_MAX - g_rand_idx < 16) - fill_buff(); - *bytes_s = (unsigned char*)malloc(sizeof(char) * 16); - memcpy(*bytes_s, &g_rand_buff + g_rand_idx, sizeof(char) * 16); - g_rand_idx += 16; + size_t size_to_fill = 16; + *len_s = size_to_fill; + if (RAND_BUFF_MAX - g_rand_idx < size_to_fill) + if (fill_buff() != SRP_OK) goto error_and_exit; + *bytes_s = (unsigned char *)srp_alloc(size_to_fill); + if (!*bytes_s) goto error_and_exit; + memcpy(*bytes_s, &g_rand_buff + g_rand_idx, size_to_fill); + g_rand_idx += size_to_fill; } - - if (!calculate_x(x, alg, *bytes_s, *len_s, username_for_verifier, - password, len_password)) - goto cleanup_and_exit; + if (!calculate_x( + x, alg, *bytes_s, *len_s, username_for_verifier, password, len_password)) + goto error_and_exit; srp_dbg_num(x, "Server calculated x: "); @@ -615,20 +625,23 @@ void srp_create_salted_verification_key( SRP_HashAlgorithm alg, *len_v = mpz_num_bytes(v); - *bytes_v = (unsigned char*)malloc(*len_v); + *bytes_v = (unsigned char *)srp_alloc(*len_v); - if (!bytes_v) - goto cleanup_and_exit; + if (!*bytes_v) goto error_and_exit; mpz_to_bin(v, *bytes_v); cleanup_and_exit: - delete_ng( ng ); + delete_ng(ng); mpz_clear(v); mpz_clear(x); + return ret; +error_and_exit: + ret = SRP_ERR; + goto cleanup_and_exit; } - +// clang-format off /* Out: bytes_B, len_B. * @@ -653,6 +666,7 @@ struct SRPVerifier *srp_verifier_new(SRP_HashAlgorithm alg, mpz_t tmp1; mpz_init(tmp1); mpz_t tmp2; mpz_init(tmp2); mpz_t tmp3; mpz_init(tmp3); + // clang-format on size_t ulen = strlen(username) + 1; NGConstant *ng = new_ng(ng_type, n_hex, g_hex); struct SRPVerifier *ver = 0; @@ -660,27 +674,29 @@ struct SRPVerifier *srp_verifier_new(SRP_HashAlgorithm alg, *len_B = 0; *bytes_B = 0; - if (!ng) - goto cleanup_and_exit; + if (!ng) goto cleanup_and_exit; - ver = (struct SRPVerifier *) malloc( sizeof(struct SRPVerifier) ); + ver = (struct SRPVerifier *)srp_alloc(sizeof(struct SRPVerifier)); - if (!ver) - goto cleanup_and_exit; + if (!ver) goto cleanup_and_exit; - init_random(); /* Only happens once */ + if (init_random() != SRP_OK) { /* Only happens once */ + srp_free(ver); + ver = 0; + goto cleanup_and_exit; + } - ver->username = (char *) malloc(ulen); + ver->username = (char *)srp_alloc(ulen); ver->hash_alg = alg; ver->ng = ng; if (!ver->username) { - free(ver); + srp_free(ver); ver = 0; goto cleanup_and_exit; } - memcpy((char*)ver->username, username, ulen); + memcpy((char *)ver->username, username, ulen); ver->authenticated = 0; @@ -690,25 +706,17 @@ struct SRPVerifier *srp_verifier_new(SRP_HashAlgorithm alg, if (bytes_b) { mpz_from_bin(bytes_b, len_b, b); } else { - mpz_fill_random(b); + if (!mpz_fill_random(b)) goto ver_cleanup_and_exit; } - if (!H_nn(k, alg, ng->N, ng->N, ng->g)) { - free(ver); - ver = 0; - goto cleanup_and_exit; - } + if (!H_nn(k, alg, ng->N, ng->N, ng->g)) goto ver_cleanup_and_exit; /* B = kv + g^b */ mpz_mulm(tmp1, k, v, ng->N, tmp3); mpz_powm(tmp2, ng->g, b, ng->N); mpz_addm(B, tmp1, tmp2, ng->N, tmp3); - if (!H_nn(u, alg, ng->N, A, B)) { - free(ver); - ver = 0; - goto cleanup_and_exit; - } + if (!H_nn(u, alg, ng->N, A, B)) goto ver_cleanup_and_exit; srp_dbg_num(u, "Server calculated u: "); @@ -717,27 +725,29 @@ struct SRPVerifier *srp_verifier_new(SRP_HashAlgorithm alg, mpz_mulm(tmp2, A, tmp1, ng->N, tmp3); mpz_powm(S, tmp2, b, ng->N); - hash_num(alg, S, ver->session_key); + if (!hash_num(alg, S, ver->session_key)) goto ver_cleanup_and_exit; - calculate_M(alg, ng, ver->M, username, bytes_s, len_s, A, B, ver->session_key); - calculate_H_AMK(alg, ver->H_AMK, A, ver->M, ver->session_key); + if (!calculate_M( + alg, ng, ver->M, username, bytes_s, len_s, A, B, ver->session_key)) { + goto ver_cleanup_and_exit; + } + if (!calculate_H_AMK(alg, ver->H_AMK, A, ver->M, ver->session_key)) { + goto ver_cleanup_and_exit; + } *len_B = mpz_num_bytes(B); - *bytes_B = (unsigned char*)malloc(*len_B); + *bytes_B = (unsigned char *)srp_alloc(*len_B); if (!*bytes_B) { - free(ver->username); - free(ver); - ver = 0; *len_B = 0; - goto cleanup_and_exit; + goto ver_cleanup_and_exit; } mpz_to_bin(B, *bytes_B); ver->bytes_B = *bytes_B; } else { - free(ver); + srp_free(ver); ver = 0; } @@ -753,52 +763,49 @@ cleanup_and_exit: mpz_clear(tmp2); mpz_clear(tmp3); return ver; +ver_cleanup_and_exit: + srp_free(ver->username); + srp_free(ver); + ver = 0; + goto cleanup_and_exit; } - - - void srp_verifier_delete(struct SRPVerifier *ver) { if (ver) { delete_ng(ver->ng); - free(ver->username); - free(ver->bytes_B); + srp_free(ver->username); + srp_free(ver->bytes_B); memset(ver, 0, sizeof(*ver)); - free(ver); + srp_free(ver); } } - - int srp_verifier_is_authenticated(struct SRPVerifier *ver) { return ver->authenticated; } - const char *srp_verifier_get_username(struct SRPVerifier *ver) { return ver->username; } - -const unsigned char *srp_verifier_get_session_key(struct SRPVerifier *ver, size_t *key_length) +const unsigned char *srp_verifier_get_session_key( + struct SRPVerifier *ver, size_t *key_length) { - if (key_length) - *key_length = hash_length(ver->hash_alg); + if (key_length) *key_length = hash_length(ver->hash_alg); return ver->session_key; } - size_t srp_verifier_get_session_key_length(struct SRPVerifier *ver) { return hash_length(ver->hash_alg); } - /* user_M must be exactly SHA512_DIGEST_LENGTH bytes in size */ -void srp_verifier_verify_session(struct SRPVerifier *ver, const unsigned char *user_M, unsigned char **bytes_HAMK) +void srp_verifier_verify_session( + struct SRPVerifier *ver, const unsigned char *user_M, unsigned char **bytes_HAMK) { if (memcmp(ver->M, user_M, hash_length(ver->hash_alg)) == 0) { ver->authenticated = 1; @@ -811,17 +818,17 @@ void srp_verifier_verify_session(struct SRPVerifier *ver, const unsigned char *u 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) + const unsigned char *bytes_password, size_t len_password, const char *n_hex, + const char *g_hex) { - struct SRPUser *usr = (struct SRPUser *) malloc(sizeof(struct SRPUser)); - size_t ulen = strlen(username) + 1; + struct SRPUser *usr = (struct SRPUser *)srp_alloc(sizeof(struct SRPUser)); + size_t ulen = strlen(username) + 1; size_t uvlen = strlen(username_for_verifier) + 1; - if (!usr) - goto err_exit; + if (!usr) goto err_exit; - init_random(); /* Only happens once */ + if (init_random() != SRP_OK) /* Only happens once */ + goto err_exit; usr->hash_alg = alg; usr->ng = new_ng(ng_type, n_hex, g_hex); @@ -830,16 +837,14 @@ struct SRPUser *srp_user_new(SRP_HashAlgorithm alg, SRP_NGType ng_type, mpz_init(usr->A); mpz_init(usr->S); - if (!usr->ng) - goto err_exit; + if (!usr->ng) goto err_exit; - usr->username = (char*)malloc(ulen); - usr->username_verifier = (char*)malloc(uvlen); - usr->password = (unsigned char*)malloc(len_password); + usr->username = (char *)srp_alloc(ulen); + usr->username_verifier = (char *)srp_alloc(uvlen); + usr->password = (unsigned char *)srp_alloc(len_password); usr->password_len = len_password; - if (!usr->username || !usr->password) - goto err_exit; + if (!usr->username || !usr->password || !usr->username_verifier) goto err_exit; memcpy(usr->username, username, ulen); memcpy(usr->username_verifier, username_for_verifier, uvlen); @@ -856,27 +861,22 @@ err_exit: mpz_clear(usr->a); mpz_clear(usr->A); mpz_clear(usr->S); - if (usr->ng) - delete_ng(usr->ng); - if (usr->username) - free(usr->username); - if (usr->username_verifier) - free(usr->username_verifier); + if (usr->ng) delete_ng(usr->ng); + srp_free(usr->username); + srp_free(usr->username_verifier); if (usr->password) { memset(usr->password, 0, usr->password_len); - free(usr->password); + srp_free(usr->password); } - free(usr); + srp_free(usr); } return 0; } - - void srp_user_delete(struct SRPUser *usr) { - if(usr) { + if (usr) { mpz_clear(usr->a); mpz_clear(usr->A); mpz_clear(usr->S); @@ -885,77 +885,73 @@ void srp_user_delete(struct SRPUser *usr) memset(usr->password, 0, usr->password_len); - free(usr->username); - free(usr->username_verifier); - free(usr->password); + srp_free(usr->username); + srp_free(usr->username_verifier); + srp_free(usr->password); - if (usr->bytes_A) - free(usr->bytes_A); + if (usr->bytes_A) srp_free(usr->bytes_A); memset(usr, 0, sizeof(*usr)); - free(usr); + srp_free(usr); } } - - int srp_user_is_authenticated(struct SRPUser *usr) { return usr->authenticated; } - const char *srp_user_get_username(struct SRPUser *usr) { return usr->username; } - -const unsigned char* srp_user_get_session_key(struct SRPUser* usr, size_t* key_length) +const unsigned char *srp_user_get_session_key(struct SRPUser *usr, size_t *key_length) { - if (key_length) - *key_length = hash_length(usr->hash_alg); + if (key_length) *key_length = hash_length(usr->hash_alg); return usr->session_key; } - size_t srp_user_get_session_key_length(struct SRPUser *usr) { return hash_length(usr->hash_alg); } - +// clang-format off /* Output: username, bytes_A, len_A */ -void srp_user_start_authentication(struct SRPUser *usr, char **username, +SRP_Result 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) { + // clang-format on if (bytes_a) { mpz_from_bin(bytes_a, len_a, usr->a); } else { - mpz_fill_random(usr->a); + if (!mpz_fill_random(usr->a)) goto error_and_exit; } mpz_powm(usr->A, usr->ng->g, usr->a, usr->ng->N); *len_A = mpz_num_bytes(usr->A); - *bytes_A = (unsigned char*)malloc(*len_A); + *bytes_A = (unsigned char *)srp_alloc(*len_A); - if (!*bytes_A) { - *len_A = 0; - *bytes_A = 0; - *username = 0; - return; - } + if (!*bytes_A) goto error_and_exit; mpz_to_bin(usr->A, *bytes_A); usr->bytes_A = *bytes_A; - if (username) - *username = usr->username; -} + if (username) *username = usr->username; + return SRP_OK; + +error_and_exit: + *len_A = 0; + *bytes_A = 0; + *username = 0; + return SRP_ERR; +} +// clang-format off /* Output: bytes_M. Buffer length is SHA512_DIGEST_LENGTH */ void srp_user_process_challenge(struct SRPUser *usr, const unsigned char *bytes_s, size_t len_s, @@ -971,17 +967,17 @@ void srp_user_process_challenge(struct SRPUser *usr, mpz_t tmp2; mpz_init(tmp2); mpz_t tmp3; mpz_init(tmp3); mpz_t tmp4; mpz_init(tmp4); + // clang-format on *len_M = 0; *bytes_M = 0; - if (!H_nn(u, usr->hash_alg, usr->ng->N, usr->A, B)) - goto cleanup_and_exit; + if (!H_nn(u, usr->hash_alg, usr->ng->N, usr->A, B)) goto cleanup_and_exit; srp_dbg_num(u, "Client calculated u: "); - if (!calculate_x(x, usr->hash_alg, bytes_s, len_s, - usr->username_verifier, usr->password, usr->password_len)) + if (!calculate_x(x, usr->hash_alg, bytes_s, len_s, usr->username_verifier, + usr->password, usr->password_len)) goto cleanup_and_exit; srp_dbg_num(x, "Client calculated x: "); @@ -990,11 +986,12 @@ void srp_user_process_challenge(struct SRPUser *usr, goto cleanup_and_exit; /* SRP-6a safety check */ - if ( mpz_sgn(B) != 0 && mpz_sgn(u) != 0 ) { + if (mpz_sgn(B) != 0 && mpz_sgn(u) != 0) { mpz_powm(v, usr->ng->g, x, usr->ng->N); srp_dbg_num(v, "Client calculated v: "); + // clang-format off /* S = (B - k*(g^x)) ^ (a + ux) */ mpz_mul(tmp1, u, x); mpz_add(tmp2, usr->a, tmp1); /* tmp2 = (a + ux) */ @@ -1002,23 +999,24 @@ void srp_user_process_challenge(struct SRPUser *usr, mpz_mulm(tmp3, k, tmp1, usr->ng->N, tmp4); /* tmp3 = k*(g^x) */ mpz_subm(tmp1, B, tmp3, usr->ng->N, tmp4); /* tmp1 = (B - K*(g^x)) */ mpz_powm(usr->S, tmp1, tmp2, usr->ng->N); + // clang-format on - hash_num(usr->hash_alg, usr->S, usr->session_key); + if (!hash_num(usr->hash_alg, usr->S, usr->session_key)) goto cleanup_and_exit; - calculate_M( usr->hash_alg, usr->ng, usr->M, usr->username, bytes_s, len_s, usr->A,B, usr->session_key ); - calculate_H_AMK( usr->hash_alg, usr->H_AMK, usr->A, usr->M, usr->session_key ); + if (!calculate_M(usr->hash_alg, usr->ng, usr->M, usr->username, bytes_s, len_s, + usr->A, B, usr->session_key)) + goto cleanup_and_exit; + if (!calculate_H_AMK(usr->hash_alg, usr->H_AMK, usr->A, usr->M, usr->session_key)) + goto cleanup_and_exit; *bytes_M = usr->M; - if (len_M) - *len_M = hash_length( usr->hash_alg ); + if (len_M) *len_M = hash_length(usr->hash_alg); } else { *bytes_M = NULL; - if (len_M) - *len_M = 0; + if (len_M) *len_M = 0; } cleanup_and_exit: - mpz_clear(B); mpz_clear(u); mpz_clear(x); @@ -1030,7 +1028,6 @@ cleanup_and_exit: mpz_clear(tmp4); } - void srp_user_verify_session(struct SRPUser *usr, const unsigned char *bytes_HAMK) { if (memcmp(usr->H_AMK, bytes_HAMK, hash_length(usr->hash_alg)) == 0) diff --git a/src/util/srp.h b/src/util/srp.h index 15a2b8a68..2d49b076e 100644 --- a/src/util/srp.h +++ b/src/util/srp.h @@ -56,12 +56,10 @@ #ifndef SRP_H #define SRP_H - struct SRPVerifier; struct SRPUser; -typedef enum -{ +typedef enum { SRP_NG_1024, SRP_NG_2048, SRP_NG_4096, @@ -69,8 +67,7 @@ typedef enum SRP_NG_CUSTOM } SRP_NGType; -typedef enum -{ +typedef enum { /*SRP_SHA1,*/ /*SRP_SHA224,*/ SRP_SHA256, @@ -78,6 +75,23 @@ typedef enum SRP_SHA512*/ } SRP_HashAlgorithm; +typedef enum { + SRP_ERR, + SRP_OK, +} SRP_Result; + +// clang-format off + +/* Sets the memory functions used by srp. + * Note: this doesn't set the memory functions used by gmp, + * but it is supported to have different functions for srp and gmp. + * Don't call this after you have already allocated srp structures. + */ +void srp_set_memory_functions( + void *(*new_srp_alloc) (size_t), + void *(*new_srp_realloc) (void *, size_t), + void (*new_srp_free) (void *)); + /* Out: bytes_v, len_v * * The caller is responsible for freeing the memory allocated for bytes_v @@ -85,14 +99,18 @@ typedef enum * 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. + * If bytes_s == NULL, it is filled with random data. + * The caller is responsible for freeing. + * + * Returns SRP_OK on success, and SRP_ERR on error. + * bytes_s might be in this case invalid, don't free it. */ -void srp_create_salted_verification_key( SRP_HashAlgorithm alg, +SRP_Result 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 ); + const char *n_hex, const char *g_hex); /* Out: bytes_B, len_B. * @@ -101,6 +119,8 @@ void srp_create_salted_verification_key( SRP_HashAlgorithm alg, * 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. + * + * Returns pointer to SRPVerifier on success, and NULL on error. */ struct SRPVerifier* srp_verifier_new(SRP_HashAlgorithm alg, SRP_NGType ng_type, const char *username, @@ -111,52 +131,54 @@ struct SRPVerifier* srp_verifier_new(SRP_HashAlgorithm alg, SRP_NGType ng_type, unsigned char** bytes_B, size_t *len_B, const char* n_hex, const char* g_hex); +// clang-format on -void srp_verifier_delete( struct SRPVerifier* ver ); +void srp_verifier_delete(struct SRPVerifier *ver); +// srp_verifier_verify_session must have been called before +int srp_verifier_is_authenticated(struct SRPVerifier *ver); -int srp_verifier_is_authenticated( struct SRPVerifier* ver ); - - -const char * srp_verifier_get_username( 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); +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 ); +/* Verifies session, on success, it writes bytes_HAMK. + * 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); + const unsigned char *bytes_password, size_t len_password, const char *n_hex, + const char *g_hex); -void srp_user_delete(struct SRPUser * usr); +void srp_user_delete(struct SRPUser *usr); -int srp_user_is_authenticated(struct SRPUser * usr); +int srp_user_is_authenticated(struct SRPUser *usr); - -const char* srp_user_get_username(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); +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); -size_t srp_user_get_session_key_length(struct SRPUser* usr); +// clang-format off -/* Output: username, bytes_A, len_A. If you don't want it get written, set username to NULL. +/* 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); +SRP_Result 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) */ @@ -164,8 +186,9 @@ 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); +// clang-format on /* 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); +void srp_user_verify_session(struct SRPUser *usr, const unsigned char *bytes_HAMK); #endif /* Include Guard */ diff --git a/src/util/strfnd.h b/src/util/strfnd.h new file mode 100644 index 000000000..a7cd2badb --- /dev/null +++ b/src/util/strfnd.h @@ -0,0 +1,82 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.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 STRFND_HEADER +#define STRFND_HEADER + +#include <string> + +template <typename T> +class BasicStrfnd { + typedef std::basic_string<T> String; + String str; + size_t pos; +public: + BasicStrfnd(const String &s) : str(s), pos(0) {} + void start(const String &s) { str = s; pos = 0; } + size_t where() { return pos; } + void to(size_t i) { pos = i; } + bool at_end() { return pos >= str.size(); } + String what() { return str; } + + String next(const String &sep) + { + if (pos >= str.size()) + return String(); + + size_t n; + if (sep.empty() || (n = str.find(sep, pos)) == String::npos) { + n = str.size(); + } + String ret = str.substr(pos, n - pos); + pos = n + sep.size(); + return ret; + } + + // Returns substr up to the next occurence of sep that isn't escaped with esc ('\\') + String next_esc(const String &sep, T esc=static_cast<T>('\\')) + { + if (pos >= str.size()) + return String(); + + size_t n, old_p = pos; + do { + if (sep.empty() || (n = str.find(sep, pos)) == String::npos) { + pos = n = str.size(); + break; + } + pos = n + sep.length(); + } while (n > 0 && str[n - 1] == esc); + + return str.substr(old_p, n - old_p); + } + + void skip_over(const String &chars) + { + size_t p = str.find_first_not_of(chars, pos); + if (p != String::npos) + pos = p; + } +}; + +typedef BasicStrfnd<char> Strfnd; +typedef BasicStrfnd<wchar_t> WStrfnd; + +#endif + diff --git a/src/util/string.h b/src/util/string.h index 793baad0e..40ef3e4d3 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -32,8 +32,26 @@ with this program; if not, write to the Free Software Foundation, Inc., #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) +// Checks whether a value is an ASCII printable character +#define IS_ASCII_PRINTABLE_CHAR(x) \ + (((unsigned int)(x) >= 0x20) && \ + ( (unsigned int)(x) <= 0x7e)) + // Checks whether a byte is an inner byte for an utf-8 multibyte sequence -#define IS_UTF8_MULTB_INNER(x) (((unsigned char)x >= 0x80) && ((unsigned char)x < 0xc0)) +#define IS_UTF8_MULTB_INNER(x) \ + (((unsigned char)(x) >= 0x80) && \ + ( (unsigned char)(x) <= 0xbf)) + +// Checks whether a byte is a start byte for an utf-8 multibyte sequence +#define IS_UTF8_MULTB_START(x) \ + (((unsigned char)(x) >= 0xc2) && \ + ( (unsigned char)(x) <= 0xf4)) + +// Given a start byte x for an utf-8 multibyte sequence +// it gives the length of the whole sequence in bytes. +#define UTF8_MULTB_START_LEN(x) \ + (((unsigned char)(x) < 0xe0) ? 2 : \ + (((unsigned char)(x) < 0xf0) ? 3 : 4)) typedef std::map<std::string, std::string> StringMap; @@ -281,15 +299,6 @@ inline s32 mystoi(const std::string &str, s32 min, s32 max) } -/// Returns a 64-bit value represented by the string \p str (decimal). -inline s64 stoi64(const std::string &str) -{ - std::stringstream tmp(str); - s64 t; - tmp >> t; - return t; -} - // MSVC2010 includes it's own versions of these //#if !defined(_MSC_VER) || _MSC_VER < 1600 @@ -328,9 +337,22 @@ inline float mystof(const std::string &str) #define stoi mystoi #define stof mystof +/// Returns a value represented by the string \p val. +template <typename T> +inline T from_string(const std::string &str) +{ + std::stringstream tmp(str); + T t; + tmp >> t; + return t; +} + +/// Returns a 64-bit signed value represented by the string \p str (decimal). +inline s64 stoi64(const std::string &str) { return from_string<s64>(str); } + // TODO: Replace with C++11 std::to_string. -/// Returns A string representing the value \p val. +/// Returns a string representing the value \p val. template <typename T> inline std::string to_string(T val) { @@ -364,7 +386,6 @@ inline void str_replace(std::string &str, const std::string &pattern, } } - /** * Replace all occurrences of the character \p from in \p str with \p to. * @@ -447,7 +468,7 @@ inline std::string wrap_rows(const std::string &from, * Removes backslashes from an escaped string (FormSpec strings) */ template <typename T> -inline std::basic_string<T> unescape_string(std::basic_string<T> &s) +inline std::basic_string<T> unescape_string(const std::basic_string<T> &s) { std::basic_string<T> res; @@ -463,6 +484,40 @@ inline std::basic_string<T> unescape_string(std::basic_string<T> &s) return res; } +/** + * Remove all escape sequences in \p s. + * + * @param s The string in which to remove escape sequences. + * @return \p s, with escape sequences removed. + */ +template <typename T> +std::basic_string<T> unescape_enriched(const std::basic_string<T> &s) +{ + std::basic_string<T> output; + size_t i = 0; + while (i < s.length()) { + if (s[i] == '\x1b') { + ++i; + if (i == s.length()) continue; + if (s[i] == '(') { + ++i; + while (i < s.length() && s[i] != ')') { + if (s[i] == '\\') { + ++i; + } + ++i; + } + ++i; + } else { + ++i; + } + continue; + } + output += s[i]; + ++i; + } + return output; +} /** * Checks that all characters in \p to_check are a decimal digits. diff --git a/src/util/thread.h b/src/util/thread.h index b3a5e68a2..5ed63544c 100644 --- a/src/util/thread.h +++ b/src/util/thread.h @@ -21,9 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #define UTIL_THREAD_HEADER #include "../irrlichttypes.h" -#include "../jthread/jthread.h" -#include "../jthread/jmutex.h" -#include "../jthread/jmutexautolock.h" +#include "../threading/thread.h" +#include "../threading/mutex.h" +#include "../threading/mutex_auto_lock.h" #include "porting.h" #include "log.h" @@ -36,27 +36,27 @@ public: T get() { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); return m_value; } void set(T value) { - JMutexAutoLock lock(m_mutex); + MutexAutoLock lock(m_mutex); m_value = value; } // You'll want to grab this in a SharedPtr - JMutexAutoLock *getLock() + MutexAutoLock *getLock() { - return new JMutexAutoLock(m_mutex); + return new MutexAutoLock(m_mutex); } // You pretty surely want to grab the lock when accessing this T m_value; private: - JMutex m_mutex; + Mutex m_mutex; }; /* @@ -118,7 +118,7 @@ public: typename std::list<CallerInfo<Caller, CallerData, Key, T> >::iterator j; { - JMutexAutoLock lock(m_queue.getMutex()); + MutexAutoLock lock(m_queue.getMutex()); /* If the caller is already on the list, only update CallerData @@ -192,59 +192,47 @@ private: MutexedQueue<GetRequest<Key, T, Caller, CallerData> > m_queue; }; -class UpdateThread : public JThread { +class UpdateThread : public Thread +{ public: - UpdateThread() {} - virtual ~UpdateThread() {} + UpdateThread(const std::string &name) : Thread(name + "Update") {} + ~UpdateThread() {} - void deferUpdate() - { - m_update_sem.Post(); - } + void deferUpdate() { m_update_sem.post(); } - void Stop() + void stop() { - JThread::Stop(); + Thread::stop(); // give us a nudge - m_update_sem.Post(); + m_update_sem.post(); } - void *Thread() + void *run() { - ThreadStarted(); - - const char *thread_name = getName(); - log_register_thread(thread_name); - porting::setThreadName(thread_name); - - DSTACK(__FUNCTION_NAME); + DSTACK(FUNCTION_NAME); BEGIN_DEBUG_EXCEPTION_HANDLER - while (!StopRequested()) { - m_update_sem.Wait(); - - // Empty the queue, just in case doUpdate() is expensive - while (m_update_sem.GetValue()) - m_update_sem.Wait(); + while (!stopRequested()) { + m_update_sem.wait(); + // Set semaphore to 0 + while (m_update_sem.wait(0)); - if (StopRequested()) - break; + if (stopRequested()) break; doUpdate(); } - END_DEBUG_EXCEPTION_HANDLER(errorstream) + END_DEBUG_EXCEPTION_HANDLER return NULL; } protected: virtual void doUpdate() = 0; - virtual const char *getName() = 0; private: - JSemaphore m_update_sem; + Semaphore m_update_sem; }; #endif |