github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/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  	putUint64(tmp[:], len)
   108  	d.Write(tmp[0:8])
   109  
   110  	if d.nx != 0 {
   111  		panic("d.nx != 0")
   112  	}
   113  
   114  	var digest [Size]byte
   115  
   116  	putUint32(digest[0:], d.h[0])
   117  	putUint32(digest[4:], d.h[1])
   118  	putUint32(digest[8:], d.h[2])
   119  	putUint32(digest[12:], d.h[3])
   120  	putUint32(digest[16:], d.h[4])
   121  
   122  	return digest
   123  }
   124  
   125  // ConstantTimeSum computes the same result of Sum() but in constant time
   126  func (d0 *digest) ConstantTimeSum(in []byte) []byte {
   127  	d := *d0
   128  	hash := d.constSum()
   129  	return append(in, hash[:]...)
   130  }
   131  
   132  func (d *digest) constSum() [Size]byte {
   133  	var length [8]byte
   134  	l := d.len << 3
   135  	for i := uint(0); i < 8; i++ {
   136  		length[i] = byte(l >> (56 - 8*i))
   137  	}
   138  
   139  	nx := byte(d.nx)
   140  	t := nx - 56                 // if nx < 56 then the MSB of t is one
   141  	mask1b := byte(int8(t) >> 7) // mask1b is 0xFF iff one block is enough
   142  
   143  	separator := byte(0x80) // gets reset to 0x00 once used
   144  	for i := byte(0); i < chunk; i++ {
   145  		mask := byte(int8(i-nx) >> 7) // 0x00 after the end of data
   146  
   147  		// if we reached the end of the data, replace with 0x80 or 0x00
   148  		d.x[i] = (^mask & separator) | (mask & d.x[i])
   149  
   150  		// zero the separator once used
   151  		separator &= mask
   152  
   153  		if i >= 56 {
   154  			// we might have to write the length here if all fit in one block
   155  			d.x[i] |= mask1b & length[i-56]
   156  		}
   157  	}
   158  
   159  	// compress, and only keep the digest if all fit in one block
   160  	block(d, d.x[:])
   161  
   162  	var digest [Size]byte
   163  	for i, s := range d.h {
   164  		digest[i*4] = mask1b & byte(s>>24)
   165  		digest[i*4+1] = mask1b & byte(s>>16)
   166  		digest[i*4+2] = mask1b & byte(s>>8)
   167  		digest[i*4+3] = mask1b & byte(s)
   168  	}
   169  
   170  	for i := byte(0); i < chunk; i++ {
   171  		// second block, it's always past the end of data, might start with 0x80
   172  		if i < 56 {
   173  			d.x[i] = separator
   174  			separator = 0
   175  		} else {
   176  			d.x[i] = length[i-56]
   177  		}
   178  	}
   179  
   180  	// compress, and only keep the digest if we actually needed the second block
   181  	block(d, d.x[:])
   182  
   183  	for i, s := range d.h {
   184  		digest[i*4] |= ^mask1b & byte(s>>24)
   185  		digest[i*4+1] |= ^mask1b & byte(s>>16)
   186  		digest[i*4+2] |= ^mask1b & byte(s>>8)
   187  		digest[i*4+3] |= ^mask1b & byte(s)
   188  	}
   189  
   190  	return digest
   191  }
   192  
   193  // Sum returns the SHA-1 checksum of the data.
   194  func Sum(data []byte) [Size]byte {
   195  	var d digest
   196  	d.Reset()
   197  	d.Write(data)
   198  	return d.checkSum()
   199  }
   200  
   201  func putUint64(x []byte, s uint64) {
   202  	_ = x[7]
   203  	x[0] = byte(s >> 56)
   204  	x[1] = byte(s >> 48)
   205  	x[2] = byte(s >> 40)
   206  	x[3] = byte(s >> 32)
   207  	x[4] = byte(s >> 24)
   208  	x[5] = byte(s >> 16)
   209  	x[6] = byte(s >> 8)
   210  	x[7] = byte(s)
   211  }
   212  
   213  func putUint32(x []byte, s uint32) {
   214  	_ = x[3]
   215  	x[0] = byte(s >> 24)
   216  	x[1] = byte(s >> 16)
   217  	x[2] = byte(s >> 8)
   218  	x[3] = byte(s)
   219  }