I have to make a stream cipher that takes in input a byte generator (randint
function by default). I tried to implement it in this way but I don't want to have at the output the str(
) representation, I want the bytes one, so b'\x.......')
.
I read that bytes()
with a list of integers gives the str
representation, so if I return crypted
in the crypting_fn
, with a for
cycle to pass to the bytes()
only one int
at a time, will I solve my "problem"? If not, can you please explain to me how can I do that?
import numpy as np
import numpy.random
class SC(object):
def __init__(self, key, prng=None, **kwargs):
if prng is None:
seed=None
rs = np.random.RandomState(seed)
def gen(seed):
rs = np.random.RandomState(seed)
while True:
yield rs.randint(0,255)
self.prng = rs.randint(0, 255)
else:
self.prng = prng(key, **kwargs)
def encrypt(self, plaintext):
return self.crypting_fn(plaintext)
def decrypt(self, ciphertext):
return self.crypting_fn(ciphertext)
def crypting_fn(self, text):
crypted=bytes([b^s for b, s in zip(text, range(self.prng))])
return crypted
message = 'hello world!'
key = 0x012345678
a = SC(key)
b = SC(key)
plaintextA = message.encode('utf-8')
ciphertext = a.encrypt(plaintextA)
plaintextB = b.decrypt(ciphertext)
print(plaintextA)
print(ciphertext)
print(plaintextB)
The output Is:
b'hello world!'
b'hdnok%qhzen*'
b'hello world!'
CodePudding user response:
Your use of the PRNG is borked; instead of generating a stream of bytes, you generate a single byte and your keystream is just 0, 1, 2, 3... up until you hit the random byte (so when the byte is small, you don't even have enough to encrypt the entire input).
Fix your code to make self.prng
a keystream generator, not a single random byte, and use it as such, and you'll get something that looks like what you want:
import numpy as np
import numpy.random
class SC(object):
def __init__(self, key, prng=None, **kwargs):
if prng is None:
def gen(seed):
rs = np.random.RandomState(seed)
while True:
yield rs.randint(0, 255)
self.prng = gen(key) # Seed with provided "key", not None (which seeds from system random)
else:
# Without knowing what prng should be, I can't be sure this line is correct
# This is what you'd want if calling prng produced an iterator using the keystream
self.prng = prng(key, **kwargs)
def encrypt(self, plaintext):
return self.crypting_fn(plaintext)
def decrypt(self, ciphertext):
return self.crypting_fn(ciphertext)
def crypting_fn(self, text):
crypted=bytes([b^s for b, s in zip(text, self.prng)])
return crypted
message = 'hello world!'
key = 0x012345678
a = SC(key)
b = SC(key)
plaintextA = message.encode('utf-8')
ciphertext = a.encrypt(plaintextA)
plaintextB = b.decrypt(ciphertext)
print(plaintextA)
print(ciphertext)
print(plaintextB)
which outputs:
b'hello world!'
b' \x9f\xc8\xec\xd4\\\xac\xf6\xae\xba\x9c\xeb'
b'hello world!'