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  }