// Copyright (c) 2016 Andreas Auernhammer. All rights reserved. // Use of this source code is governed by a license that can be // found in the LICENSE file. // Package skein implements the Skein512 hash function // based on the Threefish tweakable block cipher. // // // Overview // // Skein is a hash function family using the tweakable block cipher // Threefish in Unique Block Iteration (UBI) chaining mode while // leveraging an optional low-overhead argument-system // for flexibility. There are three versions of Skein, each of them // using the corresponding Threefish version: // - Skein256 using Threefish256 and processes 256 bit blocks // - Skein512 using Threefish512 and processes 512 bit blocks // - Skein1024 using Threefish1024 and processes 1024 bit blocks // // Skein can be used as hash function, MAC or KDF and supports personalized, // randomized (salted) and public-key-bound hashing. Furthermore Skein // has some additional features (currently) not implemented here. For // details see http://www.skein-hash.info/ // Skein was submitted to the SHA-3 challenge. // // Skein can produce hash values of any size (up to (2^64 -1) x BlockSize bytes) // not only the common sizes 160, 224, 256, 384 and 512 bit. // // // Security and Recommendations // // All Skein varaiants (as far as known) secure. The Skein authors recommend to use // Skein512 for most applications. Skein256 should be used for small devices // like smartcards. Skein1024 is the ultra-conservative variant providing a level of // security (mostly) not needed. package skein // import "github.com/aead/skein" import "hash" // Config contains the Skein configuration: // - Key for computing MACs // - Personal for personalized hashing // - PublicKey for public-key-bound hashing // - KeyID for key derivation // - Nonce for randomized hashing // All fields are optional and can be nil. type Config struct { Key []byte // Optional: The secret key for MAC Personal []byte // Optional: The personalization for unique hashing PublicKey []byte // Optional: The public key for public-key bound hashing KeyID []byte // Optional: The key id for key derivation Nonce []byte // Optional: The nonce for randomized hashing } // Sum512 computes the 512 bit Skein512 checksum (or MAC if key is set) of msg // and writes it to out. The key is optional and can be nil. func Sum512(out *[64]byte, msg, key []byte) { s := new(hashFunc) if len(key) > 0 { s.initialize(64, &Config{Key: key}) } else { s.hVal = iv512 s.hValCpy = iv512 s.hashsize = BlockSize s.tweak[0] = 0 s.tweak[1] = CfgMessage<<56 | FirstBlock } s.Write(msg) s.finalizeHash() s.output(out, 0) } // Sum384 computes the 384 bit Skein512 checksum (or MAC if key is set) of msg // and writes it to out. The key is optional and can be nil. func Sum384(out *[48]byte, msg, key []byte) { var out512 [64]byte s := new(hashFunc) if len(key) > 0 { s.initialize(48, &Config{Key: key}) } else { s.hVal = iv384 s.hValCpy = iv384 s.hashsize = 48 s.tweak[0] = 0 s.tweak[1] = CfgMessage<<56 | FirstBlock } s.Write(msg) s.finalizeHash() s.output(&out512, 0) copy(out[:], out512[:48]) } // Sum256 computes the 256 bit Skein512 checksum (or MAC if key is set) of msg // and writes it to out. The key is optional and can be nil. func Sum256(out *[32]byte, msg, key []byte) { var out512 [64]byte s := new(hashFunc) if len(key) > 0 { s.initialize(32, &Config{Key: key}) } else { s.hVal = iv256 s.hValCpy = iv256 s.hashsize = 32 s.tweak[0] = 0 s.tweak[1] = CfgMessage<<56 | FirstBlock } s.Write(msg) s.finalizeHash() s.output(&out512, 0) copy(out[:], out512[:32]) } // Sum160 computes the 160 bit Skein512 checksum (or MAC if key is set) of msg // and writes it to out. The key is optional and can be nil. func Sum160(out *[20]byte, msg, key []byte) { var out512 [64]byte s := new(hashFunc) if len(key) > 0 { s.initialize(20, &Config{Key: key}) } else { s.hVal = iv160 s.hValCpy = iv160 s.hashsize = 20 s.tweak[0] = 0 s.tweak[1] = CfgMessage<<56 | FirstBlock } s.Write(msg) s.finalizeHash() s.output(&out512, 0) copy(out[:], out512[:20]) } // Sum returns the Skein512 checksum with the given hash size of msg using the (optional) // conf for configuration. The hashsize must be > 0. func Sum(msg []byte, hashsize int, conf *Config) []byte { s := New(hashsize, conf) s.Write(msg) return s.Sum(nil) } // New512 returns a hash.Hash computing the Skein512 512 bit checksum. // The key is optional and turns the hash into a MAC. func New512(key []byte) hash.Hash { s := new(hashFunc) if len(key) > 0 { s.initialize(BlockSize, &Config{Key: key}) } else { copy(s.hVal[:8], iv512[:]) s.hValCpy = s.hVal s.hashsize = BlockSize s.tweak[0] = 0 s.tweak[1] = CfgMessage<<56 | FirstBlock } return s } // New256 returns a hash.Hash computing the Skein512 256 bit checksum. // The key is optional and turns the hash into a MAC. func New256(key []byte) hash.Hash { s := new(hashFunc) if len(key) > 0 { s.initialize(32, &Config{Key: key}) } else { copy(s.hVal[:8], iv256[:]) s.hValCpy = s.hVal s.hashsize = 32 s.tweak[0] = 0 s.tweak[1] = CfgMessage<<56 | FirstBlock } return s } // New returns a hash.Hash computing the Skein512 checksum with the given hash size. // The conf is optional and configurates the hash.Hash func New(hashsize int, conf *Config) hash.Hash { s := new(hashFunc) s.initialize(hashsize, conf) return s }