github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/kbfscrypto/pad.go (about) 1 // Copyright 2019 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package kbfscrypto 6 7 import ( 8 "encoding/binary" 9 "io" 10 11 "github.com/pkg/errors" 12 ) 13 14 const ( 15 padPrefixSize = 4 16 minBlockSize = 256 17 ) 18 19 // powerOfTwoEqualOrGreater returns smallest power of 2 greater than or equal 20 // to the input n. 21 // https://en.wikipedia.org/wiki/Power_of_two#Algorithm_to_round_up_to_power_of_two 22 func powerOfTwoEqualOrGreater(n int) int { 23 if n <= minBlockSize { 24 return minBlockSize 25 } 26 if n&(n-1) == 0 { 27 // if n is already power of 2, return it 28 return n 29 } 30 31 n-- 32 n |= (n >> 1) 33 n |= (n >> 2) 34 n |= (n >> 4) 35 n |= (n >> 8) 36 n |= (n >> 16) 37 n |= (n >> 16 >> 16) // make it work with 64 bit int; no effect on 32bit. 38 n++ 39 40 return n 41 } 42 43 // PadBlock adds zero padding to an encoded block. 44 func PadBlock(block []byte) ([]byte, error) { 45 totalLen := powerOfTwoEqualOrGreater(len(block)) 46 47 buf := make([]byte, padPrefixSize+totalLen) 48 binary.LittleEndian.PutUint32(buf, uint32(len(block))) 49 50 copy(buf[padPrefixSize:], block) 51 return buf, nil 52 } 53 54 // DepadBlock extracts the actual block data from a padded block. 55 func DepadBlock(paddedBlock []byte) ([]byte, error) { 56 totalLen := len(paddedBlock) 57 if totalLen < padPrefixSize { 58 return nil, errors.WithStack(io.ErrUnexpectedEOF) 59 } 60 61 blockLen := binary.LittleEndian.Uint32(paddedBlock) 62 blockEndPos := int(blockLen + padPrefixSize) 63 64 if totalLen < blockEndPos { 65 return nil, errors.WithStack( 66 PaddedBlockReadError{ 67 ActualLen: totalLen, 68 ExpectedLen: blockEndPos, 69 }) 70 } 71 return paddedBlock[padPrefixSize:blockEndPos], nil 72 }