Home > OS >  numpy randint() to generate bytes
numpy randint() to generate bytes

Time:05-01

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!'

Try it online!

  • Related