git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/tools/hasher/main.go (about) 1 package main 2 3 import ( 4 "crypto/sha512" 5 "encoding/hex" 6 "fmt" 7 "hash" 8 "io" 9 "os" 10 11 "crypto/sha256" 12 13 "git.sr.ht/~pingoo/stdx/cobra" 14 "github.com/zeebo/blake3" 15 "golang.org/x/crypto/blake2b" 16 ) 17 18 const ( 19 version = "0.1.0" 20 21 AlgorithmSha256 = "sha256" 22 AlgorithmSha512 = "sha512" 23 AlgorithmBlake3 = "blake3" 24 AlgorithmBlake2b = "blake2b" 25 ) 26 27 var ( 28 algorithmArg string 29 stdinArg bool 30 ) 31 32 func init() { 33 rootCmd.Flags().StringVarP(&algorithmArg, "algorithm", "a", AlgorithmSha256, "Algorithm to use. Valid values are [sha256, sha512, blake3, blake2b]") 34 rootCmd.Flags().BoolVar(&stdinArg, "stdin", false, "Read data from stdin") 35 } 36 37 func main() { 38 err := rootCmd.Execute() 39 if err != nil { 40 fmt.Fprintln(os.Stdout, err.Error()) 41 os.Exit(1) 42 } 43 } 44 45 var rootCmd = &cobra.Command{ 46 Use: "hash [flags] [files...]", 47 Short: "Hash and verify files", 48 Version: version, 49 // SilenceUsage: true, 50 SilenceErrors: true, 51 RunE: func(cmd *cobra.Command, args []string) (err error) { 52 if stdinArg { 53 var hash []byte 54 55 hash, err = hashData(os.Stdin, algorithmArg) 56 if err != nil { 57 return 58 } 59 fmt.Println(hex.EncodeToString(hash)) 60 61 return 62 } 63 64 if len(args) < 1 { 65 cmd.Help() 66 return 67 } 68 69 for _, file := range args { 70 var hash []byte 71 72 hash, err = hashFile(file, algorithmArg) 73 if err != nil { 74 return 75 } 76 fmt.Printf("%s %s\n", hex.EncodeToString(hash), file) 77 } 78 79 return 80 }, 81 } 82 83 func hashFile(filePath, algorithm string) (outputHash []byte, err error) { 84 var file *os.File 85 86 file, err = os.Open(filePath) 87 if err != nil { 88 err = fmt.Errorf("opening file %s: %w", filePath, err) 89 return 90 } 91 defer file.Close() 92 93 outputHash, err = hashData(file, algorithm) 94 if err != nil { 95 err = fmt.Errorf("file %s: %w", filePath, err) 96 return 97 } 98 99 return 100 } 101 102 func hashData(data io.Reader, algorithm string) (outputHash []byte, err error) { 103 var hasher hash.Hash 104 105 switch algorithm { 106 case AlgorithmSha256: 107 hasher = sha256.New() 108 case AlgorithmSha512: 109 hasher = sha512.New() 110 case AlgorithmBlake2b: 111 hasher, err = blake2b.New(32, nil) 112 if err != nil { 113 err = fmt.Errorf("error when initializing blake2b hashing function: %w", err) 114 return 115 } 116 case AlgorithmBlake3: 117 hasher = blake3.New() 118 119 default: 120 err = fmt.Errorf("%s is not a supported hashing algorithm", algorithm) 121 return 122 } 123 124 _, err = io.Copy(hasher, data) 125 if err != nil { 126 err = fmt.Errorf("error when hashing: %w", err) 127 return 128 } 129 130 outputHash = hasher.Sum(nil) 131 132 return 133 }