-
Notifications
You must be signed in to change notification settings - Fork 5
/
skein.go
198 lines (168 loc) · 5.34 KB
/
skein.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// 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 "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
}