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
andnonce
(similar to theseed
in PRNG terminology) - encryption is just this
cipherstream
XORed withplaintext
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.
\x00\x00...
gives a CSPRNG, for which the seed is the AES key+nonce pair? $\endgroup$