#!/usr/bin/python3 """ * File : sdlh [The Shamir Discrete Logarithm Hash Function https://senderek.ie/sdlh] * Version : 2.0 * Date : 1 Jan 2025 * License : BSD * * Copyright (c) 2003 - 2025 * Ralf Senderek, Ireland. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Ralf Senderek. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * """ import sys import os HashModulus = 1 HashModulusLength = 1 Generator = 1 GeneratorLength = 1 UserID = "none" Min_Hashmodulus = 1000 #-----------------------------------------------------------# def ModExp (Base, Exp, Mod): Hash = 1 X = Exp Factor = Base while X > 0 : Remainder = X % 2 X = X // 2 if Remainder == 1: Hash = Hash * Factor % Mod Factor = Factor * Factor % Mod return Hash #-----------------------------------------------------------# def SDLH(Message) : # Message is of type bytes # Calculates hash(x) = Generator^Message mod HashModulus # # Speeding up the computation by avoiding to convert the string into # a long integer # This code processes characters one by one using # two ModExp()-operations for every character # Hash = 1 # for Character in Message: # (1) A = ModExp(Generator, ord(Character), HashModulus) # (2) B = ModExp(Hash, 256, HashModulus) # (3) Hash = (A * B) % HashModulus # return Hash # Implementation with precomputed table # precomputing table for step (1) table = [] table.append(1) index = 1 Number = 1 while index < 256 : Number = (Number * Generator) % HashModulus table.append(Number) index = index + 1 # process the message byte by byte Hash = 1 for Byte in Message: A = table[Byte] # step (1) B = Hash # step (2) index = 8 while index > 0 : B = (B * B) % HashModulus index = index - 1 Hash = (A * B) % HashModulus # step (3) return Hash #-----------------------------------------------------------# def SDLH256(Message) : Hash256 = 0 X = SDLH(Message) Size = pow(2,256) while X > 0 : Section = X % Size X = X // Size Hash256 = Hash256 ^ Section # XOR operation return Hash256 #-----------------------------------------------------------# def read_keyfile(FileName) : import string global HashModulus, HashModulusLength, Generator, GeneratorLength global UserID start = 0 try: FILE = open(FileName, "r") Key = FILE.readlines() FILE.close() except : print ("Cannot open keyfile ", FileName) sys.exit(2) if (Key[0+start][:15] == "-----BEGIN PURE") : start += 1 if (Key[0+start][:7].upper() == "MODULUS") : start += 1 if (Key[0+start][:10].upper() == "ENCRYPTION") : start += 1 if (Key[0+start][:10].upper() == "DECRYPTION") : start += 1 if len(Key) >= 3 : try: if (Key[0+start][:11].upper()) == "HASHMODULUS" and (Key[1+start][:9].upper()) == "GENERATOR" : HashModulus = int(Key[0+start][14:-1]) X = HashModulus HashModulusLength = 0 while X > 0 : X = X // 2 HashModulusLength = HashModulusLength + 1 Generator = int(Key[1+start][12:-1]) GeneratorLength = 0 X = Generator while X > 0 : X = X // 2 GeneratorLength = GeneratorLength + 1 if HashModulusLength < Min_Hashmodulus : print ("The Hashmodulus is too short!") sys.exit(2) else : error() UserID = Key[2+start][:-1] + " (" + str(HashModulusLength) + "," + str(GeneratorLength) + ")" except: print ("The neccessary key information is not available.") sys.exit(2) else: error() sys.exit(2) #-----------------------------------------------------------# def print_hash(Message, Filename) : if Bits == 256 : Hash = SDLH256(Message) else : Hash = SDLH(Message) print ( Hash, Filename), if Verbose : print (Bits, "bits") print () #-----------------------------------------------------------# def error() : print ("The keyfile is corrupt.",) print ("It must consist of 3 lines (for example) :") print () print ("Hashmodulus = 342345...7763578991") print ("Generator = 323471...95343213") print ("User Identification String") print () sys.exit(2) #-----------------------------------------------------------# # MAIN # #-----------------------------------------------------------# Bits = HashModulusLength Key = "unknown" UserID = "None" HOME = "." Verbose = False # look for a config file with hashkey information. # if no hashkey file is found, abort ! if os.name == "posix": HOME = os.environ['HOME'] if os.path.exists(HOME + "/.hashkey") : read_keyfile(HOME + "/.hashkey") Key = "config" if len(sys.argv) > 0 : if len(sys.argv) > 1 : if sys.argv[1] == "-256" : Bits = 256 del sys.argv[1] if sys.argv[1] == "-v" : Verbose = True del sys.argv[1] if (len(sys.argv) > 1): if (sys.argv[1] == "-key") and (len(sys.argv) >= 3) : read_keyfile(sys.argv[2]) Key = "file" del sys.argv[1:3] if not ((Key == "config") or (Key == "file")): # keyfile is not available print("Cannot hash without a keyfile") sys.exit(4) if Bits != 256 : Bits = HashModulusLength if Key == "config" and Verbose : print ("Using config file.") if Key == "file" and Verbose : print ("Using key file.") if Verbose : print ("User: ", UserID) print() if (len(sys.argv) == 1) or (sys.argv[1] == "-"): InBytes = sys.stdin.buffer.read() print_hash(InBytes, "stdin") sys.exit(0) else : for File in sys.argv[1:] : try: F = open(File , "rb") InBytes = F.read() F.close() print_hash(InBytes, File) except: print ("Cannot open file ", File) sys.exit(1) sys.exit(0) else : print ("usage: sdlh [-256] [-v] [-key keyfile] files") sys.exit(0) #-----------------------------------------------------------# # Copyright 2003 - 2025, Ralf Senderek, Ireland # #-----------------------------------------------------------#