gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/sm4soft/padding/pkcs7_padding_io.go (about)

     1  // Copyright (c) 2022 zhaochun
     2  // core-gm is licensed under Mulan PSL v2.
     3  // You can use this software according to the terms and conditions of the Mulan PSL v2.
     4  // You may obtain a copy of Mulan PSL v2 at:
     5  //          http://license.coscl.org.cn/MulanPSL2
     6  // THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
     7  // See the Mulan PSL v2 for more details.
     8  
     9  /*
    10  sm4soft 是sm4的纯软实现,基于tjfoc国密算法库`tjfoc/gmsm`做了少量修改。
    11  对应版权声明: thrid_licenses/github.com/tjfoc/gmsm/版权声明
    12  */
    13  
    14  package padding
    15  
    16  import (
    17  	"bytes"
    18  	"errors"
    19  	"io"
    20  )
    21  
    22  // PKCS7PaddingReader 符合PKCS#7填充的输入流
    23  type PKCS7PaddingReader struct {
    24  	fIn       io.Reader
    25  	padding   io.Reader
    26  	blockSize int
    27  	readed    int64
    28  	eof       bool
    29  	eop       bool
    30  }
    31  
    32  // NewPKCS7PaddingReader 创建PKCS7填充Reader
    33  // in: 输入流
    34  // blockSize: 分块大小
    35  func NewPKCS7PaddingReader(in io.Reader, blockSize int) *PKCS7PaddingReader {
    36  	return &PKCS7PaddingReader{
    37  		fIn:       in,
    38  		padding:   nil,
    39  		eof:       false,
    40  		eop:       false,
    41  		blockSize: blockSize,
    42  	}
    43  }
    44  
    45  func (p *PKCS7PaddingReader) Read(buf []byte) (int, error) {
    46  	/*
    47  		- 读取文件
    48  			- 文件长度充足, 直接返还
    49  			- 不充足
    50  		- 读取到 n 字节, 剩余需要 m 字节
    51  		- 从 padding 中读取然后追加到 buff
    52  			- EOF  直接返回, 整个Reader end
    53  	*/
    54  	// 都读取完了
    55  	if p.eof && p.eop {
    56  		return 0, io.EOF
    57  	}
    58  
    59  	var n, off = 0, 0
    60  	var err error
    61  	if !p.eof {
    62  		// 读取文件
    63  		n, err = p.fIn.Read(buf)
    64  		if err != nil && !errors.Is(err, io.EOF) {
    65  			// 错误返回
    66  			return 0, err
    67  		}
    68  		p.readed += int64(n)
    69  		if errors.Is(err, io.EOF) {
    70  			// 标志文件结束
    71  			p.eof = true
    72  		}
    73  		if n == len(buf) {
    74  			// 长度足够直接返回
    75  			return n, nil
    76  		}
    77  		// 文件长度已经不足,根据已经已经读取的长度创建Padding
    78  		p.newPadding()
    79  		// 长度不足向Padding中索要
    80  		off = n
    81  	}
    82  
    83  	if !p.eop {
    84  		// 读取流
    85  		var n2 = 0
    86  		n2, err = p.padding.Read(buf[off:])
    87  		n += n2
    88  		if errors.Is(err, io.EOF) {
    89  			p.eop = true
    90  		}
    91  	}
    92  	return n, err
    93  }
    94  
    95  // 新建Padding
    96  func (p *PKCS7PaddingReader) newPadding() {
    97  	if p.padding != nil {
    98  		return
    99  	}
   100  	size := p.blockSize - int(p.readed%int64(p.blockSize))
   101  	padding := bytes.Repeat([]byte{byte(size)}, size)
   102  	p.padding = bytes.NewReader(padding)
   103  }
   104  
   105  // PKCS7PaddingWriter 符合PKCS#7去除的输入流,最后一个 分组根据会根据填充情况去除填充。
   106  type PKCS7PaddingWriter struct {
   107  	cache     *bytes.Buffer // 缓存区
   108  	swap      []byte        // 临时交换区
   109  	out       io.Writer     // 输出位置
   110  	blockSize int           // 分块大小
   111  }
   112  
   113  // NewPKCS7PaddingWriter PKCS#7 填充Writer 可以去除填充
   114  func NewPKCS7PaddingWriter(out io.Writer, blockSize int) *PKCS7PaddingWriter {
   115  	cache := bytes.NewBuffer(make([]byte, 0, 1024))
   116  	swap := make([]byte, 1024)
   117  	return &PKCS7PaddingWriter{out: out, blockSize: blockSize, cache: cache, swap: swap}
   118  }
   119  
   120  // Write 保留一个填充大小的数据,其余全部写入输出中
   121  func (p *PKCS7PaddingWriter) Write(buff []byte) (n int, err error) {
   122  	// 写入缓存
   123  	n, err = p.cache.Write(buff)
   124  	if err != nil {
   125  		return 0, err
   126  	}
   127  	if p.cache.Len() > p.blockSize {
   128  		// 把超过一个分组长度的部分读取出来,写入到实际的out中
   129  		size := p.cache.Len() - p.blockSize
   130  		_, _ = p.cache.Read(p.swap[:size])
   131  		_, err = p.out.Write(p.swap[:size])
   132  		if err != nil {
   133  			return 0, err
   134  		}
   135  	}
   136  	return n, err
   137  
   138  }
   139  
   140  // Final 去除填充写入最后一个分块
   141  func (p *PKCS7PaddingWriter) Final() error {
   142  	// 在Write 之后 cache 只会保留一个Block长度数据
   143  	b := p.cache.Bytes()
   144  	length := len(b)
   145  	if length != p.blockSize {
   146  		return errors.New("非法的PKCS7填充")
   147  	}
   148  	if length == 0 {
   149  		return nil
   150  	}
   151  	unpadding := int(b[length-1])
   152  	if unpadding > p.blockSize || unpadding == 0 {
   153  		return errors.New("非法的PKCS7填充")
   154  	}
   155  	_, err := p.out.Write(b[:(length - unpadding)])
   156  	return err
   157  }