v / vlib / crypto / blake2b / blake2b.v
377 lines · 316 sloc · 10.46 KB · 9cc40aecc7b722385cdbe731026866a2432dc774
Raw
1// Copyright (c) 2023 Kim Shrier. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4// Package blake2b implements the Blake2b 512, 384, 256, and
5// 160 bit hash algorithms
6// as defined in IETF RFC 7693.
7// Based off: https://datatracker.ietf.org/doc/html/rfc7693
8// Last updated: November 2015
9module blake2b
10
11import encoding.binary
12import math.unsigned
13
14// size160 is the size, in bytes, of a Blake2b 160 checksum.
15pub const size160 = 20
16// size256 is the size, in bytes, of a Blake2b 256 checksum.
17pub const size256 = 32
18// size384 is the size, in bytes, of a Blake2b 384 checksum.
19pub const size384 = 48
20// size512 is the size, in bytes, of a Blake2b 512 checksum.
21pub const size512 = 64
22
23// block_size is the block size, in bytes, of the Blake2b hash functions.
24pub const block_size = 128
25
26// G rotation constants
27const r1 = 32
28const r2 = 24
29const r3 = 16
30const r4 = 63
31
32// negative G rotation constants so we can rotate right.
33const nr1 = -1 * r1
34const nr2 = -1 * r2
35const nr3 = -1 * r3
36const nr4 = -1 * r4
37
38// initialization vector
39const iv = [
40 u64(0x6a09e667f3bcc908),
41 u64(0xbb67ae8584caa73b),
42 u64(0x3c6ef372fe94f82b),
43 u64(0xa54ff53a5f1d36f1),
44 u64(0x510e527fade682d1),
45 u64(0x9b05688c2b3e6c1f),
46 u64(0x1f83d9abfb41bd6b),
47 u64(0x5be0cd19137e2179),
48]
49
50// message word schedule permutations
51const sigma = [
52 [u8(0), 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]!,
53 [u8(14), 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]!,
54 [u8(11), 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4]!,
55 [u8(7), 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8]!,
56 [u8(9), 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13]!,
57 [u8(2), 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9]!,
58 [u8(12), 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11]!,
59 [u8(13), 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10]!,
60 [u8(6), 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5]!,
61 [u8(10), 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0]!,
62]!
63
64struct Digest {
65 hash_size u8
66mut:
67 input_buffer []u8
68 h []u64
69 m [16]u64
70 t unsigned.Uint128
71}
72
73// string makes a formatted string representation of a Digest structure
74pub fn (d Digest) str() string {
75 return 'blake2b.Digest{\n hash_size: ${d.hash_size}\n input_buffer: ${d.input_buffer}\n input_buffer.len: ${d.input_buffer.len}\n h: [0x${d.h[0]:016x}, 0x${d.h[1]:016x}, 0x${d.h[2]:016x}, 0x${d.h[3]:016x},\n 0x${d.h[4]:016x}, 0x${d.h[5]:016x}, 0x${d.h[6]:016x}, 0x${d.h[7]:016x}]\n m: [0x${d.m[0]:016x}, 0x${d.m[1]:016x}, 0x${d.m[2]:016x}, 0x${d.m[3]:016x},\n 0x${d.m[4]:016x}, 0x${d.m[5]:016x}, 0x${d.m[6]:016x}, 0x${d.m[7]:016x},\n 0x${d.m[8]:016x}, 0x${d.m[9]:016x}, 0x${d.m[10]:016x}, 0x${d.m[11]:016x},\n 0x${d.m[12]:016x}, 0x${d.m[13]:016x}, 0x${d.m[14]:016x}, 0x${d.m[15]:016x}]\n t: ${d.t}\n}'
76}
77
78// new512 initializes the digest structure for a Blake2b 512 bit hash
79pub fn new512() !&Digest {
80 return new_digest(size512, []u8{})!
81}
82
83// new_pmac512 initializes the digest structure for a Blake2b 512 bit prefix MAC
84pub fn new_pmac512(key []u8) !&Digest {
85 return new_digest(size512, key)!
86}
87
88// new384 initializes the digest structure for a Blake2b 384 bit hash
89pub fn new384() !&Digest {
90 return new_digest(size384, []u8{})!
91}
92
93// new_pmac384 initializes the digest structure for a Blake2b 384 bit prefix MAC
94pub fn new_pmac384(key []u8) !&Digest {
95 return new_digest(size384, key)!
96}
97
98// new256 initializes the digest structure for a Blake2b 256 bit hash
99pub fn new256() !&Digest {
100 return new_digest(size256, []u8{})!
101}
102
103// new_pmac256 initializes the digest structure for a Blake2b 256 bit prefix MAC
104pub fn new_pmac256(key []u8) !&Digest {
105 return new_digest(size256, key)!
106}
107
108// new160 initializes the digest structure for a Blake2b 160 bit hash
109pub fn new160() !&Digest {
110 return new_digest(size160, []u8{})!
111}
112
113// new_pmac160 initializes the digest structure for a Blake2b 160 bit prefix MAC
114pub fn new_pmac160(key []u8) !&Digest {
115 return new_digest(size160, key)!
116}
117
118struct HashSizeError {
119 Error
120 size u8
121}
122
123fn (err HashSizeError) msg() string {
124 return 'Hash size ${err.size} must be between 1 and ${size512}'
125}
126
127struct KeySizeError {
128 Error
129 size i32
130}
131
132fn (err KeySizeError) msg() string {
133 return 'Key size ${err.size} must be between 0 and ${size512}'
134}
135
136struct InputBufferSizeError {
137 Error
138 size i32
139}
140
141fn (err InputBufferSizeError) msg() string {
142 return 'The input buffer size ${err.size} .must be between 0 and ${block_size}'
143}
144
145// new_digest creates an initialized digest structure based on
146// the hash size and whether or not you specify a MAC key.
147//
148// hash_size - the number of bytes in the generated hash.
149// Legal values are between 1 and 64.
150//
151// key - key used for generating a prefix MAC. A zero length
152// key is used for just generating a hash. A key of 1 to
153// 64 bytes can be used for generating a prefix MAC.
154pub fn new_digest(hash_size u8, key []u8) !&Digest {
155 if hash_size < 1 || hash_size > size512 {
156 return HashSizeError{
157 size: hash_size
158 }
159 }
160
161 if key.len < 0 || key.len > size512 {
162 return KeySizeError{
163 size: i32(key.len)
164 }
165 }
166
167 mut d := Digest{
168 h: iv.clone()
169 t: unsigned.uint128_zero
170 hash_size: hash_size
171 }
172
173 if key.len > 0 {
174 p0 := 0x0000000001010000 ^ u64(key.len) << 8 ^ u64(hash_size)
175
176 d.h[0] ^= p0
177
178 d.input_buffer.clear()
179 d.input_buffer << key
180
181 pad_length := block_size - key.len
182 for _ in 0 .. pad_length {
183 d.input_buffer << 0
184 }
185 } else {
186 p0 := 0x0000000001010000 ^ u64(hash_size)
187
188 d.h[0] ^= p0
189 }
190
191 return &d
192}
193
194// The intent is to only use this method
195// when the input buffer is full or when
196// the last data to be hashed is in the
197// input buffer.
198//
199// If the input buffer does not contain enough
200// data to fill all the message blocks, the
201// input buffer is padded with 0 bytes until
202// it is full prior to moving the data into
203// the message blocks.
204//
205// The input buffer is emptied.
206//
207// The total byte count is incremented by the
208// number of bytes in the input buffer.
209fn (mut d Digest) move_input_to_message_blocks() ! {
210 // the number of bytes in the input buffer
211 // should never exceed the block size.
212 if d.input_buffer.len < 0 || d.input_buffer.len > block_size {
213 return InputBufferSizeError{
214 size: i32(d.input_buffer.len)
215 }
216 }
217
218 // keep the hashed data length up to date
219 d.t = d.t.add_64(u64(d.input_buffer.len))
220
221 // pad the input buffer if necessary
222 if d.input_buffer.len < block_size {
223 pad_length := block_size - d.input_buffer.len
224
225 for _ in 0 .. pad_length {
226 d.input_buffer << 0
227 }
228 }
229
230 // treat the input bytes as little endian u64 values
231 for i in 0 .. 16 {
232 d.m[i] = binary.little_endian_u64_at(d.input_buffer, i * 8)
233 }
234
235 // empty the input buffer
236 d.input_buffer.clear()
237
238 return
239}
240
241// write adds bytes to the hash
242pub fn (mut d Digest) write(data []u8) ! {
243 // if no data is being added to the hash,
244 // just return
245 if data.len == 0 {
246 return
247 }
248
249 // if the input buffer is already full,
250 // process the existing input bytes first.
251 // this is not the final input.
252 if d.input_buffer.len >= block_size {
253 d.move_input_to_message_blocks()!
254 d.f(false)
255 }
256
257 // add data to the input buffer until you
258 // run out of space in the input buffer or
259 // run out of data, whichever comes first.
260 empty_space := block_size - d.input_buffer.len
261 mut remaining_data := unsafe { data[..] }
262
263 if empty_space >= data.len {
264 // ran out of data first
265 // just add it to the input buffer and return
266 d.input_buffer << data
267 return
268 } else {
269 // ran out of input buffer space first
270 // fill it up and process it.
271 d.input_buffer << data[..empty_space]
272 remaining_data = unsafe { remaining_data[empty_space..] }
273
274 d.move_input_to_message_blocks()!
275 d.f(false)
276 }
277
278 // process the data in block size amounts until
279 // all the data has been processed
280 for remaining_data.len > 0 {
281 if block_size >= remaining_data.len {
282 // running out of data
283 // just add it to the input buffer and return
284 d.input_buffer << remaining_data
285 return
286 }
287
288 // add block size bytes to the input buffer
289 // and process it
290 d.input_buffer << remaining_data[..block_size]
291 remaining_data = unsafe { remaining_data[block_size..] }
292
293 d.move_input_to_message_blocks()!
294 d.f(false)
295 }
296
297 return
298}
299
300fn (mut d Digest) checksum_internal() ![]u8 {
301 // process the last input bytes
302 d.move_input_to_message_blocks()!
303 d.f(true)
304
305 // get the hash into the proper byte order
306 mut hash_bytes := []u8{}
307
308 for hash in d.h {
309 mut h_bytes := []u8{len: 8, cap: 8}
310 binary.little_endian_put_u64(mut h_bytes, hash)
311 hash_bytes << h_bytes
312 }
313
314 // return the appropriate number of hash bytes
315 return hash_bytes[..d.hash_size]
316}
317
318// checksum finalizes the hash and returns the generated bytes.
319pub fn (mut d Digest) checksum() []u8 {
320 return d.checksum_internal() or { panic(err) }
321}
322
323// sum512 returns the Blake2b 512 bit checksum of the data.
324pub fn sum512(data []u8) []u8 {
325 mut d := new512() or { panic(err) }
326 d.write(data) or { panic(err) }
327 return d.checksum_internal() or { panic(err) }
328}
329
330// sum384 returns the Blake2b 384 bit checksum of the data.
331pub fn sum384(data []u8) []u8 {
332 mut d := new384() or { panic(err) }
333 d.write(data) or { panic(err) }
334 return d.checksum_internal() or { panic(err) }
335}
336
337// sum256 returns the Blake2b 256 bit checksum of the data.
338pub fn sum256(data []u8) []u8 {
339 mut d := new256() or { panic(err) }
340 d.write(data) or { panic(err) }
341 return d.checksum_internal() or { panic(err) }
342}
343
344// sum160 returns the Blake2b 160 bit checksum of the data.
345pub fn sum160(data []u8) []u8 {
346 mut d := new160() or { panic(err) }
347 d.write(data) or { panic(err) }
348 return d.checksum_internal() or { panic(err) }
349}
350
351// pmac512 returns the Blake2b 512 bit prefix MAC of the data.
352pub fn pmac512(data []u8, key []u8) []u8 {
353 mut d := new_pmac512(key) or { panic(err) }
354 d.write(data) or { panic(err) }
355 return d.checksum_internal() or { panic(err) }
356}
357
358// pmac384 returns the Blake2b 384 bit prefix MAC of the data.
359pub fn pmac384(data []u8, key []u8) []u8 {
360 mut d := new_pmac384(key) or { panic(err) }
361 d.write(data) or { panic(err) }
362 return d.checksum_internal() or { panic(err) }
363}
364
365// pmac256 returns the Blake2b 256 bit prefix MAC of the data.
366pub fn pmac256(data []u8, key []u8) []u8 {
367 mut d := new_pmac256(key) or { panic(err) }
368 d.write(data) or { panic(err) }
369 return d.checksum_internal() or { panic(err) }
370}
371
372// pmac160 returns the Blake2b 160 bit prefix MAC of the data.
373pub fn pmac160(data []u8, key []u8) []u8 {
374 mut d := new_pmac160(key) or { panic(err) }
375 d.write(data) or { panic(err) }
376 return d.checksum_internal() or { panic(err) }
377}
378