summaryrefslogtreecommitdiff
path: root/src/hname.c
diff options
context:
space:
mode:
authorcashmere <cashmere@autistici.org>2026-09-04 09:05:24 +0200
committercashmere <cashmere@autistici.org>2026-09-04 09:05:24 +0200
commit4f49b16079b27d7ce633619e4cddfdf2bffbc952 (patch)
treec296c1e7f3c3e2f6859c6d3a1b1b208779b89679 /src/hname.c
downloadrelic-4f49b16079b27d7ce633619e4cddfdf2bffbc952.tar.gz
initial commitHEADmaster
Diffstat (limited to 'src/hname.c')
-rw-r--r--src/hname.c284
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]);
+}