diff options
| author | cashmere <cashmere@autistici.org> | 2026-09-04 09:05:24 +0200 |
|---|---|---|
| committer | cashmere <cashmere@autistici.org> | 2026-09-04 09:05:24 +0200 |
| commit | 4f49b16079b27d7ce633619e4cddfdf2bffbc952 (patch) | |
| tree | c296c1e7f3c3e2f6859c6d3a1b1b208779b89679 /src/hname.c | |
| download | relic-master.tar.gz | |
Diffstat (limited to 'src/hname.c')
| -rw-r--r-- | src/hname.c | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/src/hname.c b/src/hname.c new file mode 100644 index 0000000..7f9fc59 --- /dev/null +++ b/src/hname.c @@ -0,0 +1,284 @@ +/* +** Copyright (c) 2017 D. Richard Hipp +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the Simplified BSD License (also +** known as the "2-Clause License" or "FreeBSD License".) +** +** This program is distributed in the hope that it will be useful, +** but without any warranty; without even the implied warranty of +** merchantability or fitness for a particular purpose. +** +** Author contact information: +** drh@hwaci.com +** http://www.hwaci.com/drh/ +** +******************************************************************************* +** +** This file contains generic code for dealing with hashes used for +** naming artifacts. Specific hash algorithms are implemented separately +** (for example in sha1.c and sha3.c). This file contains the generic +** interface logic. +** +** "hname" is intended to be an abbreviation of "hash name". +*/ +#include "config.h" +#include "hname.h" + + +#if INTERFACE +/* +** Code numbers for the allowed hash algorithms. +*/ +#define HNAME_ERROR 0 /* Not a valid hash */ +#define HNAME_SHA1 1 /* SHA1 */ +#define HNAME_K256 2 /* SHA3-256 */ + +/* +** Minimum and maximum lengths for a hash value when hex encoded. +*/ +#define HNAME_MIN 40 /* Length for SHA1 */ +#define HNAME_MAX 64 /* Length for SHA3-256 */ + +/* +** Hash lengths for the various algorithms +*/ +#define HNAME_LEN_SHA1 40 +#define HNAME_LEN_K256 64 + +/* +** The number of distinct hash algorithms: +*/ +#define HNAME_COUNT 2 /* Just SHA1 and SHA3-256. Let's keep it that way! */ + +/* +** Hash naming policies +*/ +#define HPOLICY_SHA1 0 /* Use SHA1 hashes */ +#define HPOLICY_AUTO 1 /* SHA1 but auto-promote to SHA3 */ +#define HPOLICY_SHA3 2 /* Use SHA3 hashes */ +#define HPOLICY_SHA3_ONLY 3 /* Use SHA3 hashes exclusively */ +#define HPOLICY_SHUN_SHA1 4 /* Shun all SHA1 objects */ + +#endif /* INTERFACE */ + +/* +** Return a human-readable name for the hash algorithm given a hash with +** a length of nHash hexadecimal digits. +*/ +const char *hname_alg(int nHash){ + if( nHash==HNAME_LEN_SHA1 ) return "SHA1"; + if( nHash==HNAME_LEN_K256 ) return "SHA3-256"; + return "?"; +} + +/* +** Return the integer hash algorithm code number (ex: HNAME_K256) for +** the hash string provided. Or return HNAME_ERROR (0) if the input string +** is not a valid artifact hash string. +*/ +int hname_validate(const char *zHash, int nHash){ + int id; + switch( nHash ){ + case HNAME_LEN_SHA1: id = HNAME_SHA1; break; + case HNAME_LEN_K256: id = HNAME_K256; break; + default: return HNAME_ERROR; + } + if( !validate16(zHash, nHash) ) return HNAME_ERROR; + return id; +} + +/* +** Verify that zHash is a valid hash for the content in pContent. +** Return true if the hash is correct. Return false if the content +** does not match the hash. +** +** Actually, the returned value is one of the hash algorithm constants +** corresponding to the hash that matched if the hash is correct. +** (Examples: HNAME_SHA1 or HNAME_K256). And the return is HNAME_ERROR +** if the hash does not match. +*/ +int hname_verify_hash(Blob *pContent, const char *zHash, int nHash){ + int id = HNAME_ERROR; + switch( nHash ){ + case HNAME_LEN_SHA1: { + Blob hash; + sha1sum_blob(pContent, &hash); + if( memcmp(blob_buffer(&hash),zHash,HNAME_LEN_SHA1)==0 ) id = HNAME_SHA1; + blob_reset(&hash); + break; + } + case HNAME_LEN_K256: { + sha3sum_init(256); + sha3sum_step_blob(pContent); + if( memcmp(sha3sum_finish(0),zHash,64)==0 ) id = HNAME_K256; + break; + } + } + return id; +} + +/* +** Verify that zHash is a valid hash for the content of a file on +** disk named zFile. +** +** Return true if the hash is correct. Return false if the content +** does not match the hash. +** +** Actually, the returned value is one of the hash algorithm constants +** corresponding to the hash that matched if the hash is correct. +** (Examples: HNAME_SHA1 or HNAME_K256). And the return is HNAME_ERROR +** if the hash does not match. +*/ +int hname_verify_file_hash(const char *zFile, const char *zHash, int nHash){ + int id = HNAME_ERROR; + switch( nHash ){ + case HNAME_LEN_SHA1: { + Blob hash; + if( sha1sum_file(zFile, RepoFILE, &hash) ) break; + if( memcmp(blob_buffer(&hash),zHash,HNAME_LEN_SHA1)==0 ) id = HNAME_SHA1; + blob_reset(&hash); + break; + } + case HNAME_LEN_K256: { + Blob hash; + if( sha3sum_file(zFile, RepoFILE, 256, &hash) ) break; + if( memcmp(blob_buffer(&hash),zHash,64)==0 ) id = HNAME_LEN_K256; + blob_reset(&hash); + break; + } + } + return id; +} + +/* +** Compute a hash on blob pContent. Write the hash into blob pHashOut. +** This routine assumes that pHashOut is uninitialized. +** +** The preferred hash is used for iHType==0 and the alternative hash is +** used if iHType==1. (The interface is designed to accommodate more than +** just two hashes, but HNAME_COUNT is currently fixed at 2.) +** +** Depending on the hash policy, the alternative hash may be disallowed. +** If the alterative hash is disallowed, the routine returns 0. This +** routine returns 1 if iHType>0 and the alternative hash is allowed, +** and it always returns 1 when iHType==0. +** +** Alternative hash is disallowed for all hash policies except auto, +** sha1 and sha3. +*/ +int hname_hash(const Blob *pContent, unsigned int iHType, Blob *pHashOut){ + assert( iHType==0 || iHType==1 ); + if( iHType==1 ){ + switch( g.eHashPolicy ){ + case HPOLICY_AUTO: + case HPOLICY_SHA1: + sha3sum_blob(pContent, 256, pHashOut); + return 1; + case HPOLICY_SHA3: + sha1sum_blob(pContent, pHashOut); + return 1; + } + } + if( iHType==0 ){ + switch( g.eHashPolicy ){ + case HPOLICY_SHA1: + case HPOLICY_AUTO: + sha1sum_blob(pContent, pHashOut); + return 1; + case HPOLICY_SHA3: + case HPOLICY_SHA3_ONLY: + case HPOLICY_SHUN_SHA1: + sha3sum_blob(pContent, 256, pHashOut); + return 1; + } + } + blob_init(pHashOut, 0, 0); + return 0; +} + +/* +** Return the default hash policy for repositories that do not currently +** have an assigned hash policy. +** +** Make the default HPOLICY_AUTO if there are SHA1 artifacts but no SHA3 +** artifacts in the repository. Make the default HPOLICY_SHA3 if there +** are one or more SHA3 artifacts or if the repository is initially empty. +*/ +int hname_default_policy(void){ + if( db_exists("SELECT 1 FROM blob WHERE length(uuid)>40") + || !db_exists("SELECT 1 FROM blob WHERE length(uuid)==40") + ){ + return HPOLICY_SHA3; + }else{ + return HPOLICY_AUTO; + } +} + +/* +** Names of the hash policies. +*/ +static const char *const azPolicy[] = { + "sha1", "auto", "sha3", "sha3-only", "shun-sha1" +}; + +/* Return the name of the current hash policy. +*/ +const char *hpolicy_name(void){ + return azPolicy[g.eHashPolicy]; +} + + +/* +** COMMAND: hash-policy* +** +** Usage: fossil hash-policy ?NEW-POLICY? +** +** Query or set the hash policy for the current repository. Available hash +** policies are as follows: +** +** sha1 New artifact names are created using SHA1 +** +** auto New artifact names are created using SHA1, but +** automatically change the policy to "sha3" when +** any SHA3 artifact enters the repository. +** +** sha3 New artifact names are created using SHA3, but +** older artifacts with SHA1 names may be reused. +** +** sha3-only Use only SHA3 artifact names. Do not reuse legacy +** SHA1 names. +** +** shun-sha1 Shun any SHA1 artifacts received by sync operations +** other than clones. Older legacy SHA1 artifacts are +** allowed during a clone. +** +** The default hash policy for existing repositories is "auto", which will +** immediately promote to "sha3" if the repository contains one or more +** artifacts with SHA3 names. The default hash policy for new repositories +** is "shun-sha1". +*/ +void hash_policy_command(void){ + int i; + db_find_and_open_repository(0, 0); + if( g.argc!=2 && g.argc!=3 ) usage("?NEW-POLICY?"); + if( g.argc==2 ){ + fossil_print("%s\n", azPolicy[g.eHashPolicy]); + return; + } + for(i=HPOLICY_SHA1; i<=HPOLICY_SHUN_SHA1; i++){ + if( fossil_strcmp(g.argv[2],azPolicy[i])==0 ){ + if( i==HPOLICY_AUTO + && db_exists("SELECT 1 FROM blob WHERE length(uuid)>40") + ){ + i = HPOLICY_SHA3; + } + g.eHashPolicy = i; + db_set_int("hash-policy", i, 0); + fossil_print("%s\n", azPolicy[i]); + return; + } + } + fossil_fatal("unknown hash policy \"%s\" - should be one of: sha1 auto" + " sha3 sha3-only shun-sha1", g.argv[2]); +} |
