0

I'm trying to encrypt a message in Java and decrypt it in Python. Unfortunately i'm just starting with python and am not able to get the decryption working.

That's my Java Code:

KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] iv = sr.generateSeed(16);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
SecretKey aesKey = keygen.generateKey();

//save byte array in text file to recreate key later
byte[] encodedKey = aesKey.getEncoded();
new File("myPath\\AESKey.txt");
FileOutputStream fos = new FileOutputStream("myPath\\AESKey.txt");
//save AesKey in first 16 bytes and Initial Vector in next 16 bytes
fos.write(encodedKey);
fos.write(iv);
fos.close();

String secretText = "Hello cryptography";      
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec);
byte[] encrypted = cipher.doFinal(secretText.getBytes());
BASE64Encoder myEncoder  = new BASE64Encoder();
String encodedSecretText = myEncoder.encode(encrypted);

new File("myPath\\encodedSecretText.txt");
FileOutputStream fos2 = new FileOutputStream("myPath\\encodedSecretText.txt");
fos2.write(encodedSecretText.getBytes());  
fos2.close();

I was able to decrypt the message with java, but not with python. I hope someone can show me how to do this.i copied the part with padding from another answer and assume that's the problem.

I get the message: ord() expected string of length 1, but int found.

Python:

from Crypto import Random
from Crypto.Cipher import AES
import base64

BS = 16
pad = lambda s: s + (BS - len(s) % BS) * chr(BS - len(s) % BS) 
unpad = lambda s : s[0:-ord(s[-1])]

#read bytes of aesKey
file = open("myPath/AESKey.txt","rb")
aesKey = file.read(16)
iv = file.read(16)
file.close()
sec = open("myPath/encodedSecretText.txt")
for line in sec:
encodedSecretText =  line.rstrip()
sec.close()

class AESCipher:
    def __init__( self, key ):
        self.key = key
    def encrypt( self, raw ):
        raw = pad(raw)
        iv = Random.new().read( AES.block_size )
        cipher = AES.new( self.key, AES.MODE_CBC, iv )
        return base64.b64encode( iv + cipher.encrypt( raw ) ) 
    def decrypt( self, enc ):
        enc = base64.b64decode(enc)
        cipher = AES.new(self.key, AES.MODE_CBC, iv )
        return unpad(cipher.decrypt( enc[16:] ))

aes = AESCipher(aesKey)   
print(aes.decrypt(encodedSecretText))

Thanks for any hint.

8
  • First, please show a complete traceback, not just the description from the exception. Second, please fix the indentation so this code is actually runnable. Commented Jan 6, 2014 at 4:19
  • As a side note, why are you going out of your way to use lambda to define anonymous expression-only functions just so you use them in a statement and give them a name? If you want your functions to have names, that's what def does. Commented Jan 6, 2014 at 4:29
  • I've rolled back the question, because your edit removes the entire point of your question, making both it and the existing answer useless. You were having a problem with your attempted unpad function. I showed you how to solve that problem. So take that solution and move forward until you get unpad to do what you want, or get stuck somewhere else, at which point you can ask a new question. Erasing your attempted solution entirely and begging for someone to write the code for you is not a step forward. Commented Jan 6, 2014 at 19:31
  • Maybe i misunderstood you when you wrote "just don't call anything there". I thought that the unpad function is not necessary because i already have a byte? That's why i just removed the unpad function. And the reason i removed the for loop is that i just implemented it in the first place for testing. the secret message will be transfered differently later. Now i really dont know how to get the decrypted message in plaintext ("Hello cryptagrophy") and what i'm still missing. Commented Jan 6, 2014 at 20:29
  • Your unpad function did more than just call ord, it used the result of that ord to slice the bytes. If one part of the implementation of that function was incorrect and unnecessary, that doesn't mean you can just throw the whole function away and expect everything to work. Commented Jan 6, 2014 at 20:32

1 Answer 1

1

You're calling ord on an integer. Which is obviously illegal. The whole point of ord is that you give it a Unicode character, as a string, and it gives you back the numerical value of the code point.

So, why do you have a number? Well, I'm not sure what you expected to have, but let's look at what you actually have. If s[-1] is an integer, then s is some kind of sequence of integers. And s is the result of calling cipher.decrypt(). As the documentation for that function says, it returns a byte string. This isn't a specific type, just a description of a type—you can find out what the actual return value is with some basic debugging, maybe like this:

    cipher = AES.new(self.key, AES.MODE_CBC, iv )
    plaintext = cipher.decrypt(enc[16:])
    print(type(plaintext), repr(plaintext))
    return unpad(plaintext)    

But I'm going to guess that it's a bytes object, which (quoting from http://docs.python.org/3/library/functions.html#bytes) …

is an immutable sequence of integers in the range 0 <= x < 256.

So, s[-1] is an integer in the range [0, 256). Hence the error.

So, what should you be doing instead? Well, why are you trying to call ord? You have a byte. Presumably what you want is a byte. So… just don't call anything there.


Meanwhile, there's at least one other serious error in your code:

for line in sec:
encodedSecretText =  line.rstrip()
sec.close()

As pasted, this will raise an IndentationError. And if you indent both the second and third lines, you'll get an error for reading from a closed file. So presumably you want to indent just the second one. In which case, what you're doing is going through all of the lines, stripping the trailing whitespace off each, and then doing nothing with them. At the end of the loop, encodedSecretText holds the last line of encoded text, and all of the other lines are long forgotten and unrecoverable.

If you want to read all of the text into a list of lines, you will want something like this:

encodedSecretText = []
for line in sec:
    encodedSecretText.append(line.rstrip())

Or, if you want to read it into one big string, with the newlines removed, you could do the above and then encodedSecretText = b''.join(encodedSecretText), or just do skip the whole loop and do encodedSecretText = sec.read().replace(b'\n', b'').

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer, when i used encryption i used PKCS5Padding and thought that i have to use it in decryption as well. My goal is to decrypt the encrypted message. Thats where i dont make any progress. I will post the new code in python in a sec
@user3157669: I don't see what that comment has to do with the question or with my answer. Your problem is that your code raises a TypeError. I showed you why it does that, and how to fix it. So fix that error and move forward until you get stuck again, then ask a new question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.