Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #17

Merged
merged 7 commits into from
Mar 26, 2025
Merged

Dev #17

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 66 additions & 11 deletions safeheron_api_sdk_python/cosigner/co_signer_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,33 @@ def __init__(self):
self.txKey = None


class CoSignerResponseV3:
def __init__(self):
# action
self.action = None
# approvalId
self.approvalId = None


class CoSignerConverter:

def __init__(self, config):
self.api_pub_key = config['apiPubKey']
if config.get('bizPrivKey'):
self.biz_privKey = PEM_PRIVATE_HEAD + config['bizPrivKey'] + PEM_PRIVATE_END
if config.get('bizPrivKeyPemFile'):
self.biz_privKey = load_rsa_private_key(config['bizPrivKeyPemFile'])
# Supports both coSignerPubKey and apiPublKey
self.co_signer_pub_key = config.get('coSignerPubKey') or config.get('apiPubKey')

# Supports both approvalCallbackServicePrivateKey and bizPrivKey
private_key = config.get('approvalCallbackServicePrivateKey') or config.get('bizPrivKey')
if private_key:
self.approval_callback_service_private_key = PEM_PRIVATE_HEAD + private_key + PEM_PRIVATE_END

# Supports both approvalCallbackServicePrivateKeyPemFile and bizPrivKeyPemFile
pem_file = config.get('approvalCallbackServicePrivateKeyPemFile') or config.get('bizPrivKeyPemFile')
if pem_file:
self.approval_callback_service_private_key = load_rsa_private_key(pem_file)

def request_convert(self, co_signer_call_back):
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.api_pub_key + PEM_PUBLIC_END)
api_user_rsa_sk = get_rsa_key(self.biz_privKey)
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.co_signer_pub_key + PEM_PUBLIC_END)
api_user_rsa_sk = get_rsa_key(self.approval_callback_service_private_key)
required_keys = {
'key',
'sig',
Expand Down Expand Up @@ -65,10 +80,50 @@ def request_convert(self, co_signer_call_back):

return json.loads(r.decode())

def request_v3_convert(self, co_signer_call_back):
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.co_signer_pub_key + PEM_PUBLIC_END)
required_keys = {
'version',
'sig',
'bizContent',
'timestamp',
}

missing_keys = required_keys.difference(co_signer_call_back.keys())
if missing_keys:
raise Exception(co_signer_call_back)
co_signer_call_back['version'] = 'v3'
sig = co_signer_call_back.pop('sig')

need_sign_message = sort_request(co_signer_call_back)
v = rsa_pass_verify(platform_rsa_pk, need_sign_message, sig)
if not v:
raise Exception("rsa verify: false")
return json.loads(b64decode(co_signer_call_back['bizContent']).decode())

def response_v3_converter(self, co_signer_response: CoSignerResponseV3):
api_user_rsa_sk = get_rsa_key(self.approval_callback_service_private_key)
ret = dict()
response_data = json.dumps(co_signer_response.__dict__).replace('\'', '\"').replace('\n', '').encode('utf-8')

if response_data is not None:
ret['bizContent'] = b64encode(response_data).decode()

ret['timestamp'] = str(int(time.time() * 1000))
ret['code'] = str('200')
ret['version'] = str('v3')
ret['message'] = str('SUCCESS')

# 4 sign request
need_sign_message = sort_request(ret)
ret['sig'] = rsa_pss_sign(api_user_rsa_sk, need_sign_message)
return ret


# It has been Deprecated,Please use convertCoSignerResponseWithNewCryptoType
def response_converter(self, co_signer_response: CoSignerResponse):
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.api_pub_key + PEM_PUBLIC_END)
api_user_rsa_sk = get_rsa_key(self.biz_privKey)
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.co_signer_pub_key + PEM_PUBLIC_END)
api_user_rsa_sk = get_rsa_key(self.approval_callback_service_private_key)

ret = dict()

Expand Down Expand Up @@ -98,8 +153,8 @@ def response_converter(self, co_signer_response: CoSignerResponse):
return ret

def response_converter_with_new_crypto_type(self, co_signer_response: CoSignerResponse):
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.api_pub_key + PEM_PUBLIC_END)
api_user_rsa_sk = get_rsa_key(self.biz_privKey)
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.co_signer_pub_key + PEM_PUBLIC_END)
api_user_rsa_sk = get_rsa_key(self.approval_callback_service_private_key)

ret = dict()

Expand Down
21 changes: 21 additions & 0 deletions safeheron_api_sdk_python/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from Cryptodome.Hash import SHA256, SHA1
from Cryptodome import Random
from Crypto.Cipher import PKCS1_OAEP
from Cryptodome.Signature import pss
import json
import time
import requests
Expand Down Expand Up @@ -147,6 +148,16 @@ def rsa_sign(private_key, message_hash: bytes):
except Exception as e:
raise Exception("rsa sign error: %s" % e)

def rsa_pss_sign(private_key, message_hash: bytes):
try:
signer = pss.new(private_key)
digest = SHA256.new()
digest.update(message_hash)
signed = signer.sign(digest)
return b64encode(signed).decode()
except Exception as e:
raise Exception("rsa sign error: %s" % e)


def rsa_verify(public_key, message_hash: bytes, signature):
try:
Expand All @@ -157,6 +168,16 @@ def rsa_verify(public_key, message_hash: bytes, signature):
except Exception as e:
raise Exception("rsa sign error: %s" % e)

def rsa_pass_verify(public_key, message_hash: bytes, signature):
try:
verifier = pss.new(public_key)
digest = SHA256.new()
digest.update(message_hash)
verifier.verify(digest, b64decode(signature))
return True
except Exception as e:
raise Exception("rsa sign error: %s" % e)


def sort_request(r: dict):
sortData = json.dumps(r, sort_keys=True).replace(' ', '')
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
with open("README.rst", "r") as f:
long_description = f.read()
setup(name='safeheron_api_sdk_python',
version='1.1.13',
version='1.1.14',
description='Python for Safeheron API',
long_description=long_description,
author='safeheron',
Expand Down