3

Hello i'm currently programming an application in python using Pyzmq for the communication between a PC client and a raspberry server. I need the PC client to send encrypted password to the raspberry serv. I will just post the RSA parts of my code, so if you need more informations or others parts of my program, please tell me.

So on my raspberry I do this to generate a RSA key:

from Crypto.Hash import MD5
from Crypto.PublicKey import RSA
from Crypto.Util import randpool

alea = randpool.RandomPool()
RSAKey = RSA.generate(1024,alea.get_bytes)

Then I get n and e parameters of this RSAKey which correspond at the Public Key to send them to my PC client.

When my PC receive these informations from the Raspberry, i construct the Public Key on the client:

from Crypto.Hash import MD5
from Crypto.PublicKey import RSA

def create_public_key(n,e):
    key_params = (long(n),long(e))
    return RSA.construct(key_params)

Then, when the user enters his password, I want to encrypt it:

def encrypt(text):
    crypted = Client_Public_Key.encrypt(text,32)
    return crypted[0]

Here is the crypted I get for the text "12345":

('C?\xd2\xca7j\xa0\x0cw\x8b+R"\xc37\xe8IR\xa1\x9fu\xe7v\x0c\xcaW-\xfcXb;]\x887\xc9\xfd\xf6\x0f\xe7\xae\x08\xfe\x0b\xaa*\xfa\x1b\x95:c\x99\xcb\xc6\x9f\x1d\xe1\x84\xa6\xcb\x8adh\x97w\xacR\xff\x8c\x80\xedX\xcc\xf3\xc3\x99\x99\xe9\x92\x8e\xbf]>5\xc5\xbe\x0e*G\xe2\xf2m\xdeN\xa4\x19\xbf\xd6\xd6\x9c\xba\xf9\xc8f\xa7_\xef\x84q\x877\x90\xd3\xd5\x93\xef\x81\xfc $\x9e\x03\t\x9c\xb4\xb1D,Q',)

I tried different way of encrypting (like Cipher's PKCS1_OAEP for example) and I always get these weird strings. Why I don't get a normal sequence of numbers ?

I would like to continue to use the decrypt function of this library because it's very fast, but the encrypt function keeps annoying me.

What can I do ? Thanks !

On my PC, I use Spyder with Python 2.7.14. On my Raspberry, I use Python 3.5.x.

Elweiss
  • 545
  • 1
  • 4
  • 12
  • I'll just expand on zaph's excellent answer: remember that the *character* `\xd2` represents the *byte* 0xd2. So what you're seeing is the byte-array that comes out of RSA stuffed into a string. (Are you by chance printing this as `str(encrypt(text))`? [This article](https://stackoverflow.com/questions/19210414/byte-array-to-hex-string) gives a method for converting the byte array to a hex string, assuming the output of `encrypt` really is a byte array. – lockcmpxchg8b Dec 13 '17 at 16:38

2 Answers2

4

Modern ciphers operate on bytes, not characters, both for the input as well as for the output. Sometimes the characters are implicitly encoded as bytes though - usually ASCII or ASCII compatible such as Windows-1252 (extended Latin).

However, the ciphertext is (almost) indistinguishable from random, which means that if you view the outcome as characters then you will get "garbage" as the output will contain unprintable characters. You were lucky in the sense you got hexadecimal representation of these byte values instead of Unicode with Chinese characters.

To get text you should convert to base 64 or hexadecimals (more "readable", less efficient).


RSA - the calculation - itself produces a number during encryption: the result of the modular exponentiation with the public exponent. However, the RSA standard (PKCS#1) converts this number to a fixed length byte array with the same size of the modulus (that is: the key size in bytes) in a function called I2OSP (integer to octet string primitive). It is in unsigned big endian representation to be precise.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Thanks a lot, i converted the crypted message in base64 and it's working now, i could send it to my raspberry. When you say "less efficient", you mean it's far less safe ? – Elweiss Dec 13 '17 at 16:58
  • 1
    No hex is less efficient because it uses 2 characters per byte instead if 4 for every 3. It does however also allow you to see the size in bytes more easily; just divide by two. – Maarten Bodewes Dec 13 '17 at 17:00
  • Technically @Maarten meant that hexadecimal is less efficient than base64 (which is in turn less efficient than raw bytes). It's only less efficient in terms of string length and processing; for a 64-byte response, it takes ((64 * 4/3) + (3 - 3 * R)) = 87 bytes (where R is the remainder of 64 * 4/3) to encode in base64, or (64 * 2) = 128 bytes in hexadecimal. Then there's also the (comparatively minimal) processing overhead of converting to and from the representations. – Doktor J Sep 11 '20 at 17:50
3

Encryption is byte based and many byte values do not have a corresponding character (or glyph) in a particular character encoding. Some languages will display hex such as \x0c, some will display other glyphs such as �, there is no standard on how to display un-representable binary codes.

As an example fro the question \x0c is hex for the number 12. The \x portion indicates the following two characters are to be interpreted as hexadecimal

If a character representation is needed then the usual encodings to use are Base64 and hexadecimal.

Take some time to examine character encodings, start with ASCII and then utf-8, that understanding will serve you well over time.

zaph
  • 111,848
  • 21
  • 189
  • 228