github.com/readium/readium-lcp-server@v0.0.0-20240101192032-6e95190e99f1/crypto/pad.go (about) 1 // Copyright (c) 2016 Readium Foundation 2 // 3 // Redistribution and use in source and binary forms, with or without modification, 4 // are permitted provided that the following conditions are met: 5 // 6 // 1. Redistributions of source code must retain the above copyright notice, this 7 // list of conditions and the following disclaimer. 8 // 2. Redistributions in binary form must reproduce the above copyright notice, 9 // this list of conditions and the following disclaimer in the documentation and/or 10 // other materials provided with the distribution. 11 // 3. Neither the name of the organization nor the names of its contributors may be 12 // used to endorse or promote products derived from this software without specific 13 // prior written permission 14 // 15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 19 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 26 package crypto 27 28 import ( 29 "io" 30 "math/rand" 31 "time" 32 ) 33 34 type paddedReader struct { 35 io.Reader 36 size byte 37 count byte 38 left byte 39 done bool 40 insertPadLengthAll bool 41 } 42 43 func (r *paddedReader) Read(buf []byte) (int, error) { 44 // we're still reading stuff 45 if !r.done { 46 n, err := r.Reader.Read(buf) 47 48 if err != nil && err != io.EOF { 49 return n, err 50 } 51 52 //update counter 53 r.count = byte((n + int(r.count)) % int(r.size)) 54 55 // try to read more 56 var nn int 57 for n < len(buf) && err == nil { 58 nn, err = r.Reader.Read(buf[n:]) 59 n += nn 60 r.count = byte((nn + int(r.count)) % int(r.size)) 61 } 62 63 if err == io.EOF { 64 r.done = true 65 r.left = r.size - r.count 66 r.count = r.left 67 paddingAdded, err := r.pad(buf[n:]) 68 return n + paddingAdded, err 69 } 70 71 return n, err 72 } 73 74 return r.pad(buf) 75 } 76 77 func (r *paddedReader) pad(buf []byte) (i int, err error) { 78 capacity := cap(buf) 79 80 src := rand.New(rand.NewSource(time.Now().UnixNano())) 81 82 for i = 0; capacity > 0 && r.left > 0; i++ { 83 84 if (r.insertPadLengthAll) { 85 buf[i] = r.count 86 } else { 87 if r.left == 1 { //capacity == 1 && 88 buf[i] = r.count 89 } else { 90 buf[i] = byte(src.Intn(254) + 1) 91 } 92 } 93 94 capacity-- 95 r.left-- 96 } 97 98 if r.left == 0 { 99 err = io.EOF 100 } 101 102 return 103 } 104 105 106 // insertPadLengthAll = true means PKCS#7 (padding length inserted in each padding slot), 107 // otherwise false means padding length inserted only in the last slot (the rest is random bytes) 108 func PaddedReader(r io.Reader, blockSize byte, insertPadLengthAll bool) io.Reader { 109 return &paddedReader{Reader: r, size: blockSize, count: 0, left: 0, done: false, insertPadLengthAll: insertPadLengthAll} 110 }