AES GCM is a version of AES in counter mode, and a counter mode converts a block cipher into a stream cipher. The main advantage of a stream cipher is that we do not have to worry about padding. We get 16 bytes of pseudo random key stream per invocation of the AES **encryption** function, which gets XOR ed with the plaintext to get the corresponding ciphertext. When reading a file in programming languages like ```C``` or ```C++``` or ```Python``` you can specify the number of bytes to read , while **looping** till you reach the end of file. It is advisable to choose a multiple of 16 in this case like 1024*1024 bytes or more, but keeping hardware limitations and efficiency in mind. Reading 16 bytes for every loop interation is inefficient. You can find an optimal value to read by trial and error, and some benchmarking. The number of bytes successfully read by these functions provided by those programming languages can also be checked (let that be called `x`). In the case of Python: MY_BLOCK_SIZE = 1024*1024 with open(filename, "rb") as fobj: run = True while run: data = fobj.read(MY_BLOCK_SIZE) if len(data)==0 : break elif (len(data)%MY_BLOCK_SIZE) == 0: #invoke AES encryption function MY_BLOCK_SIZE/16 times incrementing the counter each time # do all the things for calculating the authentication tag # Ciphertext is XOR(data, key_stream, len(data)) else: #invoke AES encryption function MY_BLOCK_SIZE/16 times incrementing the counter each time # do all the things for calculating the authentication # Ciphertext is XOR(data, key_stream, len(data)) Suppose you read a file of arbitrary length in blocks of bytes (which is a multiple of 16 ) , there are two possibilities, either the last block read might be exactly your block size (```x = 16*n```) or less than it (```x < 16*n```). In either case, you have to invoke the AES encryption function ```n``` times, but you use only, ```x``` bytes of the key stream, generated for that iteration, to XOR with the plaintext.