Move hash package to separate repo

This commit is contained in:
Daniel 2019-09-06 22:37:25 +02:00
parent 9d71d109b2
commit db28b35c99
5 changed files with 0 additions and 440 deletions

View file

@ -1,145 +0,0 @@
package hash
import (
"crypto/sha256"
"crypto/sha512"
"hash"
"golang.org/x/crypto/sha3"
)
type Algorithm uint8
const (
SHA2_224 Algorithm = 1 + iota
SHA2_256
SHA2_512_224
SHA2_512_256
SHA2_384
SHA2_512
SHA3_224
SHA3_256
SHA3_384
SHA3_512
BLAKE2S_256
BLAKE2B_256
BLAKE2B_384
BLAKE2B_512
)
var (
attributes = map[Algorithm][]uint8{
// block size, output size, security strength - in bytes
SHA2_224: []uint8{64, 28, 14},
SHA2_256: []uint8{64, 32, 16},
SHA2_512_224: []uint8{128, 28, 14},
SHA2_512_256: []uint8{128, 32, 16},
SHA2_384: []uint8{128, 48, 24},
SHA2_512: []uint8{128, 64, 32},
SHA3_224: []uint8{144, 28, 14},
SHA3_256: []uint8{136, 32, 16},
SHA3_384: []uint8{104, 48, 24},
SHA3_512: []uint8{72, 64, 32},
BLAKE2S_256: []uint8{64, 32, 16},
BLAKE2B_256: []uint8{128, 32, 16},
BLAKE2B_384: []uint8{128, 48, 24},
BLAKE2B_512: []uint8{128, 64, 32},
}
functions = map[Algorithm]func() hash.Hash{
SHA2_224: sha256.New224,
SHA2_256: sha256.New,
SHA2_512_224: sha512.New512_224,
SHA2_512_256: sha512.New512_256,
SHA2_384: sha512.New384,
SHA2_512: sha512.New,
SHA3_224: sha3.New224,
SHA3_256: sha3.New256,
SHA3_384: sha3.New384,
SHA3_512: sha3.New512,
BLAKE2S_256: NewBlake2s256,
BLAKE2B_256: NewBlake2b256,
BLAKE2B_384: NewBlake2b384,
BLAKE2B_512: NewBlake2b512,
}
// just ordered by strength and establishment, no research conducted yet.
orderedByRecommendation = []Algorithm{
SHA3_512, // {72, 64, 32}
SHA2_512, // {128, 64, 32}
BLAKE2B_512, // {128, 64, 32}
SHA3_384, // {104, 48, 24}
SHA2_384, // {128, 48, 24}
BLAKE2B_384, // {128, 48, 24}
SHA3_256, // {136, 32, 16}
SHA2_512_256, // {128, 32, 16}
SHA2_256, // {64, 32, 16}
BLAKE2B_256, // {128, 32, 16}
BLAKE2S_256, // {64, 32, 16}
SHA3_224, // {144, 28, 14}
SHA2_512_224, // {128, 28, 14}
SHA2_224, // {64, 28, 14}
}
// names
names = map[Algorithm]string{
SHA2_224: "SHA2-224",
SHA2_256: "SHA2-256",
SHA2_512_224: "SHA2-512/224",
SHA2_512_256: "SHA2-512/256",
SHA2_384: "SHA2-384",
SHA2_512: "SHA2-512",
SHA3_224: "SHA3-224",
SHA3_256: "SHA3-256",
SHA3_384: "SHA3-384",
SHA3_512: "SHA3-512",
BLAKE2S_256: "Blake2s-256",
BLAKE2B_256: "Blake2b-256",
BLAKE2B_384: "Blake2b-384",
BLAKE2B_512: "Blake2b-512",
}
)
func (a Algorithm) BlockSize() uint8 {
att, ok := attributes[a]
if !ok {
return 0
}
return att[0]
}
func (a Algorithm) Size() uint8 {
att, ok := attributes[a]
if !ok {
return 0
}
return att[1]
}
func (a Algorithm) SecurityStrength() uint8 {
att, ok := attributes[a]
if !ok {
return 0
}
return att[2]
}
func (a Algorithm) String() string {
return a.Name()
}
func (a Algorithm) Name() string {
name, ok := names[a]
if !ok {
return ""
}
return name
}
func (a Algorithm) New() hash.Hash {
fn, ok := functions[a]
if !ok {
return nil
}
return fn()
}

View file

@ -1,54 +0,0 @@
package hash
import "testing"
func TestAttributes(t *testing.T) {
for alg, att := range attributes {
name, ok := names[alg]
if !ok {
t.Errorf("hash test: name missing for Algorithm ID %d", alg)
}
_ = alg.String()
_, ok = functions[alg]
if !ok {
t.Errorf("hash test: function missing for Algorithm %s", name)
}
hash := alg.New()
if len(att) != 3 {
t.Errorf("hash test: Algorithm %s does not have exactly 3 attributes", name)
}
if hash.BlockSize() != int(alg.BlockSize()) {
t.Errorf("hash test: block size mismatch at Algorithm %s", name)
}
if hash.Size() != int(alg.Size()) {
t.Errorf("hash test: size mismatch at Algorithm %s", name)
}
if alg.Size()/2 != alg.SecurityStrength() {
t.Errorf("hash test: possible strength error at Algorithm %s", name)
}
}
noAlg := Algorithm(255)
if noAlg.String() != "" {
t.Error("hash test: invalid Algorithm error")
}
if noAlg.BlockSize() != 0 {
t.Error("hash test: invalid Algorithm error")
}
if noAlg.Size() != 0 {
t.Error("hash test: invalid Algorithm error")
}
if noAlg.SecurityStrength() != 0 {
t.Error("hash test: invalid Algorithm error")
}
if noAlg.New() != nil {
t.Error("hash test: invalid Algorithm error")
}
}

View file

@ -1,131 +0,0 @@
package hash
import (
"bytes"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io"
"github.com/safing/portbase/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
}

View file

@ -1,82 +0,0 @@
package hash
import (
"bytes"
"testing"
)
var (
testEmpty = []byte("")
testFox = []byte("The quick brown fox jumps over the lazy dog")
)
func testAlgorithm(t *testing.T, alg Algorithm, emptyHex, foxHex string) {
var err error
// testEmpty
hash := Sum(testEmpty, alg)
if err != nil {
t.Errorf("test Sum %s (empty): error occured: %s", alg.String(), err)
}
if hash.Hex()[2:] != emptyHex {
t.Errorf("test Sum %s (empty): hex sum mismatch, expected %s, got %s", alg.String(), emptyHex, hash.Hex())
}
// testFox
hash = Sum(testFox, alg)
if err != nil {
t.Errorf("test Sum %s (fox): error occured: %s", alg.String(), err)
}
if hash.Hex()[2:] != foxHex {
t.Errorf("test Sum %s (fox): hex sum mismatch, expected %s, got %s", alg.String(), foxHex, hash.Hex())
}
// testEmpty
hash = SumString(string(testEmpty), alg)
if err != nil {
t.Errorf("test SumString %s (empty): error occured: %s", alg.String(), err)
}
if hash.Hex()[2:] != emptyHex {
t.Errorf("test SumString %s (empty): hex sum mismatch, expected %s, got %s", alg.String(), emptyHex, hash.Hex())
}
// testFox
hash = SumString(string(testFox), alg)
if err != nil {
t.Errorf("test SumString %s (fox): error occured: %s", alg.String(), err)
}
if hash.Hex()[2:] != foxHex {
t.Errorf("test SumString %s (fox): hex sum mismatch, expected %s, got %s", alg.String(), foxHex, hash.Hex())
}
// testEmpty
hash, err = SumReader(bytes.NewReader(testEmpty), alg)
if err != nil {
t.Errorf("test SumReader %s (empty): error occured: %s", alg.String(), err)
}
if hash.Hex()[2:] != emptyHex {
t.Errorf("test SumReader %s (empty): hex sum mismatch, expected %s, got %s", alg.String(), emptyHex, hash.Hex())
}
// testFox
hash, err = SumReader(bytes.NewReader(testFox), alg)
if err != nil {
t.Errorf("test SumReader %s (fox): error occured: %s", alg.String(), err)
}
if hash.Hex()[2:] != foxHex {
t.Errorf("test SumReader %s (fox): hex sum mismatch, expected %s, got %s", alg.String(), foxHex, hash.Hex())
}
}
func TestHash(t *testing.T) {
testAlgorithm(t, SHA2_512,
"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
"07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6",
)
testAlgorithm(t, SHA3_512,
"a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26",
"01dedd5de4ef14642445ba5f5b97c15e47b9ad931326e4b0727cd94cefc44fff23f07bf543139939b49128caf436dc1bdee54fcb24023a08d9403f9b4bf0d450",
)
}

View file

@ -1,28 +0,0 @@
package hash
import (
"hash"
"golang.org/x/crypto/blake2b"
"golang.org/x/crypto/blake2s"
)
func NewBlake2s256() hash.Hash {
h, _ := blake2s.New256(nil)
return h
}
func NewBlake2b256() hash.Hash {
h, _ := blake2b.New256(nil)
return h
}
func NewBlake2b384() hash.Hash {
h, _ := blake2b.New384(nil)
return h
}
func NewBlake2b512() hash.Hash {
h, _ := blake2b.New512(nil)
return h
}