Source file src/crypto/sha1/sha1.go

Documentation: crypto/sha1

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

View as plain text