Home | History | Annotate | Download | only in sha512
      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 sha512 implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256
      6 // hash algorithms as defined in FIPS 180-4.
      7 package sha512
      8 
      9 import (
     10 	"crypto"
     11 	"hash"
     12 )
     13 
     14 func init() {
     15 	crypto.RegisterHash(crypto.SHA384, New384)
     16 	crypto.RegisterHash(crypto.SHA512, New)
     17 	crypto.RegisterHash(crypto.SHA512_224, New512_224)
     18 	crypto.RegisterHash(crypto.SHA512_256, New512_256)
     19 }
     20 
     21 const (
     22 	// Size is the size, in bytes, of a SHA-512 checksum.
     23 	Size = 64
     24 
     25 	// Size224 is the size, in bytes, of a SHA-512/224 checksum.
     26 	Size224 = 28
     27 
     28 	// Size256 is the size, in bytes, of a SHA-512/256 checksum.
     29 	Size256 = 32
     30 
     31 	// Size384 is the size, in bytes, of a SHA-384 checksum.
     32 	Size384 = 48
     33 
     34 	// BlockSize is the block size, in bytes, of the SHA-512/224,
     35 	// SHA-512/256, SHA-384 and SHA-512 hash functions.
     36 	BlockSize = 128
     37 )
     38 
     39 const (
     40 	chunk     = 128
     41 	init0     = 0x6a09e667f3bcc908
     42 	init1     = 0xbb67ae8584caa73b
     43 	init2     = 0x3c6ef372fe94f82b
     44 	init3     = 0xa54ff53a5f1d36f1
     45 	init4     = 0x510e527fade682d1
     46 	init5     = 0x9b05688c2b3e6c1f
     47 	init6     = 0x1f83d9abfb41bd6b
     48 	init7     = 0x5be0cd19137e2179
     49 	init0_224 = 0x8c3d37c819544da2
     50 	init1_224 = 0x73e1996689dcd4d6
     51 	init2_224 = 0x1dfab7ae32ff9c82
     52 	init3_224 = 0x679dd514582f9fcf
     53 	init4_224 = 0x0f6d2b697bd44da8
     54 	init5_224 = 0x77e36f7304c48942
     55 	init6_224 = 0x3f9d85a86a1d36c8
     56 	init7_224 = 0x1112e6ad91d692a1
     57 	init0_256 = 0x22312194fc2bf72c
     58 	init1_256 = 0x9f555fa3c84c64c2
     59 	init2_256 = 0x2393b86b6f53b151
     60 	init3_256 = 0x963877195940eabd
     61 	init4_256 = 0x96283ee2a88effe3
     62 	init5_256 = 0xbe5e1e2553863992
     63 	init6_256 = 0x2b0199fc2c85b8aa
     64 	init7_256 = 0x0eb72ddc81c52ca2
     65 	init0_384 = 0xcbbb9d5dc1059ed8
     66 	init1_384 = 0x629a292a367cd507
     67 	init2_384 = 0x9159015a3070dd17
     68 	init3_384 = 0x152fecd8f70e5939
     69 	init4_384 = 0x67332667ffc00b31
     70 	init5_384 = 0x8eb44a8768581511
     71 	init6_384 = 0xdb0c2e0d64f98fa7
     72 	init7_384 = 0x47b5481dbefa4fa4
     73 )
     74 
     75 // digest represents the partial evaluation of a checksum.
     76 type digest struct {
     77 	h        [8]uint64
     78 	x        [chunk]byte
     79 	nx       int
     80 	len      uint64
     81 	function crypto.Hash
     82 }
     83 
     84 func (d *digest) Reset() {
     85 	switch d.function {
     86 	case crypto.SHA384:
     87 		d.h[0] = init0_384
     88 		d.h[1] = init1_384
     89 		d.h[2] = init2_384
     90 		d.h[3] = init3_384
     91 		d.h[4] = init4_384
     92 		d.h[5] = init5_384
     93 		d.h[6] = init6_384
     94 		d.h[7] = init7_384
     95 	case crypto.SHA512_224:
     96 		d.h[0] = init0_224
     97 		d.h[1] = init1_224
     98 		d.h[2] = init2_224
     99 		d.h[3] = init3_224
    100 		d.h[4] = init4_224
    101 		d.h[5] = init5_224
    102 		d.h[6] = init6_224
    103 		d.h[7] = init7_224
    104 	case crypto.SHA512_256:
    105 		d.h[0] = init0_256
    106 		d.h[1] = init1_256
    107 		d.h[2] = init2_256
    108 		d.h[3] = init3_256
    109 		d.h[4] = init4_256
    110 		d.h[5] = init5_256
    111 		d.h[6] = init6_256
    112 		d.h[7] = init7_256
    113 	default:
    114 		d.h[0] = init0
    115 		d.h[1] = init1
    116 		d.h[2] = init2
    117 		d.h[3] = init3
    118 		d.h[4] = init4
    119 		d.h[5] = init5
    120 		d.h[6] = init6
    121 		d.h[7] = init7
    122 	}
    123 	d.nx = 0
    124 	d.len = 0
    125 }
    126 
    127 // New returns a new hash.Hash computing the SHA-512 checksum.
    128 func New() hash.Hash {
    129 	d := &digest{function: crypto.SHA512}
    130 	d.Reset()
    131 	return d
    132 }
    133 
    134 // New512_224 returns a new hash.Hash computing the SHA-512/224 checksum.
    135 func New512_224() hash.Hash {
    136 	d := &digest{function: crypto.SHA512_224}
    137 	d.Reset()
    138 	return d
    139 }
    140 
    141 // New512_256 returns a new hash.Hash computing the SHA-512/256 checksum.
    142 func New512_256() hash.Hash {
    143 	d := &digest{function: crypto.SHA512_256}
    144 	d.Reset()
    145 	return d
    146 }
    147 
    148 // New384 returns a new hash.Hash computing the SHA-384 checksum.
    149 func New384() hash.Hash {
    150 	d := &digest{function: crypto.SHA384}
    151 	d.Reset()
    152 	return d
    153 }
    154 
    155 func (d *digest) Size() int {
    156 	switch d.function {
    157 	case crypto.SHA512_224:
    158 		return Size224
    159 	case crypto.SHA512_256:
    160 		return Size256
    161 	case crypto.SHA384:
    162 		return Size384
    163 	default:
    164 		return Size
    165 	}
    166 }
    167 
    168 func (d *digest) BlockSize() int { return BlockSize }
    169 
    170 func (d *digest) Write(p []byte) (nn int, err error) {
    171 	nn = len(p)
    172 	d.len += uint64(nn)
    173 	if d.nx > 0 {
    174 		n := copy(d.x[d.nx:], p)
    175 		d.nx += n
    176 		if d.nx == chunk {
    177 			block(d, d.x[:])
    178 			d.nx = 0
    179 		}
    180 		p = p[n:]
    181 	}
    182 	if len(p) >= chunk {
    183 		n := len(p) &^ (chunk - 1)
    184 		block(d, p[:n])
    185 		p = p[n:]
    186 	}
    187 	if len(p) > 0 {
    188 		d.nx = copy(d.x[:], p)
    189 	}
    190 	return
    191 }
    192 
    193 func (d0 *digest) Sum(in []byte) []byte {
    194 	// Make a copy of d0 so that caller can keep writing and summing.
    195 	d := new(digest)
    196 	*d = *d0
    197 	hash := d.checkSum()
    198 	switch d.function {
    199 	case crypto.SHA384:
    200 		return append(in, hash[:Size384]...)
    201 	case crypto.SHA512_224:
    202 		return append(in, hash[:Size224]...)
    203 	case crypto.SHA512_256:
    204 		return append(in, hash[:Size256]...)
    205 	default:
    206 		return append(in, hash[:]...)
    207 	}
    208 }
    209 
    210 func (d *digest) checkSum() [Size]byte {
    211 	// Padding. Add a 1 bit and 0 bits until 112 bytes mod 128.
    212 	len := d.len
    213 	var tmp [128]byte
    214 	tmp[0] = 0x80
    215 	if len%128 < 112 {
    216 		d.Write(tmp[0 : 112-len%128])
    217 	} else {
    218 		d.Write(tmp[0 : 128+112-len%128])
    219 	}
    220 
    221 	// Length in bits.
    222 	len <<= 3
    223 	for i := uint(0); i < 16; i++ {
    224 		tmp[i] = byte(len >> (120 - 8*i))
    225 	}
    226 	d.Write(tmp[0:16])
    227 
    228 	if d.nx != 0 {
    229 		panic("d.nx != 0")
    230 	}
    231 
    232 	h := d.h[:]
    233 	if d.function == crypto.SHA384 {
    234 		h = d.h[:6]
    235 	}
    236 
    237 	var digest [Size]byte
    238 	for i, s := range h {
    239 		digest[i*8] = byte(s >> 56)
    240 		digest[i*8+1] = byte(s >> 48)
    241 		digest[i*8+2] = byte(s >> 40)
    242 		digest[i*8+3] = byte(s >> 32)
    243 		digest[i*8+4] = byte(s >> 24)
    244 		digest[i*8+5] = byte(s >> 16)
    245 		digest[i*8+6] = byte(s >> 8)
    246 		digest[i*8+7] = byte(s)
    247 	}
    248 
    249 	return digest
    250 }
    251 
    252 // Sum512 returns the SHA512 checksum of the data.
    253 func Sum512(data []byte) [Size]byte {
    254 	d := digest{function: crypto.SHA512}
    255 	d.Reset()
    256 	d.Write(data)
    257 	return d.checkSum()
    258 }
    259 
    260 // Sum384 returns the SHA384 checksum of the data.
    261 func Sum384(data []byte) (sum384 [Size384]byte) {
    262 	d := digest{function: crypto.SHA384}
    263 	d.Reset()
    264 	d.Write(data)
    265 	sum := d.checkSum()
    266 	copy(sum384[:], sum[:Size384])
    267 	return
    268 }
    269 
    270 // Sum512_224 returns the Sum512/224 checksum of the data.
    271 func Sum512_224(data []byte) (sum224 [Size224]byte) {
    272 	d := digest{function: crypto.SHA512_224}
    273 	d.Reset()
    274 	d.Write(data)
    275 	sum := d.checkSum()
    276 	copy(sum224[:], sum[:Size224])
    277 	return
    278 }
    279 
    280 // Sum512_256 returns the Sum512/256 checksum of the data.
    281 func Sum512_256(data []byte) (sum256 [Size256]byte) {
    282 	d := digest{function: crypto.SHA512_256}
    283 	d.Reset()
    284 	d.Write(data)
    285 	sum := d.checkSum()
    286 	copy(sum256[:], sum[:Size256])
    287 	return
    288 }
    289