mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-15 10:00:28 +00:00
feat(Core/Authserver): TOTP rewrite (#5620)
This commit is contained in:
43
src/common/Encoding/Base32.cpp
Normal file
43
src/common/Encoding/Base32.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#include "Base32.h"
|
||||
#include "BaseEncoding.h"
|
||||
#include "Errors.h"
|
||||
|
||||
struct B32Impl
|
||||
{
|
||||
static constexpr std::size_t BITS_PER_CHAR = 5;
|
||||
|
||||
static constexpr char PADDING = '=';
|
||||
static constexpr char Encode(uint8 v)
|
||||
{
|
||||
ASSERT(v < 0x20);
|
||||
if (v < 26) return 'A'+v;
|
||||
else return '2' + (v-26);
|
||||
}
|
||||
|
||||
static constexpr uint8 DECODE_ERROR = 0xff;
|
||||
static constexpr uint8 Decode(uint8 v)
|
||||
{
|
||||
if (v == '0') return Decode('O');
|
||||
if (v == '1') return Decode('l');
|
||||
if (v == '8') return Decode('B');
|
||||
if (('A' <= v) && (v <= 'Z')) return (v-'A');
|
||||
if (('a' <= v) && (v <= 'z')) return (v-'a');
|
||||
if (('2' <= v) && (v <= '7')) return (v-'2')+26;
|
||||
return DECODE_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
/*static*/ std::string acore::Encoding::Base32::Encode(std::vector<uint8> const& data)
|
||||
{
|
||||
return acore::Impl::GenericBaseEncoding<B32Impl>::Encode(data);
|
||||
}
|
||||
|
||||
/*static*/ Optional<std::vector<uint8>> acore::Encoding::Base32::Decode(std::string const& data)
|
||||
{
|
||||
return acore::Impl::GenericBaseEncoding<B32Impl>::Decode(data);
|
||||
}
|
||||
23
src/common/Encoding/Base32.h
Normal file
23
src/common/Encoding/Base32.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#ifndef WARHEAD_BASE32_H
|
||||
#define WARHEAD_BASE32_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "Optional.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace acore::Encoding
|
||||
{
|
||||
struct AC_COMMON_API Base32
|
||||
{
|
||||
static std::string Encode(std::vector<uint8> const& data);
|
||||
static Optional<std::vector<uint8>> Decode(std::string const& data);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
45
src/common/Encoding/Base64.cpp
Normal file
45
src/common/Encoding/Base64.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#include "Base64.h"
|
||||
#include "BaseEncoding.h"
|
||||
#include "Errors.h"
|
||||
|
||||
struct B64Impl
|
||||
{
|
||||
static constexpr std::size_t BITS_PER_CHAR = 6;
|
||||
|
||||
static constexpr char PADDING = '=';
|
||||
static constexpr char Encode(uint8 v)
|
||||
{
|
||||
ASSERT(v < 0x40);
|
||||
if (v < 26) return 'A' + v;
|
||||
if (v < 52) return 'a' + (v - 26);
|
||||
if (v < 62) return '0' + (v - 52);
|
||||
if (v == 62) return '+';
|
||||
else return '/';
|
||||
}
|
||||
|
||||
static constexpr uint8 DECODE_ERROR = 0xff;
|
||||
static constexpr uint8 Decode(uint8 v)
|
||||
{
|
||||
if (('A' <= v) && (v <= 'Z')) return (v - 'A');
|
||||
if (('a' <= v) && (v <= 'z')) return (v - 'a') + 26;
|
||||
if (('0' <= v) && (v <= '9')) return (v - '0') + 52;
|
||||
if (v == '+') return 62;
|
||||
if (v == '/') return 63;
|
||||
return DECODE_ERROR;
|
||||
}
|
||||
};
|
||||
|
||||
/*static*/ std::string acore::Encoding::Base64::Encode(std::vector<uint8> const& data)
|
||||
{
|
||||
return acore::Impl::GenericBaseEncoding<B64Impl>::Encode(data);
|
||||
}
|
||||
|
||||
/*static*/ Optional<std::vector<uint8>> acore::Encoding::Base64::Decode(std::string const& data)
|
||||
{
|
||||
return acore::Impl::GenericBaseEncoding<B64Impl>::Decode(data);
|
||||
}
|
||||
23
src/common/Encoding/Base64.h
Normal file
23
src/common/Encoding/Base64.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#ifndef WARHEAD_BASE64_H
|
||||
#define WARHEAD_BASE64_H
|
||||
|
||||
#include "Define.h"
|
||||
#include "Optional.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace acore::Encoding
|
||||
{
|
||||
struct AC_COMMON_API Base64
|
||||
{
|
||||
static std::string Encode(std::vector<uint8> const& data);
|
||||
static Optional<std::vector<uint8>> Decode(std::string const& data);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
145
src/common/Encoding/BaseEncoding.h
Normal file
145
src/common/Encoding/BaseEncoding.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
|
||||
*/
|
||||
|
||||
#ifndef WARHEAD_BASE_ENCODING_HPP
|
||||
#define WARHEAD_BASE_ENCODING_HPP
|
||||
|
||||
#include "Define.h"
|
||||
#include "Optional.h"
|
||||
#include <numeric>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace acore::Impl
|
||||
{
|
||||
template <typename Encoding>
|
||||
struct GenericBaseEncoding
|
||||
{
|
||||
static constexpr std::size_t BITS_PER_CHAR = Encoding::BITS_PER_CHAR;
|
||||
static constexpr std::size_t PAD_TO = std::lcm(8u, BITS_PER_CHAR);
|
||||
|
||||
static_assert(BITS_PER_CHAR < 8, "Encoding parameters are invalid");
|
||||
|
||||
static constexpr uint8 DECODE_ERROR = Encoding::DECODE_ERROR;
|
||||
static constexpr char PADDING = Encoding::PADDING;
|
||||
|
||||
static constexpr std::size_t EncodedSize(std::size_t size)
|
||||
{
|
||||
size *= 8; // bits in input
|
||||
if (size % PAD_TO) // pad to boundary
|
||||
size += (PAD_TO - (size % PAD_TO));
|
||||
return (size / BITS_PER_CHAR);
|
||||
}
|
||||
|
||||
static constexpr std::size_t DecodedSize(std::size_t size)
|
||||
{
|
||||
size *= BITS_PER_CHAR; // bits in input
|
||||
if (size % PAD_TO) // pad to boundary
|
||||
size += (PAD_TO - (size % PAD_TO));
|
||||
return (size / 8);
|
||||
}
|
||||
|
||||
static std::string Encode(std::vector<uint8> const& data)
|
||||
{
|
||||
auto it = data.begin(), end = data.end();
|
||||
if (it == end)
|
||||
return "";
|
||||
|
||||
std::string s;
|
||||
s.reserve(EncodedSize(data.size()));
|
||||
|
||||
uint8 bitsLeft = 8; // in current byte
|
||||
do
|
||||
{
|
||||
uint8 thisC = 0;
|
||||
if (bitsLeft >= BITS_PER_CHAR)
|
||||
{
|
||||
bitsLeft -= BITS_PER_CHAR;
|
||||
thisC = ((*it >> bitsLeft) & ((1 << BITS_PER_CHAR)-1));
|
||||
if (!bitsLeft)
|
||||
{
|
||||
++it;
|
||||
bitsLeft = 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
thisC = (*it & ((1 << bitsLeft) - 1)) << (BITS_PER_CHAR - bitsLeft);
|
||||
bitsLeft += (8 - BITS_PER_CHAR);
|
||||
if ((++it) != end)
|
||||
thisC |= (*it >> bitsLeft);
|
||||
}
|
||||
s.append(1, Encoding::Encode(thisC));
|
||||
} while (it != end);
|
||||
|
||||
while (bitsLeft != 8)
|
||||
{
|
||||
if (bitsLeft > BITS_PER_CHAR)
|
||||
bitsLeft -= BITS_PER_CHAR;
|
||||
else
|
||||
bitsLeft += (8 - BITS_PER_CHAR);
|
||||
s.append(1, PADDING);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static Optional<std::vector<uint8>> Decode(std::string const& data)
|
||||
{
|
||||
auto it = data.begin(), end = data.end();
|
||||
if (it == end)
|
||||
return std::vector<uint8>();
|
||||
|
||||
std::vector<uint8> v;
|
||||
v.reserve(DecodedSize(data.size()));
|
||||
|
||||
uint8 currentByte = 0;
|
||||
uint8 bitsLeft = 8; // in current byte
|
||||
while ((it != end) && (*it != PADDING))
|
||||
{
|
||||
uint8 cur = Encoding::Decode(*(it++));
|
||||
if (cur == DECODE_ERROR)
|
||||
return {};
|
||||
|
||||
if (bitsLeft > BITS_PER_CHAR)
|
||||
{
|
||||
bitsLeft -= BITS_PER_CHAR;
|
||||
currentByte |= (cur << bitsLeft);
|
||||
}
|
||||
else
|
||||
{
|
||||
bitsLeft = BITS_PER_CHAR - bitsLeft; // in encoded char
|
||||
currentByte |= (cur >> bitsLeft);
|
||||
v.push_back(currentByte);
|
||||
currentByte = (cur & ((1 << bitsLeft) - 1));
|
||||
bitsLeft = 8 - bitsLeft; // in byte again
|
||||
currentByte <<= bitsLeft;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentByte)
|
||||
return {}; // decode error, trailing non-zero bits
|
||||
|
||||
// process padding
|
||||
while ((it != end) && (*it == PADDING) && (bitsLeft != 8))
|
||||
{
|
||||
if (bitsLeft > BITS_PER_CHAR)
|
||||
bitsLeft -= BITS_PER_CHAR;
|
||||
else
|
||||
bitsLeft += (8 - BITS_PER_CHAR);
|
||||
++it;
|
||||
}
|
||||
|
||||
// ok, all padding should be consumed, and we should be at end of string
|
||||
if (it == end)
|
||||
return v;
|
||||
|
||||
// anything else is an error
|
||||
return {};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user