package chksum import ( "bufio" "bytes" "crypto/md5" "crypto/sha1" "crypto/sha256" "crypto/sha512" "encoding/hex" "errors" "hash" "io" "os" "regexp" ) /* checksum file format SHA512 (filename) = hex-encoded checksum or SHA256 (filename) = hex-encoded checksum */ type Checksum struct { FileName string Alg string Bytes []byte Hash hash.Hash } var hashes = map[string]func() hash.Hash{ "SHA512": sha512.New, "SHA256": sha256.New, "SHA1": sha1.New, "MD5": md5.New, } func ParseFile(fname string) ([]Checksum, error) { fd, err := os.Open(fname) if err != nil { return nil, err } defer fd.Close() var checklist []Checksum re := regexp.MustCompile(`(\w+) \(([^)]+)\) = (\w+)`) scanner := bufio.NewScanner(fd) for scanner.Scan() { //var cs Checksum r := re.FindStringSubmatch(scanner.Text()) if len(r) != 4 { return nil, errors.New("invalid content") } h, ok := hashes[r[1]] if !ok { return nil, errors.New("unknown hash alg") } bytes, err := hex.DecodeString(r[3]) if err != nil { return nil, err } cs := Checksum{ FileName: r[2], Alg: r[1], Bytes: bytes, Hash: h(), } checklist = append(checklist, cs) } return checklist, scanner.Err() } func (c Checksum) Check() error { fd, err := os.Open(c.FileName) if err != nil { return err } defer fd.Close() io.Copy(c.Hash, fd) if !bytes.Equal(c.Hash.Sum(nil), c.Bytes) { return errors.New("hash mismatch") } return nil }