1*e7b1675dSTing-Kang Chang// Copyright 2020 Google LLC 2*e7b1675dSTing-Kang Chang// 3*e7b1675dSTing-Kang Chang// Licensed under the Apache License, Version 2.0 (the "License"); 4*e7b1675dSTing-Kang Chang// you may not use this file except in compliance with the License. 5*e7b1675dSTing-Kang Chang// You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang// 7*e7b1675dSTing-Kang Chang// http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang// 9*e7b1675dSTing-Kang Chang// Unless required by applicable law or agreed to in writing, software 10*e7b1675dSTing-Kang Chang// distributed under the License is distributed on an "AS IS" BASIS, 11*e7b1675dSTing-Kang Chang// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e7b1675dSTing-Kang Chang// See the License for the specific language governing permissions and 13*e7b1675dSTing-Kang Chang// limitations under the License. 14*e7b1675dSTing-Kang Chang// 15*e7b1675dSTing-Kang Chang//////////////////////////////////////////////////////////////////////////////// 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Chang// Package noncebased provides a reusable streaming AEAD framework. 18*e7b1675dSTing-Kang Chang// 19*e7b1675dSTing-Kang Chang// It tackles the segment handling portions of the nonce based online 20*e7b1675dSTing-Kang Chang// encryption scheme proposed in "Online Authenticated-Encryption and its 21*e7b1675dSTing-Kang Chang// Nonce-Reuse Misuse-Resistance" by Hoang, Reyhanitabar, Rogaway and Vizár 22*e7b1675dSTing-Kang Chang// (https://eprint.iacr.org/2015/189.pdf). 23*e7b1675dSTing-Kang Chang// 24*e7b1675dSTing-Kang Chang// In this scheme, the format of a ciphertext is: 25*e7b1675dSTing-Kang Chang// 26*e7b1675dSTing-Kang Chang// header || segment_0 || segment_1 || ... || segment_k. 27*e7b1675dSTing-Kang Chang// 28*e7b1675dSTing-Kang Chang// The format of header is: 29*e7b1675dSTing-Kang Chang// 30*e7b1675dSTing-Kang Chang// headerLength || salt || nonce_prefix 31*e7b1675dSTing-Kang Chang// 32*e7b1675dSTing-Kang Chang// headerLength is 1 byte which documents the size of the header and can be 33*e7b1675dSTing-Kang Chang// obtained via HeaderLength(). In principle, headerLength is redundant 34*e7b1675dSTing-Kang Chang// information, since the length of the header can be determined from the key 35*e7b1675dSTing-Kang Chang// size. 36*e7b1675dSTing-Kang Chang// 37*e7b1675dSTing-Kang Chang// salt is a salt used in the key derivation. 38*e7b1675dSTing-Kang Chang// 39*e7b1675dSTing-Kang Chang// nonce_prefix is a prefix for all per-segment nonces. 40*e7b1675dSTing-Kang Chang// 41*e7b1675dSTing-Kang Chang// segment_i is the i-th segment of the ciphertext. The size of segment_1 .. 42*e7b1675dSTing-Kang Chang// segment_{k-1} is ciphertextSegmentSize. segment_0 is shorter, so that 43*e7b1675dSTing-Kang Chang// segment_0 plus additional data of size firstCiphertextSegmentOffset (e.g. 44*e7b1675dSTing-Kang Chang// the header) aligns with ciphertextSegmentSize. 45*e7b1675dSTing-Kang Chang// 46*e7b1675dSTing-Kang Chang// The first segment size will be: 47*e7b1675dSTing-Kang Chang// 48*e7b1675dSTing-Kang Chang// ciphertextSegmentSize - HeaderLength() - firstCiphertextSegmentOffset. 49*e7b1675dSTing-Kang Changpackage noncebased 50*e7b1675dSTing-Kang Chang 51*e7b1675dSTing-Kang Changimport ( 52*e7b1675dSTing-Kang Chang "encoding/binary" 53*e7b1675dSTing-Kang Chang "errors" 54*e7b1675dSTing-Kang Chang "io" 55*e7b1675dSTing-Kang Chang "math" 56*e7b1675dSTing-Kang Chang) 57*e7b1675dSTing-Kang Chang 58*e7b1675dSTing-Kang Changvar ( 59*e7b1675dSTing-Kang Chang // ErrNonceSizeTooShort indicates that the specified nonce size isn't large 60*e7b1675dSTing-Kang Chang // enough to hold the nonce prefix, counter and last segment flag. 61*e7b1675dSTing-Kang Chang ErrNonceSizeTooShort = errors.New("nonce size too short") 62*e7b1675dSTing-Kang Chang 63*e7b1675dSTing-Kang Chang // ErrCiphertextSegmentTooShort indicates the the ciphertext segment being 64*e7b1675dSTing-Kang Chang // processed is too short. 65*e7b1675dSTing-Kang Chang ErrCiphertextSegmentTooShort = errors.New("ciphertext segment too short") 66*e7b1675dSTing-Kang Chang 67*e7b1675dSTing-Kang Chang // ErrTooManySegments indicates that the ciphertext has too many segments. 68*e7b1675dSTing-Kang Chang ErrTooManySegments = errors.New("too many segments") 69*e7b1675dSTing-Kang Chang) 70*e7b1675dSTing-Kang Chang 71*e7b1675dSTing-Kang Chang// SegmentEncrypter facilitates implementing various streaming AEAD encryption 72*e7b1675dSTing-Kang Chang// modes. 73*e7b1675dSTing-Kang Changtype SegmentEncrypter interface { 74*e7b1675dSTing-Kang Chang EncryptSegment(segment, nonce []byte) ([]byte, error) 75*e7b1675dSTing-Kang Chang} 76*e7b1675dSTing-Kang Chang 77*e7b1675dSTing-Kang Chang// Writer provides a framework for ingesting plaintext data and 78*e7b1675dSTing-Kang Chang// writing encrypted data to the wrapped io.Writer. The scheme used for 79*e7b1675dSTing-Kang Chang// encrypting segments is specified by providing a SegmentEncrypter 80*e7b1675dSTing-Kang Chang// implementation. 81*e7b1675dSTing-Kang Changtype Writer struct { 82*e7b1675dSTing-Kang Chang w io.Writer 83*e7b1675dSTing-Kang Chang segmentEncrypter SegmentEncrypter 84*e7b1675dSTing-Kang Chang encryptedSegmentCnt uint64 85*e7b1675dSTing-Kang Chang firstCiphertextSegmentOffset int 86*e7b1675dSTing-Kang Chang nonceSize int 87*e7b1675dSTing-Kang Chang noncePrefix []byte 88*e7b1675dSTing-Kang Chang plaintext []byte 89*e7b1675dSTing-Kang Chang plaintextPos int 90*e7b1675dSTing-Kang Chang ciphertext []byte 91*e7b1675dSTing-Kang Chang closed bool 92*e7b1675dSTing-Kang Chang} 93*e7b1675dSTing-Kang Chang 94*e7b1675dSTing-Kang Chang// WriterParams contains the options for instantiating a Writer via NewWriter(). 95*e7b1675dSTing-Kang Changtype WriterParams struct { 96*e7b1675dSTing-Kang Chang // W is the underlying writer being wrapped. 97*e7b1675dSTing-Kang Chang W io.Writer 98*e7b1675dSTing-Kang Chang 99*e7b1675dSTing-Kang Chang // SegmentEncrypter provides a method for encrypting segments. 100*e7b1675dSTing-Kang Chang SegmentEncrypter SegmentEncrypter 101*e7b1675dSTing-Kang Chang 102*e7b1675dSTing-Kang Chang // NonceSize is the length of generated nonces. It must be at least 5 + 103*e7b1675dSTing-Kang Chang // len(NoncePrefix). It can be longer, but longer nonces introduce more 104*e7b1675dSTing-Kang Chang // overhead in the resultant ciphertext. 105*e7b1675dSTing-Kang Chang NonceSize int 106*e7b1675dSTing-Kang Chang 107*e7b1675dSTing-Kang Chang // NoncePrefix is a constant that all nonces throughout the ciphertext will 108*e7b1675dSTing-Kang Chang // start with. It's length must be at least 5 bytes shorter than NonceSize. 109*e7b1675dSTing-Kang Chang NoncePrefix []byte 110*e7b1675dSTing-Kang Chang 111*e7b1675dSTing-Kang Chang // The size of the segments which the plaintext will be split into. 112*e7b1675dSTing-Kang Chang PlaintextSegmentSize int 113*e7b1675dSTing-Kang Chang 114*e7b1675dSTing-Kang Chang // FirstCiphertexSegmentOffset indicates where the ciphertext should begin in 115*e7b1675dSTing-Kang Chang // W. This allows for the existence of overhead in the stream unrelated to 116*e7b1675dSTing-Kang Chang // this encryption scheme. 117*e7b1675dSTing-Kang Chang FirstCiphertextSegmentOffset int 118*e7b1675dSTing-Kang Chang} 119*e7b1675dSTing-Kang Chang 120*e7b1675dSTing-Kang Chang// NewWriter creates a new Writer instance. 121*e7b1675dSTing-Kang Changfunc NewWriter(params WriterParams) (*Writer, error) { 122*e7b1675dSTing-Kang Chang if params.NonceSize-len(params.NoncePrefix) < 5 { 123*e7b1675dSTing-Kang Chang return nil, ErrNonceSizeTooShort 124*e7b1675dSTing-Kang Chang } 125*e7b1675dSTing-Kang Chang return &Writer{ 126*e7b1675dSTing-Kang Chang w: params.W, 127*e7b1675dSTing-Kang Chang segmentEncrypter: params.SegmentEncrypter, 128*e7b1675dSTing-Kang Chang nonceSize: params.NonceSize, 129*e7b1675dSTing-Kang Chang noncePrefix: params.NoncePrefix, 130*e7b1675dSTing-Kang Chang firstCiphertextSegmentOffset: params.FirstCiphertextSegmentOffset, 131*e7b1675dSTing-Kang Chang plaintext: make([]byte, params.PlaintextSegmentSize), 132*e7b1675dSTing-Kang Chang }, nil 133*e7b1675dSTing-Kang Chang} 134*e7b1675dSTing-Kang Chang 135*e7b1675dSTing-Kang Chang// Write encrypts passed data and passes the encrypted data to the underlying writer. 136*e7b1675dSTing-Kang Changfunc (w *Writer) Write(p []byte) (int, error) { 137*e7b1675dSTing-Kang Chang if w.closed { 138*e7b1675dSTing-Kang Chang return 0, errors.New("write on closed writer") 139*e7b1675dSTing-Kang Chang } 140*e7b1675dSTing-Kang Chang 141*e7b1675dSTing-Kang Chang pos := 0 142*e7b1675dSTing-Kang Chang for { 143*e7b1675dSTing-Kang Chang ptLim := len(w.plaintext) 144*e7b1675dSTing-Kang Chang if w.encryptedSegmentCnt == 0 { 145*e7b1675dSTing-Kang Chang ptLim -= w.firstCiphertextSegmentOffset 146*e7b1675dSTing-Kang Chang } 147*e7b1675dSTing-Kang Chang n := copy(w.plaintext[w.plaintextPos:ptLim], p[pos:]) 148*e7b1675dSTing-Kang Chang w.plaintextPos += n 149*e7b1675dSTing-Kang Chang pos += n 150*e7b1675dSTing-Kang Chang if pos == len(p) { 151*e7b1675dSTing-Kang Chang break 152*e7b1675dSTing-Kang Chang } 153*e7b1675dSTing-Kang Chang 154*e7b1675dSTing-Kang Chang nonce, err := generateSegmentNonce(w.nonceSize, w.noncePrefix, w.encryptedSegmentCnt, false) 155*e7b1675dSTing-Kang Chang if err != nil { 156*e7b1675dSTing-Kang Chang return pos, err 157*e7b1675dSTing-Kang Chang } 158*e7b1675dSTing-Kang Chang 159*e7b1675dSTing-Kang Chang w.ciphertext, err = w.segmentEncrypter.EncryptSegment(w.plaintext[:ptLim], nonce) 160*e7b1675dSTing-Kang Chang if err != nil { 161*e7b1675dSTing-Kang Chang return pos, err 162*e7b1675dSTing-Kang Chang } 163*e7b1675dSTing-Kang Chang 164*e7b1675dSTing-Kang Chang if _, err := w.w.Write(w.ciphertext); err != nil { 165*e7b1675dSTing-Kang Chang return pos, err 166*e7b1675dSTing-Kang Chang } 167*e7b1675dSTing-Kang Chang 168*e7b1675dSTing-Kang Chang w.plaintextPos = 0 169*e7b1675dSTing-Kang Chang w.encryptedSegmentCnt++ 170*e7b1675dSTing-Kang Chang } 171*e7b1675dSTing-Kang Chang return pos, nil 172*e7b1675dSTing-Kang Chang} 173*e7b1675dSTing-Kang Chang 174*e7b1675dSTing-Kang Chang// Close encrypts the remaining data, flushes it to the underlying writer and 175*e7b1675dSTing-Kang Chang// closes this writer. 176*e7b1675dSTing-Kang Changfunc (w *Writer) Close() error { 177*e7b1675dSTing-Kang Chang if w.closed { 178*e7b1675dSTing-Kang Chang return nil 179*e7b1675dSTing-Kang Chang } 180*e7b1675dSTing-Kang Chang 181*e7b1675dSTing-Kang Chang nonce, err := generateSegmentNonce(w.nonceSize, w.noncePrefix, w.encryptedSegmentCnt, true) 182*e7b1675dSTing-Kang Chang if err != nil { 183*e7b1675dSTing-Kang Chang return err 184*e7b1675dSTing-Kang Chang } 185*e7b1675dSTing-Kang Chang 186*e7b1675dSTing-Kang Chang w.ciphertext, err = w.segmentEncrypter.EncryptSegment(w.plaintext[:w.plaintextPos], nonce) 187*e7b1675dSTing-Kang Chang if err != nil { 188*e7b1675dSTing-Kang Chang return err 189*e7b1675dSTing-Kang Chang } 190*e7b1675dSTing-Kang Chang 191*e7b1675dSTing-Kang Chang if _, err := w.w.Write(w.ciphertext); err != nil { 192*e7b1675dSTing-Kang Chang return err 193*e7b1675dSTing-Kang Chang } 194*e7b1675dSTing-Kang Chang 195*e7b1675dSTing-Kang Chang w.plaintextPos = 0 196*e7b1675dSTing-Kang Chang w.encryptedSegmentCnt++ 197*e7b1675dSTing-Kang Chang w.closed = true 198*e7b1675dSTing-Kang Chang return nil 199*e7b1675dSTing-Kang Chang} 200*e7b1675dSTing-Kang Chang 201*e7b1675dSTing-Kang Chang// SegmentDecrypter facilitates implementing various streaming AEAD encryption modes. 202*e7b1675dSTing-Kang Changtype SegmentDecrypter interface { 203*e7b1675dSTing-Kang Chang DecryptSegment(segment, nonce []byte) ([]byte, error) 204*e7b1675dSTing-Kang Chang} 205*e7b1675dSTing-Kang Chang 206*e7b1675dSTing-Kang Chang// Reader facilitates the decryption of ciphertexts created using a Writer. 207*e7b1675dSTing-Kang Chang// 208*e7b1675dSTing-Kang Chang// The scheme used for decrypting segments is specified by providing a 209*e7b1675dSTing-Kang Chang// SegmentDecrypter implementation. The implementation must align 210*e7b1675dSTing-Kang Chang// with the SegmentEncrypter used in the Writer. 211*e7b1675dSTing-Kang Changtype Reader struct { 212*e7b1675dSTing-Kang Chang r io.Reader 213*e7b1675dSTing-Kang Chang segmentDecrypter SegmentDecrypter 214*e7b1675dSTing-Kang Chang decryptedSegmentCnt uint64 215*e7b1675dSTing-Kang Chang firstCiphertextSegmentOffset int 216*e7b1675dSTing-Kang Chang nonceSize int 217*e7b1675dSTing-Kang Chang noncePrefix []byte 218*e7b1675dSTing-Kang Chang plaintext []byte 219*e7b1675dSTing-Kang Chang plaintextPos int 220*e7b1675dSTing-Kang Chang ciphertext []byte 221*e7b1675dSTing-Kang Chang ciphertextPos int 222*e7b1675dSTing-Kang Chang} 223*e7b1675dSTing-Kang Chang 224*e7b1675dSTing-Kang Chang// ReaderParams contains the options for instantiating a Reader via NewReader(). 225*e7b1675dSTing-Kang Changtype ReaderParams struct { 226*e7b1675dSTing-Kang Chang // R is the underlying reader being wrapped. 227*e7b1675dSTing-Kang Chang R io.Reader 228*e7b1675dSTing-Kang Chang 229*e7b1675dSTing-Kang Chang // SegmentDecrypter provides a method for decrypting segments. 230*e7b1675dSTing-Kang Chang SegmentDecrypter SegmentDecrypter 231*e7b1675dSTing-Kang Chang 232*e7b1675dSTing-Kang Chang // NonceSize is the length of generated nonces. It must match the NonceSize 233*e7b1675dSTing-Kang Chang // of the Writer used to create the ciphertext. 234*e7b1675dSTing-Kang Chang NonceSize int 235*e7b1675dSTing-Kang Chang 236*e7b1675dSTing-Kang Chang // NoncePrefix is a constant that all nocnes throughout the ciphertext start 237*e7b1675dSTing-Kang Chang // with. It's extracted from the header of the ciphertext. 238*e7b1675dSTing-Kang Chang NoncePrefix []byte 239*e7b1675dSTing-Kang Chang 240*e7b1675dSTing-Kang Chang // The size of the ciphertext segments. 241*e7b1675dSTing-Kang Chang CiphertextSegmentSize int 242*e7b1675dSTing-Kang Chang 243*e7b1675dSTing-Kang Chang // FirstCiphertexSegmentOffset indicates where the ciphertext actually begins 244*e7b1675dSTing-Kang Chang // in R. This allows for the existence of overhead in the stream unrelated to 245*e7b1675dSTing-Kang Chang // this encryption scheme. 246*e7b1675dSTing-Kang Chang FirstCiphertextSegmentOffset int 247*e7b1675dSTing-Kang Chang} 248*e7b1675dSTing-Kang Chang 249*e7b1675dSTing-Kang Chang// NewReader creates a new Reader instance. 250*e7b1675dSTing-Kang Changfunc NewReader(params ReaderParams) (*Reader, error) { 251*e7b1675dSTing-Kang Chang if params.NonceSize-len(params.NoncePrefix) < 5 { 252*e7b1675dSTing-Kang Chang return nil, ErrNonceSizeTooShort 253*e7b1675dSTing-Kang Chang } 254*e7b1675dSTing-Kang Chang return &Reader{ 255*e7b1675dSTing-Kang Chang r: params.R, 256*e7b1675dSTing-Kang Chang segmentDecrypter: params.SegmentDecrypter, 257*e7b1675dSTing-Kang Chang nonceSize: params.NonceSize, 258*e7b1675dSTing-Kang Chang noncePrefix: params.NoncePrefix, 259*e7b1675dSTing-Kang Chang firstCiphertextSegmentOffset: params.FirstCiphertextSegmentOffset, 260*e7b1675dSTing-Kang Chang 261*e7b1675dSTing-Kang Chang // Allocate an extra byte to detect the last segment. 262*e7b1675dSTing-Kang Chang ciphertext: make([]byte, params.CiphertextSegmentSize+1), 263*e7b1675dSTing-Kang Chang }, nil 264*e7b1675dSTing-Kang Chang} 265*e7b1675dSTing-Kang Chang 266*e7b1675dSTing-Kang Chang// Read decrypts data from underlying reader and passes it to p. 267*e7b1675dSTing-Kang Changfunc (r *Reader) Read(p []byte) (int, error) { 268*e7b1675dSTing-Kang Chang if r.plaintextPos < len(r.plaintext) { 269*e7b1675dSTing-Kang Chang n := copy(p, r.plaintext[r.plaintextPos:]) 270*e7b1675dSTing-Kang Chang r.plaintextPos += n 271*e7b1675dSTing-Kang Chang return n, nil 272*e7b1675dSTing-Kang Chang } 273*e7b1675dSTing-Kang Chang 274*e7b1675dSTing-Kang Chang r.plaintextPos = 0 275*e7b1675dSTing-Kang Chang 276*e7b1675dSTing-Kang Chang ctLim := len(r.ciphertext) 277*e7b1675dSTing-Kang Chang if r.decryptedSegmentCnt == 0 { 278*e7b1675dSTing-Kang Chang ctLim -= r.firstCiphertextSegmentOffset 279*e7b1675dSTing-Kang Chang } 280*e7b1675dSTing-Kang Chang n, err := io.ReadFull(r.r, r.ciphertext[r.ciphertextPos:ctLim]) 281*e7b1675dSTing-Kang Chang if err != nil && err != io.ErrUnexpectedEOF { 282*e7b1675dSTing-Kang Chang return 0, err 283*e7b1675dSTing-Kang Chang } 284*e7b1675dSTing-Kang Chang 285*e7b1675dSTing-Kang Chang var ( 286*e7b1675dSTing-Kang Chang lastSegment bool 287*e7b1675dSTing-Kang Chang segment int 288*e7b1675dSTing-Kang Chang ) 289*e7b1675dSTing-Kang Chang if err != nil { 290*e7b1675dSTing-Kang Chang lastSegment = true 291*e7b1675dSTing-Kang Chang segment = r.ciphertextPos + n 292*e7b1675dSTing-Kang Chang } else { 293*e7b1675dSTing-Kang Chang segment = r.ciphertextPos + n - 1 294*e7b1675dSTing-Kang Chang } 295*e7b1675dSTing-Kang Chang 296*e7b1675dSTing-Kang Chang if segment < 0 { 297*e7b1675dSTing-Kang Chang return 0, ErrCiphertextSegmentTooShort 298*e7b1675dSTing-Kang Chang } 299*e7b1675dSTing-Kang Chang 300*e7b1675dSTing-Kang Chang nonce, err := generateSegmentNonce(r.nonceSize, r.noncePrefix, r.decryptedSegmentCnt, lastSegment) 301*e7b1675dSTing-Kang Chang if err != nil { 302*e7b1675dSTing-Kang Chang return 0, err 303*e7b1675dSTing-Kang Chang } 304*e7b1675dSTing-Kang Chang 305*e7b1675dSTing-Kang Chang r.plaintext, err = r.segmentDecrypter.DecryptSegment(r.ciphertext[:segment], nonce) 306*e7b1675dSTing-Kang Chang if err != nil { 307*e7b1675dSTing-Kang Chang return 0, err 308*e7b1675dSTing-Kang Chang } 309*e7b1675dSTing-Kang Chang 310*e7b1675dSTing-Kang Chang // Copy 1 byte remainder to the beginning of ciphertext. 311*e7b1675dSTing-Kang Chang if !lastSegment { 312*e7b1675dSTing-Kang Chang remainderOffset := segment 313*e7b1675dSTing-Kang Chang r.ciphertext[0] = r.ciphertext[remainderOffset] 314*e7b1675dSTing-Kang Chang r.ciphertextPos = 1 315*e7b1675dSTing-Kang Chang } 316*e7b1675dSTing-Kang Chang 317*e7b1675dSTing-Kang Chang r.decryptedSegmentCnt++ 318*e7b1675dSTing-Kang Chang 319*e7b1675dSTing-Kang Chang n = copy(p, r.plaintext) 320*e7b1675dSTing-Kang Chang r.plaintextPos = n 321*e7b1675dSTing-Kang Chang return n, nil 322*e7b1675dSTing-Kang Chang} 323*e7b1675dSTing-Kang Chang 324*e7b1675dSTing-Kang Chang// generateSegmentNonce returns a nonce for a segment. 325*e7b1675dSTing-Kang Chang// 326*e7b1675dSTing-Kang Chang// The format of the nonce is: 327*e7b1675dSTing-Kang Chang// 328*e7b1675dSTing-Kang Chang// nonce_prefix || ctr || last_block. 329*e7b1675dSTing-Kang Chang// 330*e7b1675dSTing-Kang Chang// nonce_prefix is a constant prefix used throughout the whole ciphertext. 331*e7b1675dSTing-Kang Chang// 332*e7b1675dSTing-Kang Chang// The ctr is a 32 bit counter. 333*e7b1675dSTing-Kang Chang// 334*e7b1675dSTing-Kang Chang// last_block is 1 byte which is set to 1 for the last segment and 0 335*e7b1675dSTing-Kang Chang// otherwise. 336*e7b1675dSTing-Kang Changfunc generateSegmentNonce(size int, prefix []byte, segmentNum uint64, last bool) ([]byte, error) { 337*e7b1675dSTing-Kang Chang if segmentNum >= math.MaxUint32 { 338*e7b1675dSTing-Kang Chang return nil, ErrTooManySegments 339*e7b1675dSTing-Kang Chang } 340*e7b1675dSTing-Kang Chang 341*e7b1675dSTing-Kang Chang nonce := make([]byte, size) 342*e7b1675dSTing-Kang Chang copy(nonce, prefix) 343*e7b1675dSTing-Kang Chang offset := len(prefix) 344*e7b1675dSTing-Kang Chang binary.BigEndian.PutUint32(nonce[offset:], uint32(segmentNum)) 345*e7b1675dSTing-Kang Chang offset += 4 346*e7b1675dSTing-Kang Chang if last { 347*e7b1675dSTing-Kang Chang nonce[offset] = 1 348*e7b1675dSTing-Kang Chang } 349*e7b1675dSTing-Kang Chang return nonce, nil 350*e7b1675dSTing-Kang Chang} 351