2003-06-16 18:59:23 +03:00
|
|
|
#include <iostream>
|
2008-05-21 14:17:31 +03:00
|
|
|
#include <cstring>
|
2003-06-16 18:59:23 +03:00
|
|
|
|
2023-02-01 14:34:32 +02:00
|
|
|
#include <openssl/crypto.h>
|
2006-02-13 21:52:43 +02:00
|
|
|
#include <openssl/md5.h>
|
|
|
|
#include <openssl/sha.h>
|
2003-06-15 16:41:32 +03:00
|
|
|
|
2020-06-02 18:52:13 +03:00
|
|
|
#include "args.hh"
|
2003-06-15 16:41:32 +03:00
|
|
|
#include "hash.hh"
|
2003-06-20 13:40:25 +03:00
|
|
|
#include "archive.hh"
|
2020-07-20 20:42:34 +03:00
|
|
|
#include "split.hh"
|
2003-06-15 16:41:32 +03:00
|
|
|
|
2005-01-13 19:39:26 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
2006-09-05 00:06:23 +03:00
|
|
|
namespace nix {
|
|
|
|
|
2020-06-19 21:41:33 +03:00
|
|
|
static size_t regularHashSize(HashType type) {
|
|
|
|
switch (type) {
|
|
|
|
case htMD5: return md5HashSize;
|
|
|
|
case htSHA1: return sha1HashSize;
|
|
|
|
case htSHA256: return sha256HashSize;
|
|
|
|
case htSHA512: return sha512HashSize;
|
|
|
|
}
|
|
|
|
abort();
|
|
|
|
}
|
2006-09-05 00:06:23 +03:00
|
|
|
|
2020-07-16 20:28:52 +03:00
|
|
|
|
2020-05-10 21:32:21 +03:00
|
|
|
std::set<std::string> hashTypes = { "md5", "sha1", "sha256", "sha512" };
|
|
|
|
|
|
|
|
|
2020-07-02 01:03:22 +03:00
|
|
|
Hash::Hash(HashType type) : type(type)
|
2005-01-14 18:04:03 +02:00
|
|
|
{
|
2020-06-19 21:41:33 +03:00
|
|
|
hashSize = regularHashSize(type);
|
2005-01-14 15:51:38 +02:00
|
|
|
assert(hashSize <= maxHashSize);
|
2005-01-14 18:04:03 +02:00
|
|
|
memset(hash, 0, maxHashSize);
|
2003-06-15 16:41:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-16 01:28:27 +03:00
|
|
|
bool Hash::operator == (const Hash & h2) const
|
2003-06-15 16:41:32 +03:00
|
|
|
{
|
2005-01-13 17:44:44 +02:00
|
|
|
if (hashSize != h2.hashSize) return false;
|
2003-06-15 16:41:32 +03:00
|
|
|
for (unsigned int i = 0; i < hashSize; i++)
|
|
|
|
if (hash[i] != h2.hash[i]) return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-16 01:28:27 +03:00
|
|
|
bool Hash::operator != (const Hash & h2) const
|
2003-06-15 16:41:32 +03:00
|
|
|
{
|
|
|
|
return !(*this == h2);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-16 00:24:05 +03:00
|
|
|
bool Hash::operator < (const Hash & h) const
|
|
|
|
{
|
2017-06-24 03:17:45 +03:00
|
|
|
if (hashSize < h.hashSize) return true;
|
|
|
|
if (hashSize > h.hashSize) return false;
|
2003-07-16 00:24:05 +03:00
|
|
|
for (unsigned int i = 0; i < hashSize; i++) {
|
|
|
|
if (hash[i] < h.hash[i]) return true;
|
|
|
|
if (hash[i] > h.hash[i]) return false;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
const std::string base16Chars = "0123456789abcdef";
|
2006-03-09 19:07:25 +02:00
|
|
|
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
static std::string printHash16(const Hash & hash)
|
2003-06-15 16:41:32 +03:00
|
|
|
{
|
2023-03-29 12:54:27 +03:00
|
|
|
std::string buf;
|
|
|
|
buf.reserve(hash.hashSize * 2);
|
2005-01-14 18:04:03 +02:00
|
|
|
for (unsigned int i = 0; i < hash.hashSize; i++) {
|
2023-03-29 12:54:27 +03:00
|
|
|
buf.push_back(base16Chars[hash.hash[i] >> 4]);
|
|
|
|
buf.push_back(base16Chars[hash.hash[i] & 0x0f]);
|
2003-06-15 16:41:32 +03:00
|
|
|
}
|
2023-03-29 12:54:27 +03:00
|
|
|
return buf;
|
2003-06-15 16:41:32 +03:00
|
|
|
}
|
|
|
|
|
2015-02-03 19:35:11 +02:00
|
|
|
|
2005-01-14 18:04:03 +02:00
|
|
|
// omitted: E O U T
|
2022-02-25 17:00:00 +02:00
|
|
|
const std::string base32Chars = "0123456789abcdfghijklmnpqrsvwxyz";
|
2005-01-14 18:04:03 +02:00
|
|
|
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
static std::string printHash32(const Hash & hash)
|
2005-01-14 18:04:03 +02:00
|
|
|
{
|
2016-07-21 19:39:32 +03:00
|
|
|
assert(hash.hashSize);
|
2016-01-27 18:18:20 +02:00
|
|
|
size_t len = hash.base32Len();
|
2016-04-20 15:12:38 +03:00
|
|
|
assert(len);
|
2005-11-16 10:27:06 +02:00
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
std::string s;
|
2015-02-03 19:35:11 +02:00
|
|
|
s.reserve(len);
|
|
|
|
|
2018-05-02 14:56:34 +03:00
|
|
|
for (int n = (int) len - 1; n >= 0; n--) {
|
2015-02-03 19:35:11 +02:00
|
|
|
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(base32Chars[c & 0x1f]);
|
2005-01-14 18:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
std::string printHash16or32(const Hash & hash)
|
2012-10-23 19:05:50 +03:00
|
|
|
{
|
2020-06-25 16:50:30 +03:00
|
|
|
assert(hash.type);
|
2023-10-13 04:48:15 +03:00
|
|
|
return hash.to_string(hash.type == htMD5 ? HashFormat::Base16 : HashFormat::Base32, false);
|
2012-10-23 19:05:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-10-10 13:53:01 +03:00
|
|
|
std::string Hash::to_string(HashFormat hashFormat, bool includeType) const
|
* Removed the `id' attribute hack.
* Formalise the notion of fixed-output derivations, i.e., derivations
for which a cryptographic hash of the output is known in advance.
Changes to such derivations should not propagate upwards through the
dependency graph. Previously this was done by specifying the hash
component of the output path through the `id' attribute, but this is
insecure since you can lie about it (i.e., you can specify any hash
and then produce a completely different output). Now the
responsibility for checking the output is moved from the builder to
Nix itself.
A fixed-output derivation can be created by specifying the
`outputHash' and `outputHashAlgo' attributes, the latter taking
values `md5', `sha1', and `sha256', and the former specifying the
actual hash in hexadecimal or in base-32 (auto-detected by looking
at the length of the attribute value). MD5 is included for
compatibility but should be considered deprecated.
* Removed the `drvPath' pseudo-attribute in derivation results. It's
no longer necessary.
* Cleaned up the support for multiple output paths in derivation store
expressions. Each output now has a unique identifier (e.g., `out',
`devel', `docs'). Previously there was no way to tell output paths
apart at the store expression level.
* `nix-hash' now has a flag `--base32' to specify that the hash should
be printed in base-32 notation.
* `fetchurl' accepts parameters `sha256' and `sha1' in addition to
`md5'.
* `nix-prefetch-url' now prints out a SHA-1 hash in base-32. (TODO: a
flag to specify the hash.)
2005-01-17 18:55:19 +02:00
|
|
|
{
|
2017-07-04 15:47:59 +03:00
|
|
|
std::string s;
|
2023-10-13 04:48:15 +03:00
|
|
|
if (hashFormat == HashFormat::SRI || includeType) {
|
2020-06-19 21:41:33 +03:00
|
|
|
s += printHashType(type);
|
2023-10-13 04:48:15 +03:00
|
|
|
s += hashFormat == HashFormat::SRI ? '-' : ':';
|
* Removed the `id' attribute hack.
* Formalise the notion of fixed-output derivations, i.e., derivations
for which a cryptographic hash of the output is known in advance.
Changes to such derivations should not propagate upwards through the
dependency graph. Previously this was done by specifying the hash
component of the output path through the `id' attribute, but this is
insecure since you can lie about it (i.e., you can specify any hash
and then produce a completely different output). Now the
responsibility for checking the output is moved from the builder to
Nix itself.
A fixed-output derivation can be created by specifying the
`outputHash' and `outputHashAlgo' attributes, the latter taking
values `md5', `sha1', and `sha256', and the former specifying the
actual hash in hexadecimal or in base-32 (auto-detected by looking
at the length of the attribute value). MD5 is included for
compatibility but should be considered deprecated.
* Removed the `drvPath' pseudo-attribute in derivation results. It's
no longer necessary.
* Cleaned up the support for multiple output paths in derivation store
expressions. Each output now has a unique identifier (e.g., `out',
`devel', `docs'). Previously there was no way to tell output paths
apart at the store expression level.
* `nix-hash' now has a flag `--base32' to specify that the hash should
be printed in base-32 notation.
* `fetchurl' accepts parameters `sha256' and `sha1' in addition to
`md5'.
* `nix-prefetch-url' now prints out a SHA-1 hash in base-32. (TODO: a
flag to specify the hash.)
2005-01-17 18:55:19 +02:00
|
|
|
}
|
2023-10-10 13:53:01 +03:00
|
|
|
switch (hashFormat) {
|
2023-10-13 04:48:15 +03:00
|
|
|
case HashFormat::Base16:
|
2017-07-04 15:47:59 +03:00
|
|
|
s += printHash16(*this);
|
|
|
|
break;
|
2023-10-13 04:48:15 +03:00
|
|
|
case HashFormat::Base32:
|
2017-07-04 15:47:59 +03:00
|
|
|
s += printHash32(*this);
|
|
|
|
break;
|
2023-10-13 04:48:15 +03:00
|
|
|
case HashFormat::Base64:
|
|
|
|
case HashFormat::SRI:
|
2023-03-28 19:20:33 +03:00
|
|
|
s += base64Encode(std::string_view((const char *) hash, hashSize));
|
2017-07-04 15:47:59 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
return s;
|
* Removed the `id' attribute hack.
* Formalise the notion of fixed-output derivations, i.e., derivations
for which a cryptographic hash of the output is known in advance.
Changes to such derivations should not propagate upwards through the
dependency graph. Previously this was done by specifying the hash
component of the output path through the `id' attribute, but this is
insecure since you can lie about it (i.e., you can specify any hash
and then produce a completely different output). Now the
responsibility for checking the output is moved from the builder to
Nix itself.
A fixed-output derivation can be created by specifying the
`outputHash' and `outputHashAlgo' attributes, the latter taking
values `md5', `sha1', and `sha256', and the former specifying the
actual hash in hexadecimal or in base-32 (auto-detected by looking
at the length of the attribute value). MD5 is included for
compatibility but should be considered deprecated.
* Removed the `drvPath' pseudo-attribute in derivation results. It's
no longer necessary.
* Cleaned up the support for multiple output paths in derivation store
expressions. Each output now has a unique identifier (e.g., `out',
`devel', `docs'). Previously there was no way to tell output paths
apart at the store expression level.
* `nix-hash' now has a flag `--base32' to specify that the hash should
be printed in base-32 notation.
* `fetchurl' accepts parameters `sha256' and `sha1' in addition to
`md5'.
* `nix-prefetch-url' now prints out a SHA-1 hash in base-32. (TODO: a
flag to specify the hash.)
2005-01-17 18:55:19 +02:00
|
|
|
}
|
|
|
|
|
2020-08-05 22:11:49 +03:00
|
|
|
Hash Hash::dummy(htSHA256);
|
|
|
|
|
2020-07-02 18:11:18 +03:00
|
|
|
Hash Hash::parseSRI(std::string_view original) {
|
2020-07-02 00:32:06 +03:00
|
|
|
auto rest = original;
|
|
|
|
|
|
|
|
// Parse the has type before the separater, if there was one.
|
2020-07-03 02:16:57 +03:00
|
|
|
auto hashRaw = splitPrefixTo(rest, '-');
|
2020-07-02 00:32:06 +03:00
|
|
|
if (!hashRaw)
|
|
|
|
throw BadHash("hash '%s' is not SRI", original);
|
|
|
|
HashType parsedType = parseHashType(*hashRaw);
|
* Removed the `id' attribute hack.
* Formalise the notion of fixed-output derivations, i.e., derivations
for which a cryptographic hash of the output is known in advance.
Changes to such derivations should not propagate upwards through the
dependency graph. Previously this was done by specifying the hash
component of the output path through the `id' attribute, but this is
insecure since you can lie about it (i.e., you can specify any hash
and then produce a completely different output). Now the
responsibility for checking the output is moved from the builder to
Nix itself.
A fixed-output derivation can be created by specifying the
`outputHash' and `outputHashAlgo' attributes, the latter taking
values `md5', `sha1', and `sha256', and the former specifying the
actual hash in hexadecimal or in base-32 (auto-detected by looking
at the length of the attribute value). MD5 is included for
compatibility but should be considered deprecated.
* Removed the `drvPath' pseudo-attribute in derivation results. It's
no longer necessary.
* Cleaned up the support for multiple output paths in derivation store
expressions. Each output now has a unique identifier (e.g., `out',
`devel', `docs'). Previously there was no way to tell output paths
apart at the store expression level.
* `nix-hash' now has a flag `--base32' to specify that the hash should
be printed in base-32 notation.
* `fetchurl' accepts parameters `sha256' and `sha1' in addition to
`md5'.
* `nix-prefetch-url' now prints out a SHA-1 hash in base-32. (TODO: a
flag to specify the hash.)
2005-01-17 18:55:19 +02:00
|
|
|
|
2020-07-02 18:09:04 +03:00
|
|
|
return Hash(rest, parsedType, true);
|
2020-06-30 21:10:30 +03:00
|
|
|
}
|
|
|
|
|
2020-07-03 02:10:11 +03:00
|
|
|
// Mutates the string to eliminate the prefixes when found
|
2022-02-25 17:00:00 +02:00
|
|
|
static std::pair<std::optional<HashType>, bool> getParsedTypeAndSRI(std::string_view & rest)
|
|
|
|
{
|
2020-07-03 02:10:11 +03:00
|
|
|
bool isSRI = false;
|
|
|
|
|
2022-04-06 20:28:12 +03:00
|
|
|
// Parse the hash type before the separator, if there was one.
|
2020-07-03 02:10:11 +03:00
|
|
|
std::optional<HashType> optParsedType;
|
|
|
|
{
|
2020-07-03 02:16:57 +03:00
|
|
|
auto hashRaw = splitPrefixTo(rest, ':');
|
2020-07-03 02:10:11 +03:00
|
|
|
|
|
|
|
if (!hashRaw) {
|
2020-07-03 02:16:57 +03:00
|
|
|
hashRaw = splitPrefixTo(rest, '-');
|
2020-07-03 02:10:11 +03:00
|
|
|
if (hashRaw)
|
|
|
|
isSRI = true;
|
|
|
|
}
|
|
|
|
if (hashRaw)
|
|
|
|
optParsedType = parseHashType(*hashRaw);
|
|
|
|
}
|
|
|
|
|
|
|
|
return {optParsedType, isSRI};
|
|
|
|
}
|
|
|
|
|
2020-07-02 18:21:00 +03:00
|
|
|
Hash Hash::parseAnyPrefixed(std::string_view original)
|
2020-07-02 01:34:18 +03:00
|
|
|
{
|
2020-07-02 18:21:00 +03:00
|
|
|
auto rest = original;
|
2020-07-02 18:29:33 +03:00
|
|
|
auto [optParsedType, isSRI] = getParsedTypeAndSRI(rest);
|
2020-07-02 18:21:00 +03:00
|
|
|
|
|
|
|
// Either the string or user must provide the type, if they both do they
|
|
|
|
// must agree.
|
|
|
|
if (!optParsedType)
|
2020-07-20 20:43:19 +03:00
|
|
|
throw BadHash("hash '%s' does not include a type", rest);
|
2020-07-02 18:21:00 +03:00
|
|
|
|
|
|
|
return Hash(rest, *optParsedType, isSRI);
|
2020-07-02 01:34:18 +03:00
|
|
|
}
|
2020-06-30 21:10:30 +03:00
|
|
|
|
2020-07-02 17:58:29 +03:00
|
|
|
Hash Hash::parseAny(std::string_view original, std::optional<HashType> optType)
|
2011-12-02 13:47:06 +02:00
|
|
|
{
|
2020-07-02 17:58:29 +03:00
|
|
|
auto rest = original;
|
2020-07-02 18:29:33 +03:00
|
|
|
auto [optParsedType, isSRI] = getParsedTypeAndSRI(rest);
|
2011-12-02 13:47:06 +02:00
|
|
|
|
2020-06-19 21:41:33 +03:00
|
|
|
// Either the string or user must provide the type, if they both do they
|
|
|
|
// must agree.
|
2020-07-02 17:58:29 +03:00
|
|
|
if (!optParsedType && !optType)
|
2020-10-28 21:45:57 +02:00
|
|
|
throw BadHash("hash '%s' does not include a type, nor is the type otherwise known from context", rest);
|
2020-07-02 17:58:29 +03:00
|
|
|
else if (optParsedType && optType && *optParsedType != *optType)
|
|
|
|
throw BadHash("hash '%s' should have type '%s'", original, printHashType(*optType));
|
2020-06-19 21:41:33 +03:00
|
|
|
|
2020-07-02 18:29:33 +03:00
|
|
|
HashType hashType = optParsedType ? *optParsedType : *optType;
|
2020-07-02 18:09:04 +03:00
|
|
|
return Hash(rest, hashType, isSRI);
|
2020-07-02 01:34:18 +03:00
|
|
|
}
|
2020-07-02 00:32:06 +03:00
|
|
|
|
2020-07-02 18:34:40 +03:00
|
|
|
Hash Hash::parseNonSRIUnprefixed(std::string_view s, HashType type)
|
|
|
|
{
|
|
|
|
return Hash(s, type, false);
|
|
|
|
}
|
|
|
|
|
2020-07-02 18:09:04 +03:00
|
|
|
Hash::Hash(std::string_view rest, HashType type, bool isSRI)
|
|
|
|
: Hash(type)
|
2020-07-02 00:32:06 +03:00
|
|
|
{
|
2020-07-02 00:50:34 +03:00
|
|
|
if (!isSRI && rest.size() == base16Len()) {
|
2017-07-04 15:47:59 +03:00
|
|
|
|
|
|
|
auto parseHexDigit = [&](char c) {
|
|
|
|
if (c >= '0' && c <= '9') return c - '0';
|
|
|
|
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
|
|
|
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
2020-07-02 00:50:34 +03:00
|
|
|
throw BadHash("invalid base-16 hash '%s'", rest);
|
2017-07-04 15:47:59 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < hashSize; i++) {
|
|
|
|
hash[i] =
|
2020-07-02 00:50:34 +03:00
|
|
|
parseHexDigit(rest[i * 2]) << 4
|
|
|
|
| parseHexDigit(rest[i * 2 + 1]);
|
2017-07-04 15:47:59 +03:00
|
|
|
}
|
2003-06-15 16:41:32 +03:00
|
|
|
}
|
2017-07-04 15:47:59 +03:00
|
|
|
|
2020-07-02 00:50:34 +03:00
|
|
|
else if (!isSRI && rest.size() == base32Len()) {
|
2017-07-04 15:47:59 +03:00
|
|
|
|
2020-07-02 00:50:34 +03:00
|
|
|
for (unsigned int n = 0; n < rest.size(); ++n) {
|
|
|
|
char c = rest[rest.size() - n - 1];
|
2017-07-04 15:47:59 +03:00
|
|
|
unsigned char digit;
|
|
|
|
for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
|
|
|
|
if (base32Chars[digit] == c) break;
|
|
|
|
if (digit >= 32)
|
2020-07-02 00:50:34 +03:00
|
|
|
throw BadHash("invalid base-32 hash '%s'", rest);
|
2017-07-04 15:47:59 +03:00
|
|
|
unsigned int b = n * 5;
|
|
|
|
unsigned int i = b / 8;
|
|
|
|
unsigned int j = b % 8;
|
|
|
|
hash[i] |= digit << j;
|
|
|
|
|
|
|
|
if (i < hashSize - 1) {
|
|
|
|
hash[i + 1] |= digit >> (8 - j);
|
|
|
|
} else {
|
|
|
|
if (digit >> (8 - j))
|
2020-07-02 00:50:34 +03:00
|
|
|
throw BadHash("invalid base-32 hash '%s'", rest);
|
2017-07-04 15:47:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-02 00:50:34 +03:00
|
|
|
else if (isSRI || rest.size() == base64Len()) {
|
|
|
|
auto d = base64Decode(rest);
|
2018-02-19 18:44:30 +02:00
|
|
|
if (d.size() != hashSize)
|
2020-07-02 00:50:34 +03:00
|
|
|
throw BadHash("invalid %s hash '%s'", isSRI ? "SRI" : "base-64", rest);
|
2018-03-15 05:53:43 +02:00
|
|
|
assert(hashSize);
|
2017-07-04 15:47:59 +03:00
|
|
|
memcpy(hash, d.data(), hashSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
2020-07-02 00:50:34 +03:00
|
|
|
throw BadHash("hash '%s' has wrong length for hash type '%s'", rest, printHashType(this->type));
|
2003-06-15 16:41:32 +03:00
|
|
|
}
|
|
|
|
|
2022-01-21 15:44:00 +02:00
|
|
|
Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht)
|
2020-06-12 18:09:42 +03:00
|
|
|
{
|
2020-06-12 20:00:48 +03:00
|
|
|
if (hashStr.empty()) {
|
2020-06-19 00:58:27 +03:00
|
|
|
if (!ht)
|
|
|
|
throw BadHash("empty hash requires explicit hash type");
|
|
|
|
Hash h(*ht);
|
2023-10-13 04:48:15 +03:00
|
|
|
warn("found empty hash, assuming '%s'", h.to_string(HashFormat::SRI, true));
|
2020-06-12 20:00:48 +03:00
|
|
|
return h;
|
2020-06-12 18:09:42 +03:00
|
|
|
} else
|
2020-07-02 01:34:18 +03:00
|
|
|
return Hash::parseAny(hashStr, ht);
|
2020-06-12 18:09:42 +03:00
|
|
|
}
|
|
|
|
|
2003-06-15 16:41:32 +03:00
|
|
|
|
2006-02-13 20:00:08 +02:00
|
|
|
union Ctx
|
2003-06-16 16:33:38 +03:00
|
|
|
{
|
2006-02-13 21:52:43 +02:00
|
|
|
MD5_CTX md5;
|
|
|
|
SHA_CTX sha1;
|
2005-01-14 14:03:04 +02:00
|
|
|
SHA256_CTX sha256;
|
2015-11-04 17:31:06 +02:00
|
|
|
SHA512_CTX sha512;
|
2005-01-13 19:39:26 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void start(HashType ht, Ctx & ctx)
|
|
|
|
{
|
2020-06-19 01:09:22 +03:00
|
|
|
if (ht == htMD5) MD5_Init(&ctx.md5);
|
|
|
|
else if (ht == htSHA1) SHA1_Init(&ctx.sha1);
|
|
|
|
else if (ht == htSHA256) SHA256_Init(&ctx.sha256);
|
|
|
|
else if (ht == htSHA512) SHA512_Init(&ctx.sha512);
|
2005-01-13 19:39:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void update(HashType ht, Ctx & ctx,
|
2020-12-02 15:00:43 +02:00
|
|
|
std::string_view data)
|
2005-01-13 19:39:26 +02:00
|
|
|
{
|
2020-12-02 15:00:43 +02:00
|
|
|
if (ht == htMD5) MD5_Update(&ctx.md5, data.data(), data.size());
|
|
|
|
else if (ht == htSHA1) SHA1_Update(&ctx.sha1, data.data(), data.size());
|
|
|
|
else if (ht == htSHA256) SHA256_Update(&ctx.sha256, data.data(), data.size());
|
|
|
|
else if (ht == htSHA512) SHA512_Update(&ctx.sha512, data.data(), data.size());
|
2005-01-13 19:39:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void finish(HashType ht, Ctx & ctx, unsigned char * hash)
|
|
|
|
{
|
2020-06-19 01:09:22 +03:00
|
|
|
if (ht == htMD5) MD5_Final(hash, &ctx.md5);
|
|
|
|
else if (ht == htSHA1) SHA1_Final(hash, &ctx.sha1);
|
|
|
|
else if (ht == htSHA256) SHA256_Final(hash, &ctx.sha256);
|
|
|
|
else if (ht == htSHA512) SHA512_Final(hash, &ctx.sha512);
|
2005-01-13 19:39:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-19 21:41:33 +03:00
|
|
|
Hash hashString(HashType ht, std::string_view s)
|
2005-01-13 19:39:26 +02:00
|
|
|
{
|
|
|
|
Ctx ctx;
|
|
|
|
Hash hash(ht);
|
|
|
|
start(ht, ctx);
|
2020-12-02 15:00:43 +02:00
|
|
|
update(ht, ctx, s);
|
2005-01-13 19:39:26 +02:00
|
|
|
finish(ht, ctx, hash.hash);
|
2003-06-16 16:33:38 +03:00
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
* Removed the `id' attribute hack.
* Formalise the notion of fixed-output derivations, i.e., derivations
for which a cryptographic hash of the output is known in advance.
Changes to such derivations should not propagate upwards through the
dependency graph. Previously this was done by specifying the hash
component of the output path through the `id' attribute, but this is
insecure since you can lie about it (i.e., you can specify any hash
and then produce a completely different output). Now the
responsibility for checking the output is moved from the builder to
Nix itself.
A fixed-output derivation can be created by specifying the
`outputHash' and `outputHashAlgo' attributes, the latter taking
values `md5', `sha1', and `sha256', and the former specifying the
actual hash in hexadecimal or in base-32 (auto-detected by looking
at the length of the attribute value). MD5 is included for
compatibility but should be considered deprecated.
* Removed the `drvPath' pseudo-attribute in derivation results. It's
no longer necessary.
* Cleaned up the support for multiple output paths in derivation store
expressions. Each output now has a unique identifier (e.g., `out',
`devel', `docs'). Previously there was no way to tell output paths
apart at the store expression level.
* `nix-hash' now has a flag `--base32' to specify that the hash should
be printed in base-32 notation.
* `fetchurl' accepts parameters `sha256' and `sha1' in addition to
`md5'.
* `nix-prefetch-url' now prints out a SHA-1 hash in base-32. (TODO: a
flag to specify the hash.)
2005-01-17 18:55:19 +02:00
|
|
|
Hash hashFile(HashType ht, const Path & path)
|
2003-06-15 16:41:32 +03:00
|
|
|
{
|
2018-03-30 01:56:13 +03:00
|
|
|
HashSink sink(ht);
|
|
|
|
readFile(path, sink);
|
|
|
|
return sink.finish().first;
|
2003-06-15 16:41:32 +03:00
|
|
|
}
|
2003-06-16 18:59:23 +03:00
|
|
|
|
|
|
|
|
2007-02-21 16:31:42 +02:00
|
|
|
HashSink::HashSink(HashType ht) : ht(ht)
|
2003-06-16 18:59:23 +03:00
|
|
|
{
|
2007-02-21 16:31:42 +02:00
|
|
|
ctx = new Ctx;
|
2010-11-16 19:11:46 +02:00
|
|
|
bytes = 0;
|
2007-02-21 16:31:42 +02:00
|
|
|
start(ht, *ctx);
|
|
|
|
}
|
2015-02-03 19:35:11 +02:00
|
|
|
|
2007-02-21 16:31:42 +02:00
|
|
|
HashSink::~HashSink()
|
|
|
|
{
|
2011-12-15 18:19:53 +02:00
|
|
|
bufPos = 0;
|
2007-02-21 16:31:42 +02:00
|
|
|
delete ctx;
|
|
|
|
}
|
2003-06-16 18:59:23 +03:00
|
|
|
|
2023-04-07 10:16:40 +03:00
|
|
|
void HashSink::writeUnbuffered(std::string_view data)
|
2007-02-21 16:31:42 +02:00
|
|
|
{
|
2020-12-02 15:00:43 +02:00
|
|
|
bytes += data.size();
|
|
|
|
update(ht, *ctx, data);
|
2007-02-21 16:31:42 +02:00
|
|
|
}
|
2003-06-16 18:59:23 +03:00
|
|
|
|
2010-11-16 19:11:46 +02:00
|
|
|
HashResult HashSink::finish()
|
2003-06-16 18:59:23 +03:00
|
|
|
{
|
2011-12-15 18:19:53 +02:00
|
|
|
flush();
|
2005-01-13 19:39:26 +02:00
|
|
|
Hash hash(ht);
|
2007-02-21 16:31:42 +02:00
|
|
|
nix::finish(ht, *ctx, hash.hash);
|
2010-11-16 19:11:46 +02:00
|
|
|
return HashResult(hash, bytes);
|
2003-06-16 18:59:23 +03:00
|
|
|
}
|
2005-01-14 18:04:03 +02:00
|
|
|
|
2011-12-15 18:19:53 +02:00
|
|
|
HashResult HashSink::currentHash()
|
|
|
|
{
|
|
|
|
flush();
|
|
|
|
Ctx ctx2 = *ctx;
|
|
|
|
Hash hash(ht);
|
|
|
|
nix::finish(ht, ctx2, hash.hash);
|
|
|
|
return HashResult(hash, bytes);
|
|
|
|
}
|
|
|
|
|
2005-01-14 18:04:03 +02:00
|
|
|
|
2010-11-16 19:11:46 +02:00
|
|
|
HashResult hashPath(
|
|
|
|
HashType ht, const Path & path, PathFilter & filter)
|
2007-02-21 16:31:42 +02:00
|
|
|
{
|
|
|
|
HashSink sink(ht);
|
|
|
|
dumpPath(path, sink, filter);
|
|
|
|
return sink.finish();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-01-14 18:04:03 +02:00
|
|
|
Hash compressHash(const Hash & hash, unsigned int newSize)
|
|
|
|
{
|
2020-06-19 21:41:33 +03:00
|
|
|
Hash h(hash.type);
|
2005-01-14 18:04:03 +02:00
|
|
|
h.hashSize = newSize;
|
|
|
|
for (unsigned int i = 0; i < hash.hashSize; ++i)
|
|
|
|
h.hash[i % newSize] ^= hash.hash[i];
|
|
|
|
return h;
|
|
|
|
}
|
* Removed the `id' attribute hack.
* Formalise the notion of fixed-output derivations, i.e., derivations
for which a cryptographic hash of the output is known in advance.
Changes to such derivations should not propagate upwards through the
dependency graph. Previously this was done by specifying the hash
component of the output path through the `id' attribute, but this is
insecure since you can lie about it (i.e., you can specify any hash
and then produce a completely different output). Now the
responsibility for checking the output is moved from the builder to
Nix itself.
A fixed-output derivation can be created by specifying the
`outputHash' and `outputHashAlgo' attributes, the latter taking
values `md5', `sha1', and `sha256', and the former specifying the
actual hash in hexadecimal or in base-32 (auto-detected by looking
at the length of the attribute value). MD5 is included for
compatibility but should be considered deprecated.
* Removed the `drvPath' pseudo-attribute in derivation results. It's
no longer necessary.
* Cleaned up the support for multiple output paths in derivation store
expressions. Each output now has a unique identifier (e.g., `out',
`devel', `docs'). Previously there was no way to tell output paths
apart at the store expression level.
* `nix-hash' now has a flag `--base32' to specify that the hash should
be printed in base-32 notation.
* `fetchurl' accepts parameters `sha256' and `sha1' in addition to
`md5'.
* `nix-prefetch-url' now prints out a SHA-1 hash in base-32. (TODO: a
flag to specify the hash.)
2005-01-17 18:55:19 +02:00
|
|
|
|
|
|
|
|
2023-10-09 06:03:16 +03:00
|
|
|
std::optional<HashFormat> parseHashFormatOpt(std::string_view hashFormatName)
|
|
|
|
{
|
|
|
|
if (hashFormatName == "base16") return HashFormat::Base16;
|
|
|
|
if (hashFormatName == "base32") return HashFormat::Base32;
|
|
|
|
if (hashFormatName == "base64") return HashFormat::Base64;
|
|
|
|
if (hashFormatName == "sri") return HashFormat::SRI;
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
HashFormat parseHashFormat(std::string_view hashFormatName)
|
|
|
|
{
|
|
|
|
auto opt_f = parseHashFormatOpt(hashFormatName);
|
|
|
|
if (opt_f)
|
|
|
|
return *opt_f;
|
|
|
|
throw UsageError("unknown hash format '%1%', expect 'base16', 'base32', 'base64', or 'sri'", hashFormatName);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string_view printHashFormat(HashFormat HashFormat)
|
|
|
|
{
|
|
|
|
switch (HashFormat) {
|
|
|
|
case HashFormat::Base64:
|
|
|
|
return "base64";
|
|
|
|
case HashFormat::Base32:
|
|
|
|
return "base32";
|
|
|
|
case HashFormat::Base16:
|
|
|
|
return "base16";
|
|
|
|
case HashFormat::SRI:
|
|
|
|
return "sri";
|
|
|
|
default:
|
|
|
|
// illegal hash base enum value internally, as opposed to external input
|
|
|
|
// which should be validated with nice error message.
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-19 21:41:33 +03:00
|
|
|
std::optional<HashType> parseHashTypeOpt(std::string_view s)
|
* Removed the `id' attribute hack.
* Formalise the notion of fixed-output derivations, i.e., derivations
for which a cryptographic hash of the output is known in advance.
Changes to such derivations should not propagate upwards through the
dependency graph. Previously this was done by specifying the hash
component of the output path through the `id' attribute, but this is
insecure since you can lie about it (i.e., you can specify any hash
and then produce a completely different output). Now the
responsibility for checking the output is moved from the builder to
Nix itself.
A fixed-output derivation can be created by specifying the
`outputHash' and `outputHashAlgo' attributes, the latter taking
values `md5', `sha1', and `sha256', and the former specifying the
actual hash in hexadecimal or in base-32 (auto-detected by looking
at the length of the attribute value). MD5 is included for
compatibility but should be considered deprecated.
* Removed the `drvPath' pseudo-attribute in derivation results. It's
no longer necessary.
* Cleaned up the support for multiple output paths in derivation store
expressions. Each output now has a unique identifier (e.g., `out',
`devel', `docs'). Previously there was no way to tell output paths
apart at the store expression level.
* `nix-hash' now has a flag `--base32' to specify that the hash should
be printed in base-32 notation.
* `fetchurl' accepts parameters `sha256' and `sha1' in addition to
`md5'.
* `nix-prefetch-url' now prints out a SHA-1 hash in base-32. (TODO: a
flag to specify the hash.)
2005-01-17 18:55:19 +02:00
|
|
|
{
|
2020-06-19 01:09:22 +03:00
|
|
|
if (s == "md5") return htMD5;
|
2023-10-09 05:53:47 +03:00
|
|
|
if (s == "sha1") return htSHA1;
|
|
|
|
if (s == "sha256") return htSHA256;
|
|
|
|
if (s == "sha512") return htSHA512;
|
|
|
|
return std::nullopt;
|
* Removed the `id' attribute hack.
* Formalise the notion of fixed-output derivations, i.e., derivations
for which a cryptographic hash of the output is known in advance.
Changes to such derivations should not propagate upwards through the
dependency graph. Previously this was done by specifying the hash
component of the output path through the `id' attribute, but this is
insecure since you can lie about it (i.e., you can specify any hash
and then produce a completely different output). Now the
responsibility for checking the output is moved from the builder to
Nix itself.
A fixed-output derivation can be created by specifying the
`outputHash' and `outputHashAlgo' attributes, the latter taking
values `md5', `sha1', and `sha256', and the former specifying the
actual hash in hexadecimal or in base-32 (auto-detected by looking
at the length of the attribute value). MD5 is included for
compatibility but should be considered deprecated.
* Removed the `drvPath' pseudo-attribute in derivation results. It's
no longer necessary.
* Cleaned up the support for multiple output paths in derivation store
expressions. Each output now has a unique identifier (e.g., `out',
`devel', `docs'). Previously there was no way to tell output paths
apart at the store expression level.
* `nix-hash' now has a flag `--base32' to specify that the hash should
be printed in base-32 notation.
* `fetchurl' accepts parameters `sha256' and `sha1' in addition to
`md5'.
* `nix-prefetch-url' now prints out a SHA-1 hash in base-32. (TODO: a
flag to specify the hash.)
2005-01-17 18:55:19 +02:00
|
|
|
}
|
2006-09-05 00:06:23 +03:00
|
|
|
|
2020-06-19 21:41:33 +03:00
|
|
|
HashType parseHashType(std::string_view s)
|
2020-06-02 18:52:13 +03:00
|
|
|
{
|
|
|
|
auto opt_h = parseHashTypeOpt(s);
|
|
|
|
if (opt_h)
|
|
|
|
return *opt_h;
|
|
|
|
else
|
2023-10-09 06:00:14 +03:00
|
|
|
throw UsageError("unknown hash algorithm '%1%', expect 'md5', 'sha1', 'sha256', or 'sha512'", s);
|
2020-06-02 18:52:13 +03:00
|
|
|
}
|
2015-02-03 19:35:11 +02:00
|
|
|
|
2023-03-29 12:44:22 +03:00
|
|
|
std::string_view printHashType(HashType ht)
|
2008-12-03 18:10:17 +02:00
|
|
|
{
|
2020-06-02 18:52:13 +03:00
|
|
|
switch (ht) {
|
2020-06-25 16:50:30 +03:00
|
|
|
case htMD5: return "md5";
|
|
|
|
case htSHA1: return "sha1";
|
|
|
|
case htSHA256: return "sha256";
|
|
|
|
case htSHA512: return "sha512";
|
|
|
|
default:
|
|
|
|
// illegal hash type enum value internally, as opposed to external input
|
|
|
|
// which should be validated with nice error message.
|
2020-07-02 19:24:11 +03:00
|
|
|
assert(false);
|
2020-06-02 18:52:13 +03:00
|
|
|
}
|
2008-12-03 18:10:17 +02:00
|
|
|
}
|
|
|
|
|
2006-09-05 00:06:23 +03:00
|
|
|
}
|