Skip to content

Instantly share code, notes, and snippets.

@madmongo1
Created April 20, 2020 12:44
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save madmongo1/53c303c6fe8de64f93adc014c7671d51 to your computer and use it in GitHub Desktop.
Save madmongo1/53c303c6fe8de64f93adc014c7671d51 to your computer and use it in GitHub Desktop.
Minecraft hash
/*
* HEADER FILE
*/
//
// Copyright (c) 2020 Richard Hodges (hodges.r@gmail.com)
//
// Official repository: https://github.com/AlexAndDad/gateway
//
#pragma once
#include "minecraft/net.hpp"
#include <openssl/sha.h>
#include <string>
namespace minecraft::protocol
{
struct daft_hash_impl
{
daft_hash_impl()
: ctx_ {}
{
SHA1_Init(&ctx_);
}
daft_hash_impl(daft_hash_impl const &) = delete;
daft_hash_impl(daft_hash_impl &&) = delete;
daft_hash_impl &operator=(daft_hash_impl const &) = delete;
daft_hash_impl &operator=(daft_hash_impl &&) = delete;
~daft_hash_impl() {}
void update(net::const_buffer in) { SHA1_Update(&ctx_, in.data(), in.size()); }
std::string finalise();
private:
SHA_CTX ctx_;
};
} // namespace minecraft::protocol
/*
* CPP FILE
*/
//
// Copyright (c) 2020 Richard Hodges (hodges.r@gmail.com)
//
// Official repository: https://github.com/AlexAndDad/gateway
//
#include "minecraft/protocol/daft_hash.hpp"
#include <algorithm>
#include <array>
#include <string_view>
#include <boost/algorithm/string/case_conv.hpp>
#include <openssl/bn.h>
namespace minecraft::protocol
{
std::string daft_hash_impl::finalise()
{
auto result = std::string();
auto buf = std::array< std::uint8_t, 20 >();
SHA1_Final(buf.data(), &ctx_);
// convert has to bignum
BIGNUM *bn = BN_bin2bn(buf.data(), buf.size(), nullptr);
// reset the hasher for next use
SHA1_Init(&ctx_);
// check for "negative" value
if (BN_is_bit_set(bn, 159))
{
result += '-';
// perform 1's compliment on the bignum's bits
auto tmp = std::vector< unsigned char >(BN_num_bytes(bn));
BN_bn2bin(bn, tmp.data());
std::transform(tmp.begin(), tmp.end(), tmp.begin(), [](unsigned char b) { return ~b; });
BN_bin2bn(tmp.data(), tmp.size(), bn);
// add 1 "as-if" 2's compliment
BN_add_word(bn, 1);
}
// convert to hex
auto hex = BN_bn2hex(bn);
// remove any leading zeroes except the last
auto view = std::string_view(hex);
while (view.size() && view[0] == '0')
view = view.substr(1);
// append the hex to the result
result.append(view.begin(), view.end());
OPENSSL_free(hex);
BN_free(bn);
// convert the hex to lower case
boost::to_lower(result);
return result;
}
} // namespace minecraft::protocol
/*
* TEST FILE
*/
//
// Copyright (c) 2020 Richard Hodges (hodges.r@gmail.com)
//
// Official repository: https://github.com/AlexAndDad/gateway
//
#include <catch2/catch.hpp>
#include "minecraft/protocol/daft_hash.hpp"
using namespace minecraft;
TEST_CASE("minecraft::protocol::daft_hash")
{
protocol::daft_hash_impl hasher;
//
// Check class Notch
//
hasher.update(net::buffer(std::string("Notch")));
auto result = hasher.finalise();
CHECK(result == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
//
// Check repeatable
//
hasher.update(net::buffer(std::string("Notch")));
result = hasher.finalise();
CHECK(result == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
//
// Negative hash
//
hasher.update(net::buffer(std::string("jeb_")));
result = hasher.finalise();
CHECK(result == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
hasher.update(net::buffer(std::string("j")));
hasher.update(net::buffer(std::string("e")));
hasher.update(net::buffer(std::string("b")));
hasher.update(net::buffer(std::string("_")));
result = hasher.finalise();
CHECK(result == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
//
// simon
//
hasher.update(net::buffer(std::string("simon")));
result = hasher.finalise();
CHECK(result == "88e16a1019277b15d58faf0541e11910eb756f6");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment