# Is a stream cipher and a (cryptographically secure) PRNG nearly the same thing?

If I let the authentification tag aside (which is important), encrypting with AES-GCM and a fixed key and nonce:

import Crypto.Random, Crypto.Cipher.AES, numpy as np
key = bytes.fromhex('7d29ccf69c671775e17d4b9dd6485fd8')
nonce = bytes.fromhex('04972c7927042af0ee10c7e6ac56ddd3')
cipher = Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_GCM, nonce=nonce)
print(cipher.encrypt(b'goodgoodcrypto').hex())     # e7e4d3b74617d78022376651ba3a


can be obtained with the same result by obtaining a cipherstream (encryption of a stream of \x00\x00... null bytes) to XOR with the plaintext

xor = lambda x, y: (np.frombuffer(x, dtype='uint8') ^ np.frombuffer(y, dtype='uint8')).tobytes()
cipher = Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_GCM, nonce=nonce)
cipherstream = cipher.encrypt(b'\x00' * 14)     # 808bbcd32178b8e441451f21ce55
print(cipherstream.hex())
print(xor(cipherstream, b'goodgoodcrypto').hex())   # e7e4d3b74617d78022376651ba3a !! same ciphertext!


Here I only took 14 bytes of cipherstream because I only needed 14 bytes to encode plaintext.

Thus, it looks like in this context of AES-GCM that:

• encryption here is equivalent to just having a long-enough stream of random-looking bytes (cipherstream above),
• deterministically initialized with key and nonce (similar to the seed in PRNG terminology)
• encryption is just this cipherstream XORed with plaintext

Question: can we turn a (cryptographically secure) PRNG into a stream cipher? (the PRNG's seed is the key / nonce)

The reciprocal seems also true: AES-GCM encrypting a flow of null bytes b"\x00\x00\x00\x00..." seems to give a cryptographically secure PRNG. The seed is the key+nonce pair.