gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

checksum.go (5304B)


      1 /*
      2  * MinIO Go Library for Amazon S3 Compatible Cloud Storage
      3  * Copyright 2015-2023 MinIO, Inc.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package minio
     19 
     20 import (
     21 	"crypto/sha1"
     22 	"crypto/sha256"
     23 	"encoding/base64"
     24 	"hash"
     25 	"hash/crc32"
     26 	"io"
     27 	"math/bits"
     28 )
     29 
     30 // ChecksumType contains information about the checksum type.
     31 type ChecksumType uint32
     32 
     33 const (
     34 
     35 	// ChecksumSHA256 indicates a SHA256 checksum.
     36 	ChecksumSHA256 ChecksumType = 1 << iota
     37 	// ChecksumSHA1 indicates a SHA-1 checksum.
     38 	ChecksumSHA1
     39 	// ChecksumCRC32 indicates a CRC32 checksum with IEEE table.
     40 	ChecksumCRC32
     41 	// ChecksumCRC32C indicates a CRC32 checksum with Castagnoli table.
     42 	ChecksumCRC32C
     43 
     44 	// Keep after all valid checksums
     45 	checksumLast
     46 
     47 	// checksumMask is a mask for valid checksum types.
     48 	checksumMask = checksumLast - 1
     49 
     50 	// ChecksumNone indicates no checksum.
     51 	ChecksumNone ChecksumType = 0
     52 
     53 	amzChecksumAlgo   = "x-amz-checksum-algorithm"
     54 	amzChecksumCRC32  = "x-amz-checksum-crc32"
     55 	amzChecksumCRC32C = "x-amz-checksum-crc32c"
     56 	amzChecksumSHA1   = "x-amz-checksum-sha1"
     57 	amzChecksumSHA256 = "x-amz-checksum-sha256"
     58 )
     59 
     60 // Is returns if c is all of t.
     61 func (c ChecksumType) Is(t ChecksumType) bool {
     62 	return c&t == t
     63 }
     64 
     65 // Key returns the header key.
     66 // returns empty string if invalid or none.
     67 func (c ChecksumType) Key() string {
     68 	switch c & checksumMask {
     69 	case ChecksumCRC32:
     70 		return amzChecksumCRC32
     71 	case ChecksumCRC32C:
     72 		return amzChecksumCRC32C
     73 	case ChecksumSHA1:
     74 		return amzChecksumSHA1
     75 	case ChecksumSHA256:
     76 		return amzChecksumSHA256
     77 	}
     78 	return ""
     79 }
     80 
     81 // RawByteLen returns the size of the un-encoded checksum.
     82 func (c ChecksumType) RawByteLen() int {
     83 	switch c & checksumMask {
     84 	case ChecksumCRC32, ChecksumCRC32C:
     85 		return 4
     86 	case ChecksumSHA1:
     87 		return sha1.Size
     88 	case ChecksumSHA256:
     89 		return sha256.Size
     90 	}
     91 	return 0
     92 }
     93 
     94 // Hasher returns a hasher corresponding to the checksum type.
     95 // Returns nil if no checksum.
     96 func (c ChecksumType) Hasher() hash.Hash {
     97 	switch c & checksumMask {
     98 	case ChecksumCRC32:
     99 		return crc32.NewIEEE()
    100 	case ChecksumCRC32C:
    101 		return crc32.New(crc32.MakeTable(crc32.Castagnoli))
    102 	case ChecksumSHA1:
    103 		return sha1.New()
    104 	case ChecksumSHA256:
    105 		return sha256.New()
    106 	}
    107 	return nil
    108 }
    109 
    110 // IsSet returns whether the type is valid and known.
    111 func (c ChecksumType) IsSet() bool {
    112 	return bits.OnesCount32(uint32(c)) == 1
    113 }
    114 
    115 // String returns the type as a string.
    116 // CRC32, CRC32C, SHA1, and SHA256 for valid values.
    117 // Empty string for unset and "<invalid>" if not valid.
    118 func (c ChecksumType) String() string {
    119 	switch c & checksumMask {
    120 	case ChecksumCRC32:
    121 		return "CRC32"
    122 	case ChecksumCRC32C:
    123 		return "CRC32C"
    124 	case ChecksumSHA1:
    125 		return "SHA1"
    126 	case ChecksumSHA256:
    127 		return "SHA256"
    128 	case ChecksumNone:
    129 		return ""
    130 	}
    131 	return "<invalid>"
    132 }
    133 
    134 // ChecksumReader reads all of r and returns a checksum of type c.
    135 // Returns any error that may have occurred while reading.
    136 func (c ChecksumType) ChecksumReader(r io.Reader) (Checksum, error) {
    137 	h := c.Hasher()
    138 	if h == nil {
    139 		return Checksum{}, nil
    140 	}
    141 	_, err := io.Copy(h, r)
    142 	if err != nil {
    143 		return Checksum{}, err
    144 	}
    145 	return NewChecksum(c, h.Sum(nil)), nil
    146 }
    147 
    148 // ChecksumBytes returns a checksum of the content b with type c.
    149 func (c ChecksumType) ChecksumBytes(b []byte) Checksum {
    150 	h := c.Hasher()
    151 	if h == nil {
    152 		return Checksum{}
    153 	}
    154 	n, err := h.Write(b)
    155 	if err != nil || n != len(b) {
    156 		// Shouldn't happen with these checksummers.
    157 		return Checksum{}
    158 	}
    159 	return NewChecksum(c, h.Sum(nil))
    160 }
    161 
    162 // Checksum is a type and encoded value.
    163 type Checksum struct {
    164 	Type ChecksumType
    165 	r    []byte
    166 }
    167 
    168 // NewChecksum sets the checksum to the value of b,
    169 // which is the raw hash output.
    170 // If the length of c does not match t.RawByteLen,
    171 // a checksum with ChecksumNone is returned.
    172 func NewChecksum(t ChecksumType, b []byte) Checksum {
    173 	if t.IsSet() && len(b) == t.RawByteLen() {
    174 		return Checksum{Type: t, r: b}
    175 	}
    176 	return Checksum{}
    177 }
    178 
    179 // NewChecksumString sets the checksum to the value of s,
    180 // which is the base 64 encoded raw hash output.
    181 // If the length of c does not match t.RawByteLen, it is not added.
    182 func NewChecksumString(t ChecksumType, s string) Checksum {
    183 	b, _ := base64.StdEncoding.DecodeString(s)
    184 	if t.IsSet() && len(b) == t.RawByteLen() {
    185 		return Checksum{Type: t, r: b}
    186 	}
    187 	return Checksum{}
    188 }
    189 
    190 // IsSet returns whether the checksum is valid and known.
    191 func (c Checksum) IsSet() bool {
    192 	return c.Type.IsSet() && len(c.r) == c.Type.RawByteLen()
    193 }
    194 
    195 // Encoded returns the encoded value.
    196 // Returns the empty string if not set or valid.
    197 func (c Checksum) Encoded() string {
    198 	if !c.IsSet() {
    199 		return ""
    200 	}
    201 	return base64.StdEncoding.EncodeToString(c.r)
    202 }
    203 
    204 // Raw returns the raw checksum value if set.
    205 func (c Checksum) Raw() []byte {
    206 	if !c.IsSet() {
    207 		return nil
    208 	}
    209 	return c.r
    210 }