1package glacier 2 3import ( 4 "crypto/sha256" 5 "io" 6 7 "github.com/aws/aws-sdk-go/internal/sdkio" 8) 9 10const bufsize = 1024 * 1024 11 12// Hash contains information about the tree-hash and linear hash of a 13// Glacier payload. This structure is generated by ComputeHashes(). 14type Hash struct { 15 TreeHash []byte 16 LinearHash []byte 17} 18 19// ComputeHashes computes the tree-hash and linear hash of a seekable reader r. 20// 21// See http://docs.aws.amazon.com/amazonglacier/latest/dev/checksum-calculations.html for more information. 22func ComputeHashes(r io.ReadSeeker) Hash { 23 start, _ := r.Seek(0, sdkio.SeekCurrent) // Read the whole stream 24 defer r.Seek(start, sdkio.SeekStart) // Rewind stream at end 25 26 buf := make([]byte, bufsize) 27 hashes := [][]byte{} 28 hsh := sha256.New() 29 30 for { 31 // Build leaf nodes in 1MB chunks 32 n, err := io.ReadAtLeast(r, buf, bufsize) 33 if n == 0 { 34 break 35 } 36 37 tmpHash := sha256.Sum256(buf[:n]) 38 hashes = append(hashes, tmpHash[:]) 39 hsh.Write(buf[:n]) // Track linear hash while we're at it 40 41 if err != nil { 42 break // This is the last chunk 43 } 44 } 45 46 return Hash{ 47 LinearHash: hsh.Sum(nil), 48 TreeHash: ComputeTreeHash(hashes), 49 } 50} 51 52// ComputeTreeHash builds a tree hash root node given a slice of 53// hashes. Glacier tree hash to be derived from SHA256 hashes of 1MB 54// chucks of the data. 55// 56// See http://docs.aws.amazon.com/amazonglacier/latest/dev/checksum-calculations.html for more information. 57func ComputeTreeHash(hashes [][]byte) []byte { 58 if hashes == nil || len(hashes) == 0 { 59 return nil 60 } 61 62 for len(hashes) > 1 { 63 tmpHashes := [][]byte{} 64 65 for i := 0; i < len(hashes); i += 2 { 66 if i+1 <= len(hashes)-1 { 67 tmpHash := append(append([]byte{}, hashes[i]...), hashes[i+1]...) 68 tmpSum := sha256.Sum256(tmpHash) 69 tmpHashes = append(tmpHashes, tmpSum[:]) 70 } else { 71 tmpHashes = append(tmpHashes, hashes[i]) 72 } 73 } 74 75 hashes = tmpHashes 76 } 77 78 return hashes[0] 79} 80