5 Replies - 6608 Views - Last Post: 22 July 2011 - 01:28 PM Rate Topic: -----

#1 duffman18  Icon User is offline

  • D.I.C Head

Reputation: 14
  • View blog
  • Posts: 54
  • Joined: 20-October 10

How to work with bytes in Python

Posted 21 July 2011 - 08:41 AM

I am messing around with making encryption algorithms and have run into a simple yet annoying problem when trying to work with plain bytes. Right now I am just trying to do a very very simple encryption algorithm on a file. It is nothing fancy just doing some bit-wise operations on each byte of the file and writing that new data to a new encrypted file. The algorithm is simple:
initialData = file.read(1)
newData = initialData >> 1(with carry of LSB to MSB)
newData = ~newData
newData = newData * key(key is an int passed to the algorithm)
pad newData to 2 bytes with 0s
encryptedFile.write(newData)


So with that algorithm in mind I wrote this code to try and do that:
def encrypt(fileName, key, m = ''):
    if m == '':
        fRead = open(fileName+'.txt', 'rb')
        fWrite = open(fileName+'encrypted.txt', 'wb')

        tempB = fRead.read(1)
        while tempB != b'':
            if (tempB & b'\x01') != b'\x00':
                newB = tempB>>1
                newB = newB | b'\x80'
            else:
                newB = tempB>>1
            newB = ~newB
            newB = newB*key
            bytesWritten = fWrite.write(newB)
            print(bytesWritten)
            tempB = fRead.read(1)
            
        
    fRead.close()
    fWrite.close()
    return


However python is not even letting me do these bit-wise operations on the bytes. I keep getting "TypeError: unsupported operand type(s)" for the operations(&, >>, and ~) which I thought were bit-operations(bit-wise AND, rotate right, and bit-wise invert respectively). Is there a way to get the full individual bit control without having to make my own class for this application? Also I know I have not padded the newB out to 2 bytes with 0s yet. I could not even get to try doing that because I can't even execute the previous parts of the algorithm yet.

Is This A Good Question/Topic? 0
  • +

Replies To: How to work with bytes in Python

#2 Motoma  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 452
  • View blog
  • Posts: 796
  • Joined: 08-June 10

Re: How to work with bytes in Python

Posted 21 July 2011 - 09:03 AM

Which version of Python?

You can use ord() to convert a single byte to an integer which you can perform bitwise ops on.
Was This Post Helpful? 1
  • +
  • -

#3 duffman18  Icon User is offline

  • D.I.C Head

Reputation: 14
  • View blog
  • Posts: 54
  • Joined: 20-October 10

Re: How to work with bytes in Python

Posted 21 July 2011 - 09:11 AM

View PostMotoma, on 21 July 2011 - 09:03 AM, said:

Which version of Python?


Sorry forgot to include that I am using Python v3.1. Thanks for the help I'll give ord() a try.
Was This Post Helpful? 0
  • +
  • -

#4 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5846
  • View blog
  • Posts: 12,703
  • Joined: 16-October 07

Re: How to work with bytes in Python

Posted 21 July 2011 - 09:23 AM

So:
def encodeByte(initialData, key):
	newData = initialData >> 1
	newData = ~newData
	newData = newData * key
	return newData



The problem is you're either relying on an overflow behavior that doesn't exist in Python. Or, and I'm guessing this is the case, you're trying to manipulate a 'byte' object, which is really just a string representation of an encoding.

e.g.
>>> encodeByte(3, 42)
-84
>>> n = '\x03'
>>> n
'\x03'
>>> len(n)
1
>>> int(n)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '\x03'
>>> import struct
>>> struct.unpack('B',n)
(3,)
>>> encodeByte(b, 42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in encodeByte
TypeError: unsupported operand type(s) for >>: 'str' and 'int'
>>> 


Was This Post Helpful? 1
  • +
  • -

#5 duffman18  Icon User is offline

  • D.I.C Head

Reputation: 14
  • View blog
  • Posts: 54
  • Joined: 20-October 10

Re: How to work with bytes in Python

Posted 22 July 2011 - 07:31 AM

Thanks to the help from you guys I got my code working the way I wanted and also I got the decryption method working. There were a few difficulties I had with the invert, but in the end I got it working and will be able to do this again in a more elaborate encryption algorithm. Here is how I wrote the encryption method:
def encrypt(fileName, key, m = ''):
    if m == '':
        fRead = open(fileName, 'rb')
        fWrite = open('encrypted'+fileName, 'wb')

        tempB = fRead.read(1)
        while tempB != b'':
            intB = ord(tempB) #convert the byte to an int
            if intB%2 != 0: #Check if odd or even(LSB is set or not)
                newB = intB>>1
                newB = newB + 128 # add 128(\x80) is the same as carrying the LSB when it is set.
            else:
                newB = (intB>>1)
            newB = (~newB) & 255 #& with 255 to drop the leading 1s that you get
            newB = newB*key
            LBi = newB%256 # isolates the lower byte
            UBi = (newB>>8)%256 # rotates right to get the upper byte
            encryptedBytes = bytearray([UBi, LBi])
            bytesWritten = fWrite.write(encryptedBytes)
            print('eBytes Written:'+str(bytesWritten))
            tempB = fRead.read(1)
            
        
    fRead.close()
    fWrite.close()
    return


And here is how I handled the decryption method:
def decrypt(fileName, key):
    fRead = open(fileName, 'rb')
    fWrite = open('decrypted'+fileName, 'wb')

    #reads in the 2 bytes seperately
    tempUB = fRead.read(1)
    tempLB = fRead.read(1)
    #the only while loop condition needed because you know any
    #file encrypted will have an even number of bytes
    while tempLB != b'' and tempUB != b'':
        intUB = ord(tempUB)
        intLB = ord(tempLB)
        intB = (intUB<<8)+intLB
        intB = (intB//key) 
        # & with 255 here to change the leading 1 you get from ~ to a 0 
        # and keep the rest the same.
        intB = (~intB) & 255
        if intB > 127: #check if the MSB is 1
            newB = intB<<1
            newB += 1 # carry the 1 to the LSB
            newB = newB%256 # gets rid of the original 1 in the MSB
        else:
            newB = intB<<1
        decryptedBytes = bytearray([newB])
        bytesWritten = fWrite.write(decryptedBytes)
        print('dBytes Written:'+str(bytesWritten))
        tempUB = fRead.read(1)
        tempLB = fRead.read(1)
    fRead.close()
    fWrite.close()
    return


I forgot when I was doing the bit-wise invert that in an integer variable there were all the leading 0s in the block of memory. Therefore when I inverted the number I always got -(N+1) where N is my number I was inverting. This was not the behavior I wanted for this application. I wanted it to be an unsigned 8-bit int, but there is no way to specify this so all I had to do was & the number with 255(or \xFF) to keep just the lower 8 bits and make the rest 0. That way I will always get a positive 8-bit integer. Thanks again baavgai and Motoma for your help.
Was This Post Helpful? 1
  • +
  • -

#6 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon

Reputation: 5846
  • View blog
  • Posts: 12,703
  • Joined: 16-October 07

Re: How to work with bytes in Python

Posted 22 July 2011 - 01:28 PM

This was kind of interesting, but I have a problem with it: I can't test it without a file! Indeed, encryption implementation should be reasonably separate from file IO... what would that take?

I isolated your encryption to look something like:
def encrypt(intB, key):
	newB = intB>>1
	if not intB%2 == 0:
		newB = newB + 128 # add 128(\x80) is the same as carrying the LSB when it is set.
	newB = (~newB) & 255 #& with 255 to drop the leading 1s that you get
	newB = newB*key
	return ( (newB>>8)%256, newB%256 )



I'm dubious of those mods. You should be able to do it all with an & 255. This works the same:
def encrypt(intB, key):
	def toByte(n): return n & 255
	newB = toByte(~((intB>>1) + ((intB%2) * 128))) * key
	return ( toByte(newB>>8), toByte(newB) )



So, a decrypt with similar considerations:
def decrypt(intUB, intLB, key):
	def toByte(n): return n & 255
	intB = toByte(~(((intUB<<8)+intLB)//key))
	newB = intB<<1
	if intB > 127:
		newB += 1
	return toByte(newB)



I'll leave the integration into file IO as an exercise...
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1