podman

Форк
0
177 строк · 4.0 Кб
1
// Copyright 2017 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4

5
package blake2b
6

7
import (
8
	"encoding/binary"
9
	"errors"
10
	"io"
11
)
12

13
// XOF defines the interface to hash functions that
14
// support arbitrary-length output.
15
type XOF interface {
16
	// Write absorbs more data into the hash's state. It panics if called
17
	// after Read.
18
	io.Writer
19

20
	// Read reads more output from the hash. It returns io.EOF if the limit
21
	// has been reached.
22
	io.Reader
23

24
	// Clone returns a copy of the XOF in its current state.
25
	Clone() XOF
26

27
	// Reset resets the XOF to its initial state.
28
	Reset()
29
}
30

31
// OutputLengthUnknown can be used as the size argument to NewXOF to indicate
32
// the length of the output is not known in advance.
33
const OutputLengthUnknown = 0
34

35
// magicUnknownOutputLength is a magic value for the output size that indicates
36
// an unknown number of output bytes.
37
const magicUnknownOutputLength = (1 << 32) - 1
38

39
// maxOutputLength is the absolute maximum number of bytes to produce when the
40
// number of output bytes is unknown.
41
const maxOutputLength = (1 << 32) * 64
42

43
// NewXOF creates a new variable-output-length hash. The hash either produce a
44
// known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes
45
// (size == OutputLengthUnknown). In the latter case, an absolute limit of
46
// 256GiB applies.
47
//
48
// A non-nil key turns the hash into a MAC. The key must between
49
// zero and 32 bytes long.
50
func NewXOF(size uint32, key []byte) (XOF, error) {
51
	if len(key) > Size {
52
		return nil, errKeySize
53
	}
54
	if size == magicUnknownOutputLength {
55
		// 2^32-1 indicates an unknown number of bytes and thus isn't a
56
		// valid length.
57
		return nil, errors.New("blake2b: XOF length too large")
58
	}
59
	if size == OutputLengthUnknown {
60
		size = magicUnknownOutputLength
61
	}
62
	x := &xof{
63
		d: digest{
64
			size:   Size,
65
			keyLen: len(key),
66
		},
67
		length: size,
68
	}
69
	copy(x.d.key[:], key)
70
	x.Reset()
71
	return x, nil
72
}
73

74
type xof struct {
75
	d                digest
76
	length           uint32
77
	remaining        uint64
78
	cfg, root, block [Size]byte
79
	offset           int
80
	nodeOffset       uint32
81
	readMode         bool
82
}
83

84
func (x *xof) Write(p []byte) (n int, err error) {
85
	if x.readMode {
86
		panic("blake2b: write to XOF after read")
87
	}
88
	return x.d.Write(p)
89
}
90

91
func (x *xof) Clone() XOF {
92
	clone := *x
93
	return &clone
94
}
95

96
func (x *xof) Reset() {
97
	x.cfg[0] = byte(Size)
98
	binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length
99
	binary.LittleEndian.PutUint32(x.cfg[12:], x.length)    // XOF length
100
	x.cfg[17] = byte(Size)                                 // inner hash size
101

102
	x.d.Reset()
103
	x.d.h[1] ^= uint64(x.length) << 32
104

105
	x.remaining = uint64(x.length)
106
	if x.remaining == magicUnknownOutputLength {
107
		x.remaining = maxOutputLength
108
	}
109
	x.offset, x.nodeOffset = 0, 0
110
	x.readMode = false
111
}
112

113
func (x *xof) Read(p []byte) (n int, err error) {
114
	if !x.readMode {
115
		x.d.finalize(&x.root)
116
		x.readMode = true
117
	}
118

119
	if x.remaining == 0 {
120
		return 0, io.EOF
121
	}
122

123
	n = len(p)
124
	if uint64(n) > x.remaining {
125
		n = int(x.remaining)
126
		p = p[:n]
127
	}
128

129
	if x.offset > 0 {
130
		blockRemaining := Size - x.offset
131
		if n < blockRemaining {
132
			x.offset += copy(p, x.block[x.offset:])
133
			x.remaining -= uint64(n)
134
			return
135
		}
136
		copy(p, x.block[x.offset:])
137
		p = p[blockRemaining:]
138
		x.offset = 0
139
		x.remaining -= uint64(blockRemaining)
140
	}
141

142
	for len(p) >= Size {
143
		binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
144
		x.nodeOffset++
145

146
		x.d.initConfig(&x.cfg)
147
		x.d.Write(x.root[:])
148
		x.d.finalize(&x.block)
149

150
		copy(p, x.block[:])
151
		p = p[Size:]
152
		x.remaining -= uint64(Size)
153
	}
154

155
	if todo := len(p); todo > 0 {
156
		if x.remaining < uint64(Size) {
157
			x.cfg[0] = byte(x.remaining)
158
		}
159
		binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset)
160
		x.nodeOffset++
161

162
		x.d.initConfig(&x.cfg)
163
		x.d.Write(x.root[:])
164
		x.d.finalize(&x.block)
165

166
		x.offset = copy(p, x.block[:todo])
167
		x.remaining -= uint64(todo)
168
	}
169
	return
170
}
171

172
func (d *digest) initConfig(cfg *[Size]byte) {
173
	d.offset, d.c[0], d.c[1] = 0, 0, 0
174
	for i := range d.h {
175
		d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:])
176
	}
177
}
178

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.