0

Does anyone know what is the equivalent of this two line of PHP code in Python?

$pkeyid = openssl_get_privatekey($priv_key);
openssl_sign($data, $binary_signature, $pkeyid, OPENSSL_ALGO_SHA1);

Thanks in advance!

Edited:

$fpx_msgToken = "01";
$fpx_msgType = "BE";
$fpx_sellerExId = "ABC000012345";
$fpx_version = "6.0";
/* Generating signing String */
$data = $fpx_msgToken."|".$fpx_msgType."|".$fpx_sellerExId."|".$fpx_version;
/* Reading key */
$priv_key = file_get_contents('C:\\pki-keys\\DevExchange\\EX00002220.key');
$pkeyid = openssl_get_privatekey($priv_key);
openssl_sign($data, $binary_signature, $pkeyid, OPENSSL_ALGO_SHA1);
$fpx_checkSum = strtoupper(bin2hex( $binary_signature ) );
3
  • 1
    What have you tried so far, where exactly are you stuck? By googling the first method name, there's a result immediately Commented Jun 12, 2019 at 9:32
  • 1
    I mean, like @NicoHaase said, by googling 'python cryptography dsa' you can find full examples of how to do that in python. Commented Jun 12, 2019 at 9:38
  • Hi, thanks for the reply. I need to integrate with a bank payment gateway, they provide us the sample code in PHP, but I use Python. I hv been searching on Google for 2 days and couldn't get the answer, I totally no idea about cryptography and not even know what are the keyword to search. After searching there are too many functions on cryptography, not sure which one does the same jobs. @LLJ97 thanks for the suggested keyword DSA, I found the answer for the second line, looks like is this one "signature = private_key.sign(data, hashes.SHA256()", but the first line still don't know the answer. Commented Jun 12, 2019 at 12:39

2 Answers 2

1

In python I would use the cryptography package.

Examples shown can be found here: https://cryptography.io/en/latest/hazmat/primitives/asymmetric/dsa/

You can create a private key with the following code.

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import dsa

private_key = dsa.generate_private_key(key_size=2048, backend=default_backend())

This will create the key to generate the signature of your data.

I would suggest you 2048 bits or above for the key length.

The following code is an example for signing a message.

from cryptography.hazmat.primitives import hashes

data = b"this is some test data"
signature = private_key.sign(data, hashes.SHA256())

If you now want to verify a signature you have to get the public key from the private key.

public_key = private_key.public_key()
public_key.verify(signature, data, hashes.SHA256())

This public key corresponds with your private key and is used to verify signatures that were created with your private key.

Don't focus on each line too much, every language and library will have different methods and ways of doing basically the same thing.

Now for a complete example you can just put the above examples together.

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import dsa

private_key = dsa.generate_private_key(key_size=2048, backend=default_backend())
data = b"this is some test data"
signature = private_key.sign(data, hashes.SHA256())
public_key = private_key.public_key()
public_key.verify(signature, data, hashes.SHA256())

public_key.verify() will raise an InvalidSignature exception if the signature happens to be invalid (Source: https://cryptography.io/en/latest/hazmat/primitives/asymmetric/dsa/#verification).

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

10 Comments

Thanks @LLJ97 ! I have added the full block of the PHP code in the EDITED section of my question above. I still could not understand how to get the $pkeyid from this openssl_get_privatekey($priv_key) in Python. Looks like I need to read the EX00002220.key to get the $pkeyid and use the $pkeyid to perform public_key.verify() to get the signature. Again how do I get the $pkeyid from the key file (EX00002220.key)? Sorry to ask such a silly question, but I really no idea about cryptography.
openssl_get_privatekey() is an alias of openssl_pkey_get_private(). It's basically just a function which either reads a file or a key in the PEM format and prepares it for use in the program. So in your code they're reading a file and getting the key. The variable name $pkeyid is a pretty bad name since it is misleading. $pkeyid IS the private key, just parsed and prepared for use.
Thanks for the explanation! I got it now. I tested it and got the following error: Traceback (most recent call last): File "main.py", line 40, in <module> data = b"%s|%s|%s|%s" % (fpx_msg_token, fpx_msg_type, fpx_seller_exchange_id, fpx_version) TypeError: %b requires a bytes-like object, or an object that implements bytes, not 'str'
is your data byte like? Be careful of the b in front of the example string. You can either do b"test string" or someStringVariable.encode() to get a bytestring and therefore a byte like object.
I have edited my previous comment with different error message, previously I forgot to add the "b" in front of my data (b"my.data"), but after I added the b" and got a different error message (see my edited previous comment).
|
1

I have found the solution of Python equivalent code for the above PHP code as below.

from OpenSSL import crypto
import binascii    

fpx_msg_token = "01"
fpx_msg_type = "BE"
fpx_seller_exchange_id = "ABC0000123"
fpx_version = "6.0"

# Generating signing String
data = "{}|{}|{}|{}".format(fpx_msg_token, fpx_msg_type, fpx_seller_exchange_id, fpx_version)

key_id = open('C:\\pki-keys\\DevExchange\\EX00002220.key').read();

# Check is TraditionalOpenSSL or PKCS8 format 
if key_id.startswith('-----BEGIN RSA PRIVATE KEY'):
    # TraditionalOpenSSL format;
    priv_key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_id)
else:
    # PKCS8 format;
    priv_key = crypto.load_pkcs12(key_id).get_privatekey()

# return signature is in binary string;
signature_bin_str = crypto.sign(priv_key, data, 'sha1')

# Convert binary string to hexidecimal
signature_hex = binascii.hexlify(signature_bin_str)

# Convert binary to string;
signature = signature_hex.decode("ascii")

# Convert signature to upper case;
fpx_checksum = str(signature).upper()

At the end I got the same value as in PHP code.

:)

Comments

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.