// Copyright IBM Corp. 2014, 2026 // SPDX-License-Identifier: BUSL-1.1 package releaseauth import ( "bytes" "crypto/sha256" "encoding/hex" "errors" "fmt" "log" ) // SHA256Hash represents a 256-bit SHA hash type SHA256Hash [sha256.Size]byte // ErrInvalidSHA256Hash is returned when the hash is invalid var ErrInvalidSHA256Hash = errors.New("the value was not a valid SHA-256 hash") // SHA256FromHex decodes a SHA256Hash from a hex string dump func SHA256FromHex(hashHex string) (SHA256Hash, error) { var result [sha256.Size]byte hash, err := hex.DecodeString(hashHex) if err != nil || len(hash) != sha256.Size { return result, ErrInvalidSHA256Hash } if copy(result[:], hash) != sha256.Size { panic("could not copy hash value") } return result, nil } // SHA256Checksums decodes a file generated by the sha256sum program type SHA256Checksums map[string]SHA256Hash func ParseChecksums(data []byte) (SHA256Checksums, error) { items := bytes.Split(data, []byte("\n")) result := make(map[string]SHA256Hash, len(items)) for _, line := range items { parts := bytes.SplitN(line, []byte(" "), 2) if len(parts) != 2 { break } log.Printf("[TRACE] parsing SHA256SUMS %q = %q", parts[0], parts[1]) hash, err := SHA256FromHex(string(parts[0])) if err != nil { return result, fmt.Errorf("failed to parse checksums: %w", err) } result[string(parts[1])] = hash } return result, nil } // Validate retrieves a SHA256Hash for the a filename and compares it // to the specified hash. Validate returns an error if the hash is not found // or if it does not match. func (c SHA256Checksums) Validate(filename string, hash SHA256Hash) error { sum, ok := c[filename] if !ok { return fmt.Errorf("no checksum found for filename %q", filename) } if sum != hash { return fmt.Errorf("checksums do not match") } return nil }