github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/s3crypto/pkcs7_padder.go (about)

     1  package s3crypto
     2  
     3  // Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
     4  //
     5  // Portions Licensed under the MIT License. Copyright (c) 2016 Carl Jackson
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/subtle"
    10  
    11  	"github.com/aavshr/aws-sdk-go/aws/awserr"
    12  )
    13  
    14  const (
    15  	pkcs7MaxPaddingSize = 255
    16  )
    17  
    18  type pkcs7Padder struct {
    19  	blockSize int
    20  }
    21  
    22  // NewPKCS7Padder follows the RFC 2315: https://www.ietf.org/rfc/rfc2315.txt
    23  // PKCS7 padding is subject to side-channel attacks and timing attacks. For
    24  // the most secure data, use an authenticated crypto algorithm.
    25  func NewPKCS7Padder(blockSize int) Padder {
    26  	return pkcs7Padder{blockSize}
    27  }
    28  
    29  var errPKCS7Padding = awserr.New("InvalidPadding", "invalid padding", nil)
    30  
    31  // Pad will pad the data relative to how many bytes have been read.
    32  // Pad follows the PKCS7 standard.
    33  func (padder pkcs7Padder) Pad(buf []byte, n int) ([]byte, error) {
    34  	if padder.blockSize < 1 || padder.blockSize > pkcs7MaxPaddingSize {
    35  		return nil, awserr.New("InvalidBlockSize", "block size must be between 1 and 255", nil)
    36  	}
    37  	size := padder.blockSize - (n % padder.blockSize)
    38  	pad := bytes.Repeat([]byte{byte(size)}, size)
    39  	buf = append(buf, pad...)
    40  	return buf, nil
    41  }
    42  
    43  // Unpad will unpad the correct amount of bytes based off
    44  // of the PKCS7 standard
    45  func (padder pkcs7Padder) Unpad(buf []byte) ([]byte, error) {
    46  	if len(buf) == 0 {
    47  		return nil, errPKCS7Padding
    48  	}
    49  
    50  	// Here be dragons. We're attempting to check the padding in constant
    51  	// time. The only piece of information here which is public is len(buf).
    52  	// This code is modeled loosely after tls1_cbc_remove_padding from
    53  	// OpenSSL.
    54  	padLen := buf[len(buf)-1]
    55  	toCheck := pkcs7MaxPaddingSize
    56  	good := 1
    57  	if toCheck > len(buf) {
    58  		toCheck = len(buf)
    59  	}
    60  	for i := 0; i < toCheck; i++ {
    61  		b := buf[len(buf)-1-i]
    62  
    63  		outOfRange := subtle.ConstantTimeLessOrEq(int(padLen), i)
    64  		equal := subtle.ConstantTimeByteEq(padLen, b)
    65  		good &= subtle.ConstantTimeSelect(outOfRange, 1, equal)
    66  	}
    67  
    68  	good &= subtle.ConstantTimeLessOrEq(1, int(padLen))
    69  	good &= subtle.ConstantTimeLessOrEq(int(padLen), len(buf))
    70  
    71  	if good != 1 {
    72  		return nil, errPKCS7Padding
    73  	}
    74  
    75  	return buf[:len(buf)-int(padLen)], nil
    76  }
    77  
    78  func (padder pkcs7Padder) Name() string {
    79  	return "PKCS7Padding"
    80  }