mirror of
https://github.com/safing/portbase
synced 2026-05-01 05:09:59 +00:00
133 lines
2.9 KiB
Go
133 lines
2.9 KiB
Go
// Copyright Safing ICS Technologies GmbH. Use of this source code is governed by the AGPL license that can be found in the LICENSE file.
|
|
|
|
package hash
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/Safing/safing-core/formats/varint"
|
|
)
|
|
|
|
type Hash struct {
|
|
Algorithm Algorithm
|
|
Sum []byte
|
|
}
|
|
|
|
func FromBytes(bytes []byte) (*Hash, int, error) {
|
|
hash := &Hash{}
|
|
alg, read, err := varint.Unpack8(bytes)
|
|
hash.Algorithm = Algorithm(alg)
|
|
if err != nil {
|
|
return nil, 0, errors.New(fmt.Sprintf("hash: failed to parse: %s", err))
|
|
}
|
|
// TODO: check if length is correct
|
|
hash.Sum = bytes[read:]
|
|
return hash, 0, nil
|
|
}
|
|
|
|
func (h *Hash) Bytes() []byte {
|
|
return append(varint.Pack8(uint8(h.Algorithm)), h.Sum...)
|
|
}
|
|
|
|
func FromSafe64(s string) (*Hash, error) {
|
|
bytes, err := base64.RawURLEncoding.DecodeString(s)
|
|
if err != nil {
|
|
return nil, errors.New(fmt.Sprintf("hash: failed to parse: %s", err))
|
|
}
|
|
hash, _, err := FromBytes(bytes)
|
|
return hash, err
|
|
}
|
|
|
|
func (h *Hash) Safe64() string {
|
|
return base64.RawURLEncoding.EncodeToString(h.Bytes())
|
|
}
|
|
|
|
func FromHex(s string) (*Hash, error) {
|
|
bytes, err := hex.DecodeString(s)
|
|
if err != nil {
|
|
return nil, errors.New(fmt.Sprintf("hash: failed to parse: %s", err))
|
|
}
|
|
hash, _, err := FromBytes(bytes)
|
|
return hash, err
|
|
}
|
|
|
|
func (h *Hash) Hex() string {
|
|
return hex.EncodeToString(h.Bytes())
|
|
}
|
|
|
|
func (h *Hash) Equal(other *Hash) bool {
|
|
if h.Algorithm != other.Algorithm {
|
|
return false
|
|
}
|
|
return bytes.Equal(h.Sum, other.Sum)
|
|
}
|
|
|
|
func Sum(data []byte, alg Algorithm) *Hash {
|
|
hasher := alg.New()
|
|
hasher.Write(data)
|
|
return &Hash{
|
|
Algorithm: alg,
|
|
Sum: hasher.Sum(nil),
|
|
}
|
|
}
|
|
|
|
func SumString(data string, alg Algorithm) *Hash {
|
|
hasher := alg.New()
|
|
io.WriteString(hasher, data)
|
|
return &Hash{
|
|
Algorithm: alg,
|
|
Sum: hasher.Sum(nil),
|
|
}
|
|
}
|
|
|
|
func SumReader(reader io.Reader, alg Algorithm) (*Hash, error) {
|
|
hasher := alg.New()
|
|
_, err := io.Copy(hasher, reader)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Hash{
|
|
Algorithm: alg,
|
|
Sum: hasher.Sum(nil),
|
|
}, nil
|
|
}
|
|
|
|
func SumAndCompare(data []byte, other Hash) (bool, *Hash) {
|
|
newHash := Sum(data, other.Algorithm)
|
|
return other.Equal(newHash), newHash
|
|
}
|
|
|
|
func SumReaderAndCompare(reader io.Reader, other Hash) (bool, *Hash, error) {
|
|
newHash, err := SumReader(reader, other.Algorithm)
|
|
if err != nil {
|
|
return false, nil, err
|
|
}
|
|
return other.Equal(newHash), newHash, nil
|
|
}
|
|
|
|
func RecommendedAlg(strengthInBits uint16) Algorithm {
|
|
strengthInBytes := uint8(strengthInBits / 8)
|
|
if strengthInBits%8 != 0 {
|
|
strengthInBytes++
|
|
}
|
|
if strengthInBytes == 0 {
|
|
strengthInBytes = uint8(0xFF)
|
|
}
|
|
chosenAlg := orderedByRecommendation[0]
|
|
for _, alg := range orderedByRecommendation {
|
|
strength := alg.SecurityStrength()
|
|
if strength < strengthInBytes {
|
|
break
|
|
}
|
|
chosenAlg = alg
|
|
if strength == strengthInBytes {
|
|
break
|
|
}
|
|
}
|
|
return chosenAlg
|
|
}
|