UUID
parent
a3f6757146
commit
1e8f431f9e
|
@ -0,0 +1,195 @@
|
|||
//
|
||||
// Created by brett on 15/08/23.
|
||||
//
|
||||
|
||||
#ifndef BLT_UUID_H
|
||||
#define BLT_UUID_H
|
||||
|
||||
#include <string>
|
||||
#include <openssl/sha.h>
|
||||
#include <random>
|
||||
#include <exception>
|
||||
#include <blt/std/string.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
namespace blt::uuid
|
||||
{
|
||||
|
||||
// from https://www.rfc-editor.org/rfc/rfc4122#section-4.3
|
||||
|
||||
union uuid_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
u_int32_t time_low;
|
||||
u_int16_t time_mid;
|
||||
u_int16_t time_hi_and_version;
|
||||
u_int8_t clock_seq_hi_and_reserved;
|
||||
u_int8_t clock_seq_low;
|
||||
u_int8_t node[6];
|
||||
} uuid;
|
||||
u_int8_t str[16];
|
||||
};
|
||||
|
||||
/* Name string is a fully-qualified domain name */
|
||||
constexpr static uuid_t NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */
|
||||
{0x6ba7b810,
|
||||
0x9dad,
|
||||
0x11d1,
|
||||
0x80, 0xb4, {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}
|
||||
};
|
||||
|
||||
/* Name string is a URL */
|
||||
constexpr static uuid_t NameSpace_URL = { /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 */
|
||||
{0x6ba7b811,
|
||||
0x9dad,
|
||||
0x11d1,
|
||||
0x80, 0xb4, {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}
|
||||
};
|
||||
|
||||
/* Name string is an ISO OID */
|
||||
constexpr static uuid_t NameSpace_OID = { /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 */
|
||||
{0x6ba7b812,
|
||||
0x9dad,
|
||||
0x11d1,
|
||||
0x80, 0xb4, {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}
|
||||
};
|
||||
|
||||
/* Name string is an X.500 DN (in DER or a text output format) */
|
||||
constexpr static uuid_t NameSpace_X500 = { /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 */
|
||||
{0x6ba7b814,
|
||||
0x9dad,
|
||||
0x11d1,
|
||||
0x80, 0xb4, {0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}
|
||||
};
|
||||
|
||||
class malformed_uuid_exception : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit malformed_uuid_exception(const std::string& error = ""): std::runtime_error(error)
|
||||
{}
|
||||
};
|
||||
|
||||
static unsigned char hex2byte(const char* hex)
|
||||
{
|
||||
unsigned short byte = 0;
|
||||
std::istringstream iss(hex);
|
||||
iss >> std::hex >> byte;
|
||||
return byte % 0x100;
|
||||
}
|
||||
|
||||
static std::string byte2hex(const uint8_t* data, int len)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::hex;
|
||||
|
||||
const char dash[] = { 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0 };
|
||||
|
||||
for (int i = 0; i < len; ++i)
|
||||
{
|
||||
if (dash[i])
|
||||
ss << std::dec << '-';
|
||||
ss << std::hex << std::setw(2) << std::setfill('0') << (int) data[i];
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
static uuid_t genV5(const std::string& objectName, uuid_t namespaceUUID = NameSpace_OID)
|
||||
{
|
||||
auto new_str = std::string(reinterpret_cast<const char*>(namespaceUUID.str)) + objectName;
|
||||
const auto* c_str = reinterpret_cast<const unsigned char*>(new_str.c_str());
|
||||
unsigned char hash[SHA_DIGEST_LENGTH];
|
||||
uuid_t result{};
|
||||
|
||||
SHA1(c_str, sizeof(c_str) - 1, hash);
|
||||
|
||||
memcpy(result.str, hash, 16);
|
||||
|
||||
//set high-nibble to 5 to indicate type 5
|
||||
result.str[6] &= 0x0F;
|
||||
result.str[6] |= 0x50;
|
||||
|
||||
//set upper two bits to "10"
|
||||
result.str[8] &= 0x3F;
|
||||
result.str[8] |= 0x80;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string toString(uuid_t uuid)
|
||||
{
|
||||
return byte2hex(uuid.str, 16);
|
||||
}
|
||||
|
||||
static uuid_t toUUID(const std::string& str)
|
||||
{
|
||||
if (str.empty())
|
||||
throw malformed_uuid_exception("expected at least 32 characters!");
|
||||
if (str.size() > 36)
|
||||
throw malformed_uuid_exception("UUID cannot contain more then 128 bits of information!");
|
||||
|
||||
uuid_t uuid{};
|
||||
|
||||
std::string data = str;
|
||||
|
||||
if (data.size() == 36)
|
||||
blt::string::replaceAll(data, "-", "");
|
||||
|
||||
if (data.size() == 32)
|
||||
{
|
||||
char cpy[2];
|
||||
for (size_t i = 0; i < data.size(); i += 2)
|
||||
{
|
||||
cpy[0] = data[i];
|
||||
cpy[1] = data[i + 1];
|
||||
uuid.str[i / 2] = hex2byte(cpy);
|
||||
BLT_INFO("i: %d, %d %d, %d, %d", i/2, cpy[0], cpy[1], uuid.str[i/2], hex2byte(cpy));
|
||||
}
|
||||
} else
|
||||
throw malformed_uuid_exception("UUID is expected as a string of bytes xxxxxxxx or in uuid format 8-4-4-4-12");
|
||||
|
||||
return uuid;
|
||||
}
|
||||
|
||||
static uuid_t genV4()
|
||||
{
|
||||
static std::random_device rd;
|
||||
std::seed_seq seed{ rd(), rd(), rd(), rd() };
|
||||
static std::mt19937_64 gen(seed);
|
||||
static std::uniform_int_distribution<int> dis(0, 15);
|
||||
static std::uniform_int_distribution<> dis2(8, 11);
|
||||
|
||||
std::stringstream ss;
|
||||
int i;
|
||||
ss << std::hex;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (i = 0; i < 4; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-4";
|
||||
for (i = 0; i < 3; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
ss << dis2(gen);
|
||||
for (i = 0; i < 3; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (i = 0; i < 12; i++) {
|
||||
ss << dis(gen);
|
||||
};
|
||||
|
||||
return toUUID(ss.str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif //BLT_UUID_H
|
Loading…
Reference in New Issue