unknown0
unknown0

Reputation: 61

Python reads only one char per row from a binary file

I have a script which 'encodes' user entered text, for now it's just a string 'python' by default. I am having a problem decoding it.

This is the output with f.tell, where I can see it only reads first byte from each row and outputs only 'pto' instead of 'python'.

2
p2
2
2
t2
2
2
o2
2
2
Traceback (most recent call last):
  File "...\file.py", line 73, in <module>
    oa=ord(a)
TypeError: ord() expected a character, but string of length 0 found
>>> 

Somehow it reads without a problem until string of length 0 is found, I can't found where because text.bin is equally spaced, just like key.bin.

Running xxd -b on text.bin file shows that file contains necessary bytes for decoding.

00000000: 00000000 00000000 01110000 00000000 00000000 01111001  ..p..y
00000006: 00000000 00000000 01110100 00000000 00000000 01101000  ..t..h
0000000c: 00000000 00000000 01101111 00000000 00000000 01101110  ..o..n
00000012: 00000000 00000000                                      ..

Also key.bin contains them. Here first byte(odd) is an offset between each char in text.bin and second byte (even) is an XOR mask. I set it to 0 because I haven't thought of a method to generate symetrical bytes to do xor at the end. I guess I would need XOR cipher for this..

00000000: 00000010 00000000 00000010 00000000 00000010 00000000  ......
00000006: 00000010 00000000 00000010 00000000 00000010 00000000  ......
0000000c: 00000010 00000000 00000010 00000000 00000010 00000000  ......
00000012: 00000010 00000000 00000010 00000000 00000010 00000000  ......
00000018: 00000010                                               .

Here is the current code

fdata = open("text.bin","wb") ; fmeta = open("key.bin","w+b")
print('Enter a text:')
txt='python' # input()
print('Binary:')
print(" ".join(txt))
l=len(txt)
print(l, 'bytes')
strtobin= ' '.join(format(x, 'b') for x in bytearray(txt, 'utf-8'))
print(strtobin)

shift=int(2)
sh=nobv.to_bytes(1, byteorder='big')

# even bytes in key.bin
for v in range(0, 25, 2): # len(txt)
    #print(v)
    fmeta.seek(v)
    fmeta.write(sh)

# odd bytes in key.bin (contains first part for XOR)
for a in range(0,25): #len(txt)+1
    if a % 2 != 0:
        #print(a)
        fmeta.seek(a)
        fmeta.write(b'\x00')

pad = b'\x00\00'
for line in txt:
    for char in line:
        fdata.write(pad)
        fdata.write(char.encode())
fdata.write(pad)
fdata.close() ; fmeta.close()

f = open ("key.bin", "rb"); d = open ("text.bin", "rb")
f.seek(0); d.seek(0) ; position = 0
while 1:
        #f.seek(2,0)
        offset = f.read(1)
        f.seek(1,0)
        mask = f.read(1)
        
        if not offset: break;
        if not mask: break;

        shift = int(ord(offset))
        position = position + shift
        d.seek(position)
        
        print(f.tell())
        
        a = d.read(1)
        oa=ord(a)
        om=ord(mask)
        output = chr(oa^om)    
        print (output, end="")
f.close() ; d.close()

Upvotes: 2

Views: 153

Answers (1)

JohnAlexINL
JohnAlexINL

Reputation: 626

Your script looked like something I could help with, so I thought I'd give it the old college try.

First problem is at line 15: you didn't define "sh"; also, the way you wrote your "in range" block will not work on a lot of systems, so I made it look more like your other loop.

for v in range(0, 25):
    if v % 2 == 0:
        #print(v)
        fmeta.seek(v)
        fmeta.write(sh)

I'm not sure what you're using that variable for, specifically, so I just added the line sh = b'\x01' to the list of variables at the top while I as testing the script. Figure it'd make it easy to spot what the script is actually doing, later.

Now, at this point, I get the error

oa=ord(a)
TypeError: ord() expected a character, but string of length 0 found 

I suspect the issue is with these two lines: 38: offset = f.read(1) , and 45: shift = int(ord(offset))

Your program is reading the offset from your file "key.bin", and then stepping that far over into the file "text.bin", and when it goes to a = d.read(1), sometimes it's reading EOF or a null value.

I'm not entirely sure how to fix the script, here, because I don't understand what your goal output is, but I hope I was able to help, anyway :)

Upvotes: 1

Related Questions