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

     1  package s3crypto
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	"io"
     8  )
     9  
    10  // AESCBC is a symmetric crypto algorithm. This algorithm
    11  // requires a padder due to CBC needing to be of the same block
    12  // size. AES CBC is vulnerable to Padding Oracle attacks and
    13  // so should be avoided when possible.
    14  type aesCBC struct {
    15  	encrypter cipher.BlockMode
    16  	decrypter cipher.BlockMode
    17  	padder    Padder
    18  }
    19  
    20  // newAESCBC creates a new AES CBC cipher. Expects keys to be of
    21  // the correct size.
    22  func newAESCBC(cd CipherData, padder Padder) (Cipher, error) {
    23  	block, err := aes.NewCipher(cd.Key)
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  
    28  	encrypter := cipher.NewCBCEncrypter(block, cd.IV)
    29  	decrypter := cipher.NewCBCDecrypter(block, cd.IV)
    30  
    31  	return &aesCBC{encrypter, decrypter, padder}, nil
    32  }
    33  
    34  // Encrypt will encrypt the data using AES CBC by returning
    35  // an io.Reader. The io.Reader will encrypt the data as Read
    36  // is called.
    37  func (c *aesCBC) Encrypt(src io.Reader) io.Reader {
    38  	reader := &cbcEncryptReader{
    39  		encrypter: c.encrypter,
    40  		src:       src,
    41  		padder:    c.padder,
    42  	}
    43  	return reader
    44  }
    45  
    46  type cbcEncryptReader struct {
    47  	encrypter cipher.BlockMode
    48  	src       io.Reader
    49  	padder    Padder
    50  	size      int
    51  	buf       bytes.Buffer
    52  }
    53  
    54  // Read will read from our io.Reader and encrypt the data as necessary.
    55  // Due to padding, we have to do some logic that when we encounter an
    56  // end of file to pad properly.
    57  func (reader *cbcEncryptReader) Read(data []byte) (int, error) {
    58  	n, err := reader.src.Read(data)
    59  	reader.size += n
    60  	blockSize := reader.encrypter.BlockSize()
    61  	reader.buf.Write(data[:n])
    62  
    63  	if err == io.EOF {
    64  		b := make([]byte, getSliceSize(blockSize, reader.buf.Len(), len(data)))
    65  		n, err = reader.buf.Read(b)
    66  		if err != nil && err != io.EOF {
    67  			return n, err
    68  		}
    69  		// The buffer is now empty, we can now pad the data
    70  		if reader.buf.Len() == 0 {
    71  			b, err = reader.padder.Pad(b[:n], reader.size)
    72  			if err != nil {
    73  				return n, err
    74  			}
    75  			n = len(b)
    76  			err = io.EOF
    77  		}
    78  		// We only want to encrypt if we have read anything
    79  		if n > 0 {
    80  			reader.encrypter.CryptBlocks(data, b)
    81  		}
    82  		return n, err
    83  	}
    84  
    85  	if err != nil {
    86  		return n, err
    87  	}
    88  
    89  	if size := reader.buf.Len(); size >= blockSize {
    90  		nBlocks := size / blockSize
    91  		if size > len(data) {
    92  			nBlocks = len(data) / blockSize
    93  		}
    94  
    95  		if nBlocks > 0 {
    96  			b := make([]byte, nBlocks*blockSize)
    97  			n, _ = reader.buf.Read(b)
    98  			reader.encrypter.CryptBlocks(data, b[:n])
    99  		}
   100  	} else {
   101  		n = 0
   102  	}
   103  	return n, nil
   104  }
   105  
   106  // Decrypt will decrypt the data using AES CBC
   107  func (c *aesCBC) Decrypt(src io.Reader) io.Reader {
   108  	return &cbcDecryptReader{
   109  		decrypter: c.decrypter,
   110  		src:       src,
   111  		padder:    c.padder,
   112  	}
   113  }
   114  
   115  type cbcDecryptReader struct {
   116  	decrypter cipher.BlockMode
   117  	src       io.Reader
   118  	padder    Padder
   119  	buf       bytes.Buffer
   120  }
   121  
   122  // Read will read from our io.Reader and decrypt the data as necessary.
   123  // Due to padding, we have to do some logic that when we encounter an
   124  // end of file to pad properly.
   125  func (reader *cbcDecryptReader) Read(data []byte) (int, error) {
   126  	n, err := reader.src.Read(data)
   127  	blockSize := reader.decrypter.BlockSize()
   128  	reader.buf.Write(data[:n])
   129  
   130  	if err == io.EOF {
   131  		b := make([]byte, getSliceSize(blockSize, reader.buf.Len(), len(data)))
   132  		n, err = reader.buf.Read(b)
   133  		if err != nil && err != io.EOF {
   134  			return n, err
   135  		}
   136  		// We only want to decrypt if we have read anything
   137  		if n > 0 {
   138  			reader.decrypter.CryptBlocks(data, b)
   139  		}
   140  
   141  		if reader.buf.Len() == 0 {
   142  			b, err = reader.padder.Unpad(data[:n])
   143  			n = len(b)
   144  			if err != nil {
   145  				return n, err
   146  			}
   147  			err = io.EOF
   148  		}
   149  		return n, err
   150  	}
   151  
   152  	if err != nil {
   153  		return n, err
   154  	}
   155  
   156  	if size := reader.buf.Len(); size >= blockSize {
   157  		nBlocks := size / blockSize
   158  		if size > len(data) {
   159  			nBlocks = len(data) / blockSize
   160  		}
   161  		// The last block is always padded. This will allow us to unpad
   162  		// when we receive an io.EOF error
   163  		nBlocks -= blockSize
   164  
   165  		if nBlocks > 0 {
   166  			b := make([]byte, nBlocks*blockSize)
   167  			n, _ = reader.buf.Read(b)
   168  			reader.decrypter.CryptBlocks(data, b[:n])
   169  		} else {
   170  			n = 0
   171  		}
   172  	}
   173  
   174  	return n, nil
   175  }
   176  
   177  // getSliceSize will return the correct amount of bytes we need to
   178  // read with regards to padding.
   179  func getSliceSize(blockSize, bufSize, dataSize int) int {
   180  	size := bufSize
   181  	if bufSize > dataSize {
   182  		size = dataSize
   183  	}
   184  	size = size - (size % blockSize) - blockSize
   185  	if size <= 0 {
   186  		size = blockSize
   187  	}
   188  
   189  	return size
   190  }