2

created a client-server application with sockets and I am trying to transfer the signature from client to server. I convert it from tuple to string and then back to tuple. But signing stops working. How to resolve this?

from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA

public_key_file = open('public.pem','r')
public_key = RSA.importKey(public_key_file.read())

signature = "(90392831408741910958006452852395405116864328891950288888434929210668328849466319419951775157374761930395371626801844365799774616689823184955256615103504859356914334395152128600862146719619859327119380994333493461955529620578485576675021993313219918726432622856542420570716350341841652548574072964446809201965L,)"
signature_tuple = signature.split(",")
message = "Block_Height:1 From:c52030257a864a67ae4ef8a726282ed2b6b273fbccb474885027a857 To:2 Amount:3"

if public_key.verify(message, signature_tuple) == True:
    print "Signature valid"

.

Traceback (most recent call last):
  File "C:\Users\kucerjan\Desktop\test\sco\public_test.py", line 12, in <module>
    if public_key.verify(message, signature_tuple) == True:
  File "build\bdist.win32\egg\Crypto\PublicKey\RSA.py", line 221, in verify
    return pubkey.pubkey.verify(self, M, signature)
  File "build\bdist.win32\egg\Crypto\PublicKey\pubkey.py", line 126, in verify
    return self._verify(M, signature)
  File "build\bdist.win32\egg\Crypto\PublicKey\RSA.py", line 257, in _verify
    return self.key._verify(m, s)
  File "build\bdist.win32\egg\Crypto\PublicKey\_slowmath.py", line 73, in _verify
    return self._encrypt(sig) == m
  File "build\bdist.win32\egg\Crypto\PublicKey\_slowmath.py", line 65, in _encrypt
    return pow(m, self.e, self.n)
TypeError: unsupported operand type(s) for pow(): 'str', 'long', 'long'

This signature is already converted to string using str(signature). I basically need to convert it to string and back.

Function reference: https://www.dlitz.net/software/pycrypto/api/current/Crypto.PublicKey.RSA._RSAobj-class.html#verify

Public key:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFiMH7Lbd4JPFug8TaxX1DT8ad
lzzGm7CG1js0IQn2pCPPWBS+io1i0iUPmj78IOtUuoBqtEYGPgwqguYHozBuvdJy
Lcz4C2bYcjb2l8mQ4PM7iaCN4eHB+4xa+iJduogTjq8gx5m3j5mttEGUbZc2Q/AO
yde592P2iuRIrXcLuwIDAQAB
-----END PUBLIC KEY-----
mikeazo
  • 389
  • 2
  • 24
HCLivess
  • 1,015
  • 1
  • 13
  • 21

2 Answers2

3

The problem is in deserializing the signature tuple.

PyCrypto is expecting a tuple with an integer as the first value, you are passing it a string with a beginning paren "(" and then a string version of a number.

Instead of doing this:

signature_tuple = signature.split(",")

do this

signature_tuple = eval(signature)

That will properly parse the signature.

Now, there are security risks with using eval. So, if I were you, I'd come up with a better serialization/deserialization process.

Community
  • 1
  • 1
mikeazo
  • 389
  • 2
  • 24
  • Thank you very much, this worked! I only started with this, so after I finish some testing phase, I will consider a better process. – HCLivess May 07 '15 at 13:32
  • For now I am thinking of using something like a regexp check before evaluating: `match = re.match ("\(\d+L\,\)",signature) if match != None: signature_tuple = eval(signature) else: print "Malicious code received"` – HCLivess May 07 '15 at 14:03
  • OK, so I will use `signature_tuple = ast.literal_eval(signature)` and I should be safe. Thanks, didn't know eval was that evil. – HCLivess May 07 '15 at 14:11
1

The best way is to use PKCS1_v1_5 for real applications in combination with base64 for encoding and decoding the signature between client and server. No eval is needed.

from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
import base64

message = 'To be signed'
key = RSA.importKey(open('privkey.der').read())
h = SHA.new(message)
signer = PKCS1_v1_5.new(key)
signature = signer.sign(h)
signature_enc = str(base64.b64encode(signature))
#print signature_enc


signature_dec = str(base64.b64decode (signature_enc))
#print sugnature_dec
key = RSA.importKey(open('pubkey.der').read())
h = SHA.new(message)
verifier = PKCS1_v1_5.new(key)
if verifier.verify(h, signature_dec):
   print "The signature is authentic."
else:
   print "The signature is not authentic."
HCLivess
  • 1,015
  • 1
  • 13
  • 21