...

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