github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/crypto/sha1/sha1.go (about)

     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  	"hash"
    14  )
    15  
    16  func init() {
    17  	crypto.RegisterHash(crypto.SHA1, New)
    18  }
    19  
    20  // The size of a SHA-1 checksum in bytes.
    21  const Size = 20
    22  
    23  // The blocksize of SHA-1 in bytes.
    24  const BlockSize = 64
    25  
    26  const (
    27  	chunk = 64
    28  	init0 = 0x67452301
    29  	init1 = 0xEFCDAB89
    30  	init2 = 0x98BADCFE
    31  	init3 = 0x10325476
    32  	init4 = 0xC3D2E1F0
    33  )
    34  
    35  // digest represents the partial evaluation of a checksum.
    36  type digest struct {
    37  	h   [5]uint32
    38  	x   [chunk]byte
    39  	nx  int
    40  	len uint64
    41  }
    42  
    43  func (d *digest) Reset() {
    44  	d.h[0] = init0
    45  	d.h[1] = init1
    46  	d.h[2] = init2
    47  	d.h[3] = init3
    48  	d.h[4] = init4
    49  	d.nx = 0
    50  	d.len = 0
    51  }
    52  
    53  // New returns a new hash.Hash computing the SHA1 checksum.
    54  func New() hash.Hash {
    55  	d := new(digest)
    56  	d.Reset()
    57  	return d
    58  }
    59  
    60  func (d *digest) Size() int { return Size }
    61  
    62  func (d *digest) BlockSize() int { return BlockSize }
    63  
    64  func (d *digest) Write(p []byte) (nn int, err error) {
    65  	nn = len(p)
    66  	d.len += uint64(nn)
    67  	if d.nx > 0 {
    68  		n := copy(d.x[d.nx:], p)
    69  		d.nx += n
    70  		if d.nx == chunk {
    71  			block(d, d.x[:])
    72  			d.nx = 0
    73  		}
    74  		p = p[n:]
    75  	}
    76  	if len(p) >= chunk {
    77  		n := len(p) &^ (chunk - 1)
    78  		block(d, p[:n])
    79  		p = p[n:]
    80  	}
    81  	if len(p) > 0 {
    82  		d.nx = copy(d.x[:], p)
    83  	}
    84  	return
    85  }
    86  
    87  func (d0 *digest) Sum(in []byte) []byte {
    88  	// Make a copy of d0 so that caller can keep writing and summing.
    89  	d := *d0
    90  	hash := d.checkSum()
    91  	return append(in, hash[:]...)
    92  }
    93  
    94  func (d *digest) checkSum() [Size]byte {
    95  	len := d.len
    96  	// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
    97  	var tmp [64]byte
    98  	tmp[0] = 0x80
    99  	if len%64 < 56 {
   100  		d.Write(tmp[0 : 56-len%64])
   101  	} else {
   102  		d.Write(tmp[0 : 64+56-len%64])
   103  	}
   104  
   105  	// Length in bits.
   106  	len <<= 3
   107  	for i := uint(0); i < 8; i++ {
   108  		tmp[i] = byte(len >> (56 - 8*i))
   109  	}
   110  	d.Write(tmp[0:8])
   111  
   112  	if d.nx != 0 {
   113  		panic("d.nx != 0")
   114  	}
   115  
   116  	var digest [Size]byte
   117  	for i, s := range d.h {
   118  		digest[i*4] = byte(s >> 24)
   119  		digest[i*4+1] = byte(s >> 16)
   120  		digest[i*4+2] = byte(s >> 8)
   121  		digest[i*4+3] = byte(s)
   122  	}
   123  
   124  	return digest
   125  }
   126  
   127  // ConstantTimeSum computes the same result of Sum() but in constant time
   128  func (d0 *digest) ConstantTimeSum(in []byte) []byte {
   129  	d := *d0
   130  	hash := d.constSum()
   131  	return append(in, hash[:]...)
   132  }
   133  
   134  func (d *digest) constSum() [Size]byte {
   135  	var length [8]byte
   136  	l := d.len << 3
   137  	for i := uint(0); i < 8; i++ {
   138  		length[i] = byte(l >> (56 - 8*i))
   139  	}
   140  
   141  	nx := byte(d.nx)
   142  	t := nx - 56                 // if nx < 56 then the MSB of t is one
   143  	mask1b := byte(int8(t) >> 7) // mask1b is 0xFF iff one block is enough
   144  
   145  	separator := byte(0x80) // gets reset to 0x00 once used
   146  	for i := byte(0); i < chunk; i++ {
   147  		mask := byte(int8(i-nx) >> 7) // 0x00 after the end of data
   148  
   149  		// if we reached the end of the data, replace with 0x80 or 0x00
   150  		d.x[i] = (^mask & separator) | (mask & d.x[i])
   151  
   152  		// zero the separator once used
   153  		separator &= mask
   154  
   155  		if i >= 56 {
   156  			// we might have to write the length here if all fit in one block
   157  			d.x[i] |= mask1b & length[i-56]
   158  		}
   159  	}
   160  
   161  	// compress, and only keep the digest if all fit in one block
   162  	block(d, d.x[:])
   163  
   164  	var digest [Size]byte
   165  	for i, s := range d.h {
   166  		digest[i*4] = mask1b & byte(s>>24)
   167  		digest[i*4+1] = mask1b & byte(s>>16)
   168  		digest[i*4+2] = mask1b & byte(s>>8)
   169  		digest[i*4+3] = mask1b & byte(s)
   170  	}
   171  
   172  	for i := byte(0); i < chunk; i++ {
   173  		// second block, it's always past the end of data, might start with 0x80
   174  		if i < 56 {
   175  			d.x[i] = separator
   176  			separator = 0
   177  		} else {
   178  			d.x[i] = length[i-56]
   179  		}
   180  	}
   181  
   182  	// compress, and only keep the digest if we actually needed the second block
   183  	block(d, d.x[:])
   184  
   185  	for i, s := range d.h {
   186  		digest[i*4] |= ^mask1b & byte(s>>24)
   187  		digest[i*4+1] |= ^mask1b & byte(s>>16)
   188  		digest[i*4+2] |= ^mask1b & byte(s>>8)
   189  		digest[i*4+3] |= ^mask1b & byte(s)
   190  	}
   191  
   192  	return digest
   193  }
   194  
   195  // Sum returns the SHA-1 checksum of the data.
   196  func Sum(data []byte) [Size]byte {
   197  	var d digest
   198  	d.Reset()
   199  	d.Write(data)
   200  	return d.checkSum()
   201  }