// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package sha512 implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256 // hash algorithms as defined in FIPS 180-4.
package sha512 import ( ) const ( // size512 is the size, in bytes, of a SHA-512 checksum. size512 = 64 // size224 is the size, in bytes, of a SHA-512/224 checksum. size224 = 28 // size256 is the size, in bytes, of a SHA-512/256 checksum. size256 = 32 // size384 is the size, in bytes, of a SHA-384 checksum. size384 = 48 // blockSize is the block size, in bytes, of the SHA-512/224, // SHA-512/256, SHA-384 and SHA-512 hash functions. blockSize = 128 ) const ( chunk = 128 init0 = 0x6a09e667f3bcc908 init1 = 0xbb67ae8584caa73b init2 = 0x3c6ef372fe94f82b init3 = 0xa54ff53a5f1d36f1 init4 = 0x510e527fade682d1 init5 = 0x9b05688c2b3e6c1f init6 = 0x1f83d9abfb41bd6b init7 = 0x5be0cd19137e2179 init0_224 = 0x8c3d37c819544da2 init1_224 = 0x73e1996689dcd4d6 init2_224 = 0x1dfab7ae32ff9c82 init3_224 = 0x679dd514582f9fcf init4_224 = 0x0f6d2b697bd44da8 init5_224 = 0x77e36f7304c48942 init6_224 = 0x3f9d85a86a1d36c8 init7_224 = 0x1112e6ad91d692a1 init0_256 = 0x22312194fc2bf72c init1_256 = 0x9f555fa3c84c64c2 init2_256 = 0x2393b86b6f53b151 init3_256 = 0x963877195940eabd init4_256 = 0x96283ee2a88effe3 init5_256 = 0xbe5e1e2553863992 init6_256 = 0x2b0199fc2c85b8aa init7_256 = 0x0eb72ddc81c52ca2 init0_384 = 0xcbbb9d5dc1059ed8 init1_384 = 0x629a292a367cd507 init2_384 = 0x9159015a3070dd17 init3_384 = 0x152fecd8f70e5939 init4_384 = 0x67332667ffc00b31 init5_384 = 0x8eb44a8768581511 init6_384 = 0xdb0c2e0d64f98fa7 init7_384 = 0x47b5481dbefa4fa4 ) // Digest is a SHA-384, SHA-512, SHA-512/224, or SHA-512/256 [hash.Hash] // implementation. type Digest struct { h [8]uint64 x [chunk]byte nx int len uint64 size int // size224, size256, size384, or size512 } func ( *Digest) () { switch .size { case size384: .h[0] = init0_384 .h[1] = init1_384 .h[2] = init2_384 .h[3] = init3_384 .h[4] = init4_384 .h[5] = init5_384 .h[6] = init6_384 .h[7] = init7_384 case size224: .h[0] = init0_224 .h[1] = init1_224 .h[2] = init2_224 .h[3] = init3_224 .h[4] = init4_224 .h[5] = init5_224 .h[6] = init6_224 .h[7] = init7_224 case size256: .h[0] = init0_256 .h[1] = init1_256 .h[2] = init2_256 .h[3] = init3_256 .h[4] = init4_256 .h[5] = init5_256 .h[6] = init6_256 .h[7] = init7_256 case size512: .h[0] = init0 .h[1] = init1 .h[2] = init2 .h[3] = init3 .h[4] = init4 .h[5] = init5 .h[6] = init6 .h[7] = init7 default: panic("unknown size") } .nx = 0 .len = 0 } const ( magic384 = "sha\x04" magic512_224 = "sha\x05" magic512_256 = "sha\x06" magic512 = "sha\x07" marshaledSize = len(magic512) + 8*8 + chunk + 8 ) func ( *Digest) () ([]byte, error) { return .AppendBinary(make([]byte, 0, marshaledSize)) } func ( *Digest) ( []byte) ([]byte, error) { switch .size { case size384: = append(, magic384...) case size224: = append(, magic512_224...) case size256: = append(, magic512_256...) case size512: = append(, magic512...) default: panic("unknown size") } = byteorder.BEAppendUint64(, .h[0]) = byteorder.BEAppendUint64(, .h[1]) = byteorder.BEAppendUint64(, .h[2]) = byteorder.BEAppendUint64(, .h[3]) = byteorder.BEAppendUint64(, .h[4]) = byteorder.BEAppendUint64(, .h[5]) = byteorder.BEAppendUint64(, .h[6]) = byteorder.BEAppendUint64(, .h[7]) = append(, .x[:.nx]...) = append(, make([]byte, len(.x)-.nx)...) = byteorder.BEAppendUint64(, .len) return , nil } func ( *Digest) ( []byte) error { if len() < len(magic512) { return errors.New("crypto/sha512: invalid hash state identifier") } switch { case .size == size384 && string([:len(magic384)]) == magic384: case .size == size224 && string([:len(magic512_224)]) == magic512_224: case .size == size256 && string([:len(magic512_256)]) == magic512_256: case .size == size512 && string([:len(magic512)]) == magic512: default: return errors.New("crypto/sha512: invalid hash state identifier") } if len() != marshaledSize { return errors.New("crypto/sha512: invalid hash state size") } = [len(magic512):] , .h[0] = consumeUint64() , .h[1] = consumeUint64() , .h[2] = consumeUint64() , .h[3] = consumeUint64() , .h[4] = consumeUint64() , .h[5] = consumeUint64() , .h[6] = consumeUint64() , .h[7] = consumeUint64() = [copy(.x[:], ):] , .len = consumeUint64() .nx = int(.len % chunk) return nil } func consumeUint64( []byte) ([]byte, uint64) { return [8:], byteorder.BEUint64() } // New returns a new Digest computing the SHA-512 hash. func () *Digest { := &Digest{size: size512} .Reset() return } // New512_224 returns a new Digest computing the SHA-512/224 hash. func () *Digest { := &Digest{size: size224} .Reset() return } // New512_256 returns a new Digest computing the SHA-512/256 hash. func () *Digest { := &Digest{size: size256} .Reset() return } // New384 returns a new Digest computing the SHA-384 hash. func () *Digest { := &Digest{size: size384} .Reset() return } func ( *Digest) () int { return .size } func ( *Digest) () int { return blockSize } func ( *Digest) ( []byte) ( int, error) { = len() .len += uint64() if .nx > 0 { := copy(.x[.nx:], ) .nx += if .nx == chunk { block(, .x[:]) .nx = 0 } = [:] } if len() >= chunk { := len() &^ (chunk - 1) block(, [:]) = [:] } if len() > 0 { .nx = copy(.x[:], ) } return } func ( *Digest) ( []byte) []byte { fips140.RecordApproved() // Make a copy of d so that caller can keep writing and summing. := new(Digest) * = * := .checkSum() return append(, [:.size]...) } func ( *Digest) () [size512]byte { // Padding. Add a 1 bit and 0 bits until 112 bytes mod 128. := .len var [128 + 16]byte // padding + length buffer [0] = 0x80 var uint64 if %128 < 112 { = 112 - %128 } else { = 128 + 112 - %128 } // Length in bits. <<= 3 := [:+16] // Upper 64 bits are always zero, because len variable has type uint64, // and tmp is already zeroed at that index, so we can skip updating it. // byteorder.BEPutUint64(padlen[t+0:], 0) byteorder.BEPutUint64([+8:], ) .Write() if .nx != 0 { panic("d.nx != 0") } var [size512]byte byteorder.BEPutUint64([0:], .h[0]) byteorder.BEPutUint64([8:], .h[1]) byteorder.BEPutUint64([16:], .h[2]) byteorder.BEPutUint64([24:], .h[3]) byteorder.BEPutUint64([32:], .h[4]) byteorder.BEPutUint64([40:], .h[5]) if .size != size384 { byteorder.BEPutUint64([48:], .h[6]) byteorder.BEPutUint64([56:], .h[7]) } return }