...

Source file src/pkg/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		"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