cryptopals

https://cryptopals.com/
Log | Files | Refs

sha1.go (4884B)


      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 sha_1
     10 
     11 // The size of a SHA-1 checksum in bytes.
     12 const Size = 20
     13 
     14 // The blocksize of SHA-1 in bytes.
     15 const BlockSize = 64
     16 
     17 const (
     18 	chunk = 64
     19 	init0 = 0x67452301
     20 	init1 = 0xEFCDAB89
     21 	init2 = 0x98BADCFE
     22 	init3 = 0x10325476
     23 	init4 = 0xC3D2E1F0
     24 )
     25 
     26 const (
     27 	_K0 = 0x5A827999
     28 	_K1 = 0x6ED9EBA1
     29 	_K2 = 0x8F1BBCDC
     30 	_K3 = 0xCA62C1D6
     31 )
     32 
     33 // digest represents the partial evaluation of a checksum.
     34 type digest struct {
     35 	h   [5]uint32
     36 	x   [chunk]byte
     37 	nx  int
     38 	len uint64
     39 }
     40 
     41 func (d *digest) Reset() {
     42 	d.h[0] = init0
     43 	d.h[1] = init1
     44 	d.h[2] = init2
     45 	d.h[3] = init3
     46 	d.h[4] = init4
     47 	d.nx = 0
     48 	d.len = 0
     49 }
     50 
     51 func (d *digest) Size() int { return Size }
     52 
     53 func (d *digest) BlockSize() int { return BlockSize }
     54 
     55 func (d *digest) Write(p []byte) (nn int, err error) {
     56 	nn = len(p)
     57 	d.len += uint64(nn)
     58 	if d.nx > 0 {
     59 		n := copy(d.x[d.nx:], p)
     60 		d.nx += n
     61 		if d.nx == chunk {
     62 			blockGeneric(d, d.x[:])
     63 			d.nx = 0
     64 		}
     65 		p = p[n:]
     66 	}
     67 	if len(p) >= chunk {
     68 		n := len(p) &^ (chunk - 1)
     69 		blockGeneric(d, p[:n])
     70 		p = p[n:]
     71 	}
     72 	if len(p) > 0 {
     73 		d.nx = copy(d.x[:], p)
     74 	}
     75 	return
     76 }
     77 
     78 func (d *digest) checkSum() [Size]byte {
     79 	len := d.len
     80 	// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
     81 	var tmp [64]byte
     82 	tmp[0] = 0x80
     83 	if len%64 < 56 {
     84 		d.Write(tmp[0 : 56-len%64])
     85 	} else {
     86 		d.Write(tmp[0 : 64+56-len%64])
     87 	}
     88 
     89 	// Length in bits.
     90 	len <<= 3
     91 	PutUint64(tmp[:], len)
     92 	d.Write(tmp[0:8])
     93 
     94 	if d.nx != 0 {
     95 		panic("d.nx != 0")
     96 	}
     97 
     98 	var digest [Size]byte
     99 
    100 	putUint32(digest[0:], d.h[0])
    101 	putUint32(digest[4:], d.h[1])
    102 	putUint32(digest[8:], d.h[2])
    103 	putUint32(digest[12:], d.h[3])
    104 	putUint32(digest[16:], d.h[4])
    105 
    106 	return digest
    107 }
    108 
    109 // Sum returns the SHA-1 checksum of the data.
    110 func Sum(data []byte) [Size]byte {
    111 	var d digest
    112 	d.Reset()
    113 	d.Write(data)
    114 	return d.checkSum()
    115 }
    116 
    117 func (d *digest) ResetForged(registers [5]uint32) {
    118 	d.h[0] = registers[0]
    119 	d.h[1] = registers[1]
    120 	d.h[2] = registers[2]
    121 	d.h[3] = registers[3]
    122 	d.h[4] = registers[4]
    123 	d.nx = 0
    124 	d.len = 0
    125 }
    126 
    127 func SumForged(data []byte, registers [5]uint32) [Size]byte {
    128 	var d digest
    129 	d.ResetForged(registers)
    130 	d.Write(data)
    131 	return d.checkSum()
    132 }
    133 
    134 func PutUint64(x []byte, s uint64) {
    135 	_ = x[7]
    136 	x[0] = byte(s >> 56)
    137 	x[1] = byte(s >> 48)
    138 	x[2] = byte(s >> 40)
    139 	x[3] = byte(s >> 32)
    140 	x[4] = byte(s >> 24)
    141 	x[5] = byte(s >> 16)
    142 	x[6] = byte(s >> 8)
    143 	x[7] = byte(s)
    144 }
    145 
    146 func putUint32(x []byte, s uint32) {
    147 	_ = x[3]
    148 	x[0] = byte(s >> 24)
    149 	x[1] = byte(s >> 16)
    150 	x[2] = byte(s >> 8)
    151 	x[3] = byte(s)
    152 }
    153 
    154 // blockGeneric is a portable, pure Go version of the SHA-1 block step.
    155 // It's used by sha1block_generic.go and tests.
    156 func blockGeneric(dig *digest, p []byte) {
    157 	var w [16]uint32
    158 
    159 	h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
    160 	for len(p) >= chunk {
    161 		// Can interlace the computation of w with the
    162 		// rounds below if needed for speed.
    163 		for i := 0; i < 16; i++ {
    164 			j := i * 4
    165 			w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
    166 		}
    167 
    168 		a, b, c, d, e := h0, h1, h2, h3, h4
    169 
    170 		// Each of the four 20-iteration rounds
    171 		// differs only in the computation of f and
    172 		// the choice of K (_K0, _K1, etc).
    173 		i := 0
    174 		for ; i < 16; i++ {
    175 			f := b&c | (^b)&d
    176 			a5 := a<<5 | a>>(32-5)
    177 			b30 := b<<30 | b>>(32-30)
    178 			t := a5 + f + e + w[i&0xf] + _K0
    179 			a, b, c, d, e = t, a, b30, c, d
    180 		}
    181 		for ; i < 20; i++ {
    182 			tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
    183 			w[i&0xf] = tmp<<1 | tmp>>(32-1)
    184 
    185 			f := b&c | (^b)&d
    186 			a5 := a<<5 | a>>(32-5)
    187 			b30 := b<<30 | b>>(32-30)
    188 			t := a5 + f + e + w[i&0xf] + _K0
    189 			a, b, c, d, e = t, a, b30, c, d
    190 		}
    191 		for ; i < 40; i++ {
    192 			tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
    193 			w[i&0xf] = tmp<<1 | tmp>>(32-1)
    194 			f := b ^ c ^ d
    195 			a5 := a<<5 | a>>(32-5)
    196 			b30 := b<<30 | b>>(32-30)
    197 			t := a5 + f + e + w[i&0xf] + _K1
    198 			a, b, c, d, e = t, a, b30, c, d
    199 		}
    200 		for ; i < 60; i++ {
    201 			tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
    202 			w[i&0xf] = tmp<<1 | tmp>>(32-1)
    203 			f := ((b | c) & d) | (b & c)
    204 
    205 			a5 := a<<5 | a>>(32-5)
    206 			b30 := b<<30 | b>>(32-30)
    207 			t := a5 + f + e + w[i&0xf] + _K2
    208 			a, b, c, d, e = t, a, b30, c, d
    209 		}
    210 		for ; i < 80; i++ {
    211 			tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
    212 			w[i&0xf] = tmp<<1 | tmp>>(32-1)
    213 			f := b ^ c ^ d
    214 			a5 := a<<5 | a>>(32-5)
    215 			b30 := b<<30 | b>>(32-30)
    216 			t := a5 + f + e + w[i&0xf] + _K3
    217 			a, b, c, d, e = t, a, b30, c, d
    218 		}
    219 
    220 		h0 += a
    221 		h1 += b
    222 		h2 += c
    223 		h3 += d
    224 		h4 += e
    225 
    226 		p = p[chunk:]
    227 	}
    228 
    229 	dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] = h0, h1, h2, h3, h4
    230 }