granitdev
granitdev

Reputation: 146

How to decrypt pgp armored string using PGPy when the armored string isn't from PGPy?

I'm creating a script that communicates with a server that is using PGP encryption to encrypt it's responses.

I can request the public key of the server, and use that key to encrypt my request via the PGPy library, and the server is able to decrypt it and respond.

The scripts encrypted request has it's public key in it, which the server is expecting as a part of it's API, so it takes that key and encrypts the response and sends it back to my script. My script receives this encrypted response fine, but PGPy appears to lack the facilities to decrypt it.

From what I can tell, PGPy can only decrypt a message that it encrypted because the the PGPKey.decrypt() takes a PGPMessage object, not an armored string, and I cannot find any method that takes an armored string and either decrypts it or turns it into a PGPMessage so that I can decrypt it.

This is as far as I've gotten:

def get_token_from_payload(encrypted_payload):
    print("Payload: ", encrypted_payload)
    privkey, _ = pgpy.PGPKey.from_file('private.key')
    message_blob = pgpy.PGPMessage.new(encrypted_payload)
    token_string = privkey.decrypt(message_blob).message
    print("Token: ", token_string)
    return json.load(token_string)

The message_blob = pgpy.PGPMessage.new(encrypted_payload) that I thought would do the right thing, doesn't, and instead makes it's own encrypted text blob that the line token_string = privkey.decrypt(message_blob).message simply turns back into the armored ascii string I started with. Of course the last line fails because there is no json to do anything with so we'll ignore that for right now as that should work just fine once PGPy is decrypting things.

I must be missing something. This library is essentially useless if it can't do this. How do I either decrypt the armored string or convert the armored string into a PGPMessage that can then be decrypted?

Update:

def get_token_from_payload(encrypted_payload):
    ep_file = open("ep.pgp", "w")
    ep_file.write(encrypted_payload)
    ep_file.close()
    privkey, _ = pgpy.PGPKey.from_file('private.key')
    message = pgpy.PGPMessage.from_file("ep.pgp")
    token_string = privkey.decrypt(message).message
    return json.loads(token_string)

This solution does work, but I don't find it acceptable as it requires an extraneous set of IO steps, creating a file and then reading it right back in. I already have the armored ascii message in memory, I just want to decrypt it directly.

Upvotes: 0

Views: 1706

Answers (1)

Steve G
Steve G

Reputation: 131

You should be able to create a PGPMessage object from the ascii armored string in memory by using pgpy.PGPMessage.from_blob()

def get_token_from_payload(encrypted_payload):
  print("Payload: ", encrypted_payload)
  privkey, _ = pgpy.PGPKey.from_file('private.key')
  message_blob = pgpy.PGPMessage.from_blob(encrypted_payload)
  token = privkey.decrypt(message_blob).message
  print("Token: ", token)
  return json.load(token)

You might also need to convert the token value from a bytearray to a string. Something like this should work:

  token_string = str(token, 'UTF-8')
  print("Token: ", token_string)
  return json.load(token_string)

Upvotes: 0

Related Questions