github.com/aavshr/aws-sdk-go@v1.41.3/service/glacier/treehash.go (about)

     1  package glacier
     2  
     3  import (
     4  	"crypto/sha256"
     5  	"io"
     6  
     7  	"github.com/aavshr/aws-sdk-go/internal/sdkio"
     8  )
     9  
    10  const 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().
    14  type 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.
    22  func 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.
    57  func 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  }