mirror of
https://github.com/NixOS/nix.git
synced 2025-11-08 19:46:02 +01:00
Merge pull request #13685 from obsidiansystems/hash-sentinal-encapsulation
Encapsulate `invalidBase32`, avoid 0xFF magic number
This commit is contained in:
commit
0889960869
8 changed files with 101 additions and 38 deletions
|
|
@ -1,5 +1,6 @@
|
|||
#include "nix/util/references.hh"
|
||||
#include "nix/store/path.hh"
|
||||
#include "nix/util/base-nix-32.hh"
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
|
|
@ -10,9 +11,9 @@ using namespace nix;
|
|||
template<typename OIt>
|
||||
static void randomReference(std::mt19937 & urng, OIt outIter)
|
||||
{
|
||||
auto dist = std::uniform_int_distribution<std::size_t>(0, nix32Chars.size() - 1);
|
||||
auto dist = std::uniform_int_distribution<std::size_t>(0, BaseNix32::characters.size() - 1);
|
||||
dist(urng);
|
||||
std::generate_n(outIter, StorePath::HashLen, [&]() { return nix32Chars[dist(urng)]; });
|
||||
std::generate_n(outIter, StorePath::HashLen, [&]() { return BaseNix32::characters[dist(urng)]; });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
42
src/libutil/base-nix-32.cc
Normal file
42
src/libutil/base-nix-32.cc
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#include <cassert>
|
||||
|
||||
#include "nix/util/base-nix-32.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
constexpr const std::array<unsigned char, 256> BaseNix32::reverseMap = [] {
|
||||
std::array<unsigned char, 256> map{};
|
||||
|
||||
for (size_t i = 0; i < map.size(); ++i)
|
||||
map[i] = invalid; // invalid
|
||||
|
||||
for (unsigned char i = 0; i < 32; ++i)
|
||||
map[static_cast<unsigned char>(characters[i])] = i;
|
||||
|
||||
return map;
|
||||
}();
|
||||
|
||||
std::string BaseNix32::encode(std::span<const uint8_t> originalData)
|
||||
{
|
||||
if (originalData.size() == 0)
|
||||
return {};
|
||||
|
||||
size_t len = encodedLength(originalData.size());
|
||||
assert(len);
|
||||
|
||||
std::string s;
|
||||
s.reserve(len);
|
||||
|
||||
for (int n = (int) len - 1; n >= 0; n--) {
|
||||
unsigned int b = n * 5;
|
||||
unsigned int i = b / 8;
|
||||
unsigned int j = b % 8;
|
||||
unsigned char c =
|
||||
(originalData.data()[i] >> j) | (i >= originalData.size() - 1 ? 0 : originalData.data()[i + 1] << (8 - j));
|
||||
s.push_back(characters[c & 0x1f]);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
#include "nix/util/archive.hh"
|
||||
#include "nix/util/configuration.hh"
|
||||
#include "nix/util/split.hh"
|
||||
#include "nix/util/base-nix-32.hh"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
|
@ -71,39 +72,10 @@ static std::string printHash16(const Hash & hash)
|
|||
return buf;
|
||||
}
|
||||
|
||||
// omitted: E O U T
|
||||
constexpr char nix32Chars[] = "0123456789abcdfghijklmnpqrsvwxyz";
|
||||
|
||||
constexpr const std::array<unsigned char, 256> reverseNix32Map = [] {
|
||||
std::array<unsigned char, 256> map{};
|
||||
|
||||
for (size_t i = 0; i < map.size(); ++i)
|
||||
map[i] = 0xFF; // invalid
|
||||
|
||||
for (unsigned char i = 0; i < 32; ++i)
|
||||
map[static_cast<unsigned char>(nix32Chars[i])] = i;
|
||||
|
||||
return map;
|
||||
}();
|
||||
|
||||
static std::string printHash32(const Hash & hash)
|
||||
{
|
||||
assert(hash.hashSize);
|
||||
size_t len = hash.base32Len();
|
||||
assert(len);
|
||||
|
||||
std::string s;
|
||||
s.reserve(len);
|
||||
|
||||
for (int n = (int) len - 1; n >= 0; n--) {
|
||||
unsigned int b = n * 5;
|
||||
unsigned int i = b / 8;
|
||||
unsigned int j = b % 8;
|
||||
unsigned char c = (hash.hash[i] >> j) | (i >= hash.hashSize - 1 ? 0 : hash.hash[i + 1] << (8 - j));
|
||||
s.push_back(nix32Chars[c & 0x1f]);
|
||||
}
|
||||
|
||||
return s;
|
||||
return BaseNix32::encode({&hash.hash[0], hash.hashSize});
|
||||
}
|
||||
|
||||
std::string printHash16or32(const Hash & hash)
|
||||
|
|
@ -229,11 +201,13 @@ Hash::Hash(std::string_view rest, HashAlgorithm algo, bool isSRI)
|
|||
|
||||
for (unsigned int n = 0; n < rest.size(); ++n) {
|
||||
char c = rest[rest.size() - n - 1];
|
||||
unsigned char digit = reverseNix32Map[static_cast<unsigned char>(c)];
|
||||
auto digit_opt = BaseNix32::lookupReverse(c);
|
||||
|
||||
if (digit == 0xFF)
|
||||
if (!digit_opt)
|
||||
throw BadHash("invalid base-32 hash: '%s'", rest);
|
||||
|
||||
uint8_t digit = std::move(*digit_opt);
|
||||
|
||||
unsigned int b = n * 5;
|
||||
unsigned int i = b / 8;
|
||||
unsigned int j = b % 8;
|
||||
|
|
|
|||
45
src/libutil/include/nix/util/base-nix-32.hh
Normal file
45
src/libutil/include/nix/util/base-nix-32.hh
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <span>
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct BaseNix32
|
||||
{
|
||||
/// omitted: E O U T
|
||||
constexpr static std::array<char, 32> characters = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a',
|
||||
'b', 'c', 'd', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'p', 'q', 'r', 's', 'v', 'w', 'x', 'y', 'z'};
|
||||
|
||||
private:
|
||||
static const std::array<uint8_t, 256> reverseMap;
|
||||
|
||||
const static constexpr uint8_t invalid = 0xFF;
|
||||
|
||||
public:
|
||||
static inline std::optional<uint8_t> lookupReverse(char base32)
|
||||
{
|
||||
uint8_t digit = reverseMap[static_cast<unsigned char>(base32)];
|
||||
if (digit == invalid)
|
||||
return std::nullopt;
|
||||
else
|
||||
return digit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of a base-32 representation of this hash.
|
||||
*/
|
||||
static size_t encodedLength(size_t originalLength)
|
||||
{
|
||||
return (originalLength * 8 - 1) / 5 + 1;
|
||||
}
|
||||
|
||||
static std::string encode(std::span<const uint8_t> originalData);
|
||||
};
|
||||
|
||||
} // namespace nix
|
||||
|
|
@ -35,8 +35,6 @@ constexpr inline size_t regularHashSize(HashAlgorithm type)
|
|||
|
||||
extern const StringSet hashAlgorithms;
|
||||
|
||||
extern const std::array<unsigned char, 256> reverseNix32Map;
|
||||
|
||||
/**
|
||||
* @brief Enumeration representing the hash formats.
|
||||
*/
|
||||
|
|
@ -44,7 +42,7 @@ enum struct HashFormat : int {
|
|||
/// @brief Base 64 encoding.
|
||||
/// @see [IETF RFC 4648, section 4](https://datatracker.ietf.org/doc/html/rfc4648#section-4).
|
||||
Base64,
|
||||
/// @brief Nix-specific base-32 encoding. @see nix32Chars
|
||||
/// @brief Nix-specific base-32 encoding. @see BaseNix32
|
||||
Nix32,
|
||||
/// @brief Lowercase hexadecimal encoding. @see base16Chars
|
||||
Base16,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ headers = files(
|
|||
'archive.hh',
|
||||
'args.hh',
|
||||
'args/root.hh',
|
||||
'base-nix-32.hh',
|
||||
'callback.hh',
|
||||
'canon-path.hh',
|
||||
'checked-arithmetic.hh',
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ subdir('nix-meson-build-support/common')
|
|||
sources = [config_priv_h] + files(
|
||||
'archive.cc',
|
||||
'args.cc',
|
||||
'base-nix-32.cc',
|
||||
'canon-path.cc',
|
||||
'compression.cc',
|
||||
'compute-levels.cc',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "nix/util/references.hh"
|
||||
#include "nix/util/hash.hh"
|
||||
#include "nix/util/archive.hh"
|
||||
#include "nix/util/base-nix-32.hh"
|
||||
|
||||
#include <map>
|
||||
#include <cstdlib>
|
||||
|
|
@ -17,7 +18,7 @@ static void search(std::string_view s, StringSet & hashes, StringSet & seen)
|
|||
int j;
|
||||
bool match = true;
|
||||
for (j = refLength - 1; j >= 0; --j)
|
||||
if (reverseNix32Map[(unsigned char) s[i + j]] == 0xFF) {
|
||||
if (!BaseNix32::lookupReverse(s[i + j])) {
|
||||
i += j + 1;
|
||||
match = false;
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue