Source file src/crypto/sha1/sha1.go

     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(make([]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, make([]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) || string(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 := new(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  

View as plain text