// 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 sha1 implements the SHA-1 hash algorithm as defined in RFC 3174. // // SHA-1 is cryptographically broken and should not be used for secure // applications.
package sha1 import ( ) func init() { crypto.RegisterHash(crypto.SHA1, New) } // The size of a SHA-1 checksum in bytes. const Size = 20 // The blocksize of SHA-1 in bytes. const BlockSize = 64 const ( chunk = 64 init0 = 0x67452301 init1 = 0xEFCDAB89 init2 = 0x98BADCFE init3 = 0x10325476 init4 = 0xC3D2E1F0 ) // digest represents the partial evaluation of a checksum. type digest struct { h [5]uint32 x [chunk]byte nx int len uint64 } const ( magic = "sha\x01" marshaledSize = len(magic) + 5*4 + chunk + 8 ) func ( *digest) () ([]byte, error) { := make([]byte, 0, marshaledSize) = append(, magic...) = binary.BigEndian.AppendUint32(, .h[0]) = binary.BigEndian.AppendUint32(, .h[1]) = binary.BigEndian.AppendUint32(, .h[2]) = binary.BigEndian.AppendUint32(, .h[3]) = binary.BigEndian.AppendUint32(, .h[4]) = append(, .x[:.nx]...) = [:len()+len(.x)-.nx] // already zero = binary.BigEndian.AppendUint64(, .len) return , nil } func ( *digest) ( []byte) error { if len() < len(magic) || string([:len(magic)]) != magic { return errors.New("crypto/sha1: invalid hash state identifier") } if len() != marshaledSize { return errors.New("crypto/sha1: invalid hash state size") } = [len(magic):] , .h[0] = consumeUint32() , .h[1] = consumeUint32() , .h[2] = consumeUint32() , .h[3] = consumeUint32() , .h[4] = consumeUint32() = [copy(.x[:], ):] , .len = consumeUint64() .nx = int(.len % chunk) return nil } func consumeUint64( []byte) ([]byte, uint64) { _ = [7] := uint64([7]) | uint64([6])<<8 | uint64([5])<<16 | uint64([4])<<24 | uint64([3])<<32 | uint64([2])<<40 | uint64([1])<<48 | uint64([0])<<56 return [8:], } func consumeUint32( []byte) ([]byte, uint32) { _ = [3] := uint32([3]) | uint32([2])<<8 | uint32([1])<<16 | uint32([0])<<24 return [4:], } func ( *digest) () { .h[0] = init0 .h[1] = init1 .h[2] = init2 .h[3] = init3 .h[4] = init4 .nx = 0 .len = 0 } // New returns a new hash.Hash computing the SHA1 checksum. The Hash also // implements [encoding.BinaryMarshaler] and [encoding.BinaryUnmarshaler] to // marshal and unmarshal the internal state of the hash. func () hash.Hash { if boring.Enabled { return boring.NewSHA1() } := new(digest) .Reset() return } func ( *digest) () int { return Size } func ( *digest) () int { return BlockSize } func ( *digest) ( []byte) ( int, error) { boring.Unreachable() = 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 { boring.Unreachable() // Make a copy of d so that caller can keep writing and summing. := * := .checkSum() return append(, [:]...) } func ( *digest) () [Size]byte { := .len // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64. var [64 + 8]byte // padding + length buffer [0] = 0x80 var uint64 if %64 < 56 { = 56 - %64 } else { = 64 + 56 - %64 } // Length in bits. <<= 3 := [:+8] binary.BigEndian.PutUint64([:], ) .Write() if .nx != 0 { panic("d.nx != 0") } var [Size]byte binary.BigEndian.PutUint32([0:], .h[0]) binary.BigEndian.PutUint32([4:], .h[1]) binary.BigEndian.PutUint32([8:], .h[2]) binary.BigEndian.PutUint32([12:], .h[3]) binary.BigEndian.PutUint32([16:], .h[4]) return } // ConstantTimeSum computes the same result of [Sum] but in constant time func ( *digest) ( []byte) []byte { := * := .constSum() return append(, [:]...) } func ( *digest) () [Size]byte { var [8]byte := .len << 3 for := uint(0); < 8; ++ { [] = byte( >> (56 - 8*)) } := byte(.nx) := - 56 // if nx < 56 then the MSB of t is one := byte(int8() >> 7) // mask1b is 0xFF iff one block is enough := byte(0x80) // gets reset to 0x00 once used for := byte(0); < chunk; ++ { := byte(int8(-) >> 7) // 0x00 after the end of data // if we reached the end of the data, replace with 0x80 or 0x00 .x[] = (^ & ) | ( & .x[]) // zero the separator once used &= if >= 56 { // we might have to write the length here if all fit in one block .x[] |= & [-56] } } // compress, and only keep the digest if all fit in one block block(, .x[:]) var [Size]byte for , := range .h { [*4] = & byte(>>24) [*4+1] = & byte(>>16) [*4+2] = & byte(>>8) [*4+3] = & byte() } for := byte(0); < chunk; ++ { // second block, it's always past the end of data, might start with 0x80 if < 56 { .x[] = = 0 } else { .x[] = [-56] } } // compress, and only keep the digest if we actually needed the second block block(, .x[:]) for , := range .h { [*4] |= ^ & byte(>>24) [*4+1] |= ^ & byte(>>16) [*4+2] |= ^ & byte(>>8) [*4+3] |= ^ & byte() } return } // Sum returns the SHA-1 checksum of the data. func ( []byte) [Size]byte { if boring.Enabled { return boring.SHA1() } var digest .Reset() .Write() return .checkSum() }