sha1.mx raw

   1  // Copyright 2009 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  // Package sha1 implements the SHA-1 hash algorithm as defined in RFC 3174.
   6  //
   7  // SHA-1 is cryptographically broken and should not be used for secure
   8  // applications.
   9  package sha1
  10  
  11  import (
  12  	"crypto"
  13  	"crypto/internal/boring"
  14  	"crypto/internal/fips140only"
  15  	"errors"
  16  	"hash"
  17  	"internal/byteorder"
  18  )
  19  
  20  func init() {
  21  	crypto.RegisterHash(crypto.SHA1, New)
  22  }
  23  
  24  // The size of a SHA-1 checksum in bytes.
  25  const Size = 20
  26  
  27  // The blocksize of SHA-1 in bytes.
  28  const BlockSize = 64
  29  
  30  const (
  31  	chunk = 64
  32  	init0 = 0x67452301
  33  	init1 = 0xEFCDAB89
  34  	init2 = 0x98BADCFE
  35  	init3 = 0x10325476
  36  	init4 = 0xC3D2E1F0
  37  )
  38  
  39  // digest represents the partial evaluation of a checksum.
  40  type digest struct {
  41  	h   [5]uint32
  42  	x   [chunk]byte
  43  	nx  int
  44  	len uint64
  45  }
  46  
  47  const (
  48  	magic         = "sha\x01"
  49  	marshaledSize = len(magic) + 5*4 + chunk + 8
  50  )
  51  
  52  func (d *digest) MarshalBinary() ([]byte, error) {
  53  	return d.AppendBinary([]byte{:0:marshaledSize})
  54  }
  55  
  56  func (d *digest) AppendBinary(b []byte) ([]byte, error) {
  57  	b = append(b, magic...)
  58  	b = byteorder.BEAppendUint32(b, d.h[0])
  59  	b = byteorder.BEAppendUint32(b, d.h[1])
  60  	b = byteorder.BEAppendUint32(b, d.h[2])
  61  	b = byteorder.BEAppendUint32(b, d.h[3])
  62  	b = byteorder.BEAppendUint32(b, d.h[4])
  63  	b = append(b, d.x[:d.nx]...)
  64  	b = append(b, []byte{:len(d.x)-d.nx}...)
  65  	b = byteorder.BEAppendUint64(b, d.len)
  66  	return b, nil
  67  }
  68  
  69  func (d *digest) UnmarshalBinary(b []byte) error {
  70  	if len(b) < len(magic) || b[:len(magic)] != magic {
  71  		return errors.New("crypto/sha1: invalid hash state identifier")
  72  	}
  73  	if len(b) != marshaledSize {
  74  		return errors.New("crypto/sha1: invalid hash state size")
  75  	}
  76  	b = b[len(magic):]
  77  	b, d.h[0] = consumeUint32(b)
  78  	b, d.h[1] = consumeUint32(b)
  79  	b, d.h[2] = consumeUint32(b)
  80  	b, d.h[3] = consumeUint32(b)
  81  	b, d.h[4] = consumeUint32(b)
  82  	b = b[copy(d.x[:], b):]
  83  	b, d.len = consumeUint64(b)
  84  	d.nx = int(d.len % chunk)
  85  	return nil
  86  }
  87  
  88  func consumeUint64(b []byte) ([]byte, uint64) {
  89  	return b[8:], byteorder.BEUint64(b)
  90  }
  91  
  92  func consumeUint32(b []byte) ([]byte, uint32) {
  93  	return b[4:], byteorder.BEUint32(b)
  94  }
  95  
  96  func (d *digest) Clone() (hash.Cloner, error) {
  97  	r := *d
  98  	return &r, nil
  99  }
 100  
 101  func (d *digest) Reset() {
 102  	d.h[0] = init0
 103  	d.h[1] = init1
 104  	d.h[2] = init2
 105  	d.h[3] = init3
 106  	d.h[4] = init4
 107  	d.nx = 0
 108  	d.len = 0
 109  }
 110  
 111  // New returns a new [hash.Hash] computing the SHA1 checksum. The Hash
 112  // also implements [encoding.BinaryMarshaler], [encoding.BinaryAppender] and
 113  // [encoding.BinaryUnmarshaler] to marshal and unmarshal the internal
 114  // state of the hash.
 115  func New() hash.Hash {
 116  	if boring.Enabled {
 117  		return boring.NewSHA1()
 118  	}
 119  	d := &digest{}
 120  	d.Reset()
 121  	return d
 122  }
 123  
 124  func (d *digest) Size() int { return Size }
 125  
 126  func (d *digest) BlockSize() int { return BlockSize }
 127  
 128  func (d *digest) Write(p []byte) (nn int, err error) {
 129  	if fips140only.Enabled {
 130  		return 0, errors.New("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
 131  	}
 132  	boring.Unreachable()
 133  	nn = len(p)
 134  	d.len += uint64(nn)
 135  	if d.nx > 0 {
 136  		n := copy(d.x[d.nx:], p)
 137  		d.nx += n
 138  		if d.nx == chunk {
 139  			block(d, d.x[:])
 140  			d.nx = 0
 141  		}
 142  		p = p[n:]
 143  	}
 144  	if len(p) >= chunk {
 145  		n := len(p) &^ (chunk - 1)
 146  		block(d, p[:n])
 147  		p = p[n:]
 148  	}
 149  	if len(p) > 0 {
 150  		d.nx = copy(d.x[:], p)
 151  	}
 152  	return
 153  }
 154  
 155  func (d *digest) Sum(in []byte) []byte {
 156  	boring.Unreachable()
 157  	// Make a copy of d so that caller can keep writing and summing.
 158  	d0 := *d
 159  	hash := d0.checkSum()
 160  	return append(in, hash[:]...)
 161  }
 162  
 163  func (d *digest) checkSum() [Size]byte {
 164  	if fips140only.Enabled {
 165  		panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
 166  	}
 167  
 168  	len := d.len
 169  	// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
 170  	var tmp [64 + 8]byte // padding + length buffer
 171  	tmp[0] = 0x80
 172  	var t uint64
 173  	if len%64 < 56 {
 174  		t = 56 - len%64
 175  	} else {
 176  		t = 64 + 56 - len%64
 177  	}
 178  
 179  	// Length in bits.
 180  	len <<= 3
 181  	padlen := tmp[:t+8]
 182  	byteorder.BEPutUint64(padlen[t:], len)
 183  	d.Write(padlen)
 184  
 185  	if d.nx != 0 {
 186  		panic("d.nx != 0")
 187  	}
 188  
 189  	var digest [Size]byte
 190  
 191  	byteorder.BEPutUint32(digest[0:], d.h[0])
 192  	byteorder.BEPutUint32(digest[4:], d.h[1])
 193  	byteorder.BEPutUint32(digest[8:], d.h[2])
 194  	byteorder.BEPutUint32(digest[12:], d.h[3])
 195  	byteorder.BEPutUint32(digest[16:], d.h[4])
 196  
 197  	return digest
 198  }
 199  
 200  // ConstantTimeSum computes the same result of [Sum] but in constant time
 201  func (d *digest) ConstantTimeSum(in []byte) []byte {
 202  	d0 := *d
 203  	hash := d0.constSum()
 204  	return append(in, hash[:]...)
 205  }
 206  
 207  func (d *digest) constSum() [Size]byte {
 208  	if fips140only.Enabled {
 209  		panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
 210  	}
 211  
 212  	var length [8]byte
 213  	l := d.len << 3
 214  	for i := uint(0); i < 8; i++ {
 215  		length[i] = byte(l >> (56 - 8*i))
 216  	}
 217  
 218  	nx := byte(d.nx)
 219  	t := nx - 56                 // if nx < 56 then the MSB of t is one
 220  	mask1b := byte(int8(t) >> 7) // mask1b is 0xFF iff one block is enough
 221  
 222  	separator := byte(0x80) // gets reset to 0x00 once used
 223  	for i := byte(0); i < chunk; i++ {
 224  		mask := byte(int8(i-nx) >> 7) // 0x00 after the end of data
 225  
 226  		// if we reached the end of the data, replace with 0x80 or 0x00
 227  		d.x[i] = (^mask & separator) | (mask & d.x[i])
 228  
 229  		// zero the separator once used
 230  		separator &= mask
 231  
 232  		if i >= 56 {
 233  			// we might have to write the length here if all fit in one block
 234  			d.x[i] |= mask1b & length[i-56]
 235  		}
 236  	}
 237  
 238  	// compress, and only keep the digest if all fit in one block
 239  	block(d, d.x[:])
 240  
 241  	var digest [Size]byte
 242  	for i, s := range d.h {
 243  		digest[i*4] = mask1b & byte(s>>24)
 244  		digest[i*4+1] = mask1b & byte(s>>16)
 245  		digest[i*4+2] = mask1b & byte(s>>8)
 246  		digest[i*4+3] = mask1b & byte(s)
 247  	}
 248  
 249  	for i := byte(0); i < chunk; i++ {
 250  		// second block, it's always past the end of data, might start with 0x80
 251  		if i < 56 {
 252  			d.x[i] = separator
 253  			separator = 0
 254  		} else {
 255  			d.x[i] = length[i-56]
 256  		}
 257  	}
 258  
 259  	// compress, and only keep the digest if we actually needed the second block
 260  	block(d, d.x[:])
 261  
 262  	for i, s := range d.h {
 263  		digest[i*4] |= ^mask1b & byte(s>>24)
 264  		digest[i*4+1] |= ^mask1b & byte(s>>16)
 265  		digest[i*4+2] |= ^mask1b & byte(s>>8)
 266  		digest[i*4+3] |= ^mask1b & byte(s)
 267  	}
 268  
 269  	return digest
 270  }
 271  
 272  // Sum returns the SHA-1 checksum of the data.
 273  func Sum(data []byte) [Size]byte {
 274  	if boring.Enabled {
 275  		return boring.SHA1(data)
 276  	}
 277  	if fips140only.Enabled {
 278  		panic("crypto/sha1: use of SHA-1 is not allowed in FIPS 140-only mode")
 279  	}
 280  	var d digest
 281  	d.Reset()
 282  	d.Write(data)
 283  	return d.checkSum()
 284  }
 285