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 }