Need help to create signature in python - python

I have sample code from golang,
here is some sample values to run the code:
app_secret = 777, path = /api/orders, app_key = 12345, timestamp = 1623812664
or you guys can refer this link to get more info https://developers.tiktok-shops.com/documents/document/234136#3.Signature%20Algorithm
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"sort"
)
func generateSHA256(path string, queries map[string]string, secret string) string{
keys := make([]string, len(queries))
idx := 0
for k, _ := range queries{
keys[idx] = k
idx++
}
sort.Slice(keys, func(i, j int) bool {
return keys[i] < keys[j]
})
input := path
for _, key := range keys{
input = input + key + queries[key]
}
input = secret + input + secret
h := hmac.New(sha256.New, []byte(secret))
if _, err := h.Write([]byte(input)); err != nil{
// todo: log error
return ""
}
return hex.EncodeToString(h.Sum(nil))
}
need help converting this golang sample into python sample
i have tried but keep getting signature invalid when submit
my python code
import hmac
import hashlib
def _short_sign(self, app_key, app_secret, path, timestamp):
base_string = "%sapp_key%stimestamp%s"%(path, app_key, timestamp)
sign_string = app_secret + base_string + app_secret
sign = hmac.new(app_secret.encode(), sign_string.encode(), hashlib.sha256).hexdigest()
return sign

Found the issue, i was trying to digest with out digestmod
Working Example:
sign = hmac.new(
app_secret.encode(),
sign_string.encode(),
digestmod = hashlib.sha256
).hexdigest()

Related

I want to send my response to an API using TOTP?

I want to sent my assignment gist in the JSON Response :
{
gist :"",
email :""
}
to an API using TOTP(Time-based one-time password) method . Is there any solution available for that?
Although you have to do it by yourself but still if you invested lot's of time and didn't find solution then you can use my solution for that :
import requests
import hmac
import hashlib
import time
import sys
import struct
import json
from requests.auth import HTTPBasicAuth
root = "YOUR API RESIDES HERE"
content_type = "application/json"
userid = "YOUR USERID"
secret_suffix = "YOUR SECRET SUFFIX OR KEY"
shared_secret = userid+secret_suffix
timestep = 30
T0 = 0
def HOTP(K, C, digits=10):
"""HTOP:
K is the shared key
C is the counter value
digits control the response length
"""
K_bytes = str.encode(K)
C_bytes = struct.pack(">Q", C)
hmac_sha512 = hmac.new(key = K_bytes, msg=C_bytes, digestmod=hashlib.sha512).hexdigest()
return Truncate(hmac_sha512)[-digits:]
def Truncate(hmac_sha512):
"""truncate sha512 value"""
offset = int(hmac_sha512[-1], 16)
binary = int(hmac_sha512[(offset *2):((offset*2)+8)], 16) & 0x7FFFFFFF
return str(binary)
def TOTP(K, digits=10, timeref = 0, timestep = 30):
"""TOTP, time-based variant of HOTP
digits control the response length
the C in HOTP is replaced by ( (currentTime - timeref) / timestep )
"""
C = int ( time.time() - timeref ) // timestep
return HOTP(K, C, digits = digits)
data = {
"github_url": "YOUR GITHUB URL",
"contact_email": "YOUR EMAIL",
"solution_language": "IT IS OPTIONAL"
}
passwd = TOTP(shared_secret, 10, T0, timestep).zfill(10)
resp = requests.post(root, auth=HTTPBasicAuth(userid, passwd), data=json.dumps(data))
print(resp.json())
I hope this works !!
Happy Coding !!

Signature Verification of transaction executed on Payment Gateway in NodeJs

How do I implement the below python/Java/PHP code in NodeJs?
ReferenceLink
Python Code (for reference):
import hashlib
import hmac
import base64
#app.route('/notify_url/', methods=["POST"])
def notify_url_process():
postData = {
"orderId" : request.form['orderId'],
"orderAmount" : request.form['orderAmount'],
"referenceId" : request.form['referenceId'],
"txStatus" : request.form['txStatus'],
"paymentMode" : request.form['paymentMode'],
"txMsg" : request.form['txMsg'],
"txTime" : request.form['txTime'],
}
signatureData = postData["orderId"] + postData["orderAmount"] + postData["referenceId"] + postData["txStatus"] + postData["paymentMode"] + postData["txMsg"] + postData["txTime"]
message = bytes(signatureData).encode('utf-8')
#get secret key from your config
secret = bytes(secretKey).encode('utf-8')
signature = base64.b64encode(hmac.new(secret,
message,digestmod=hashlib.sha256).digest())
So far, I was able to come up with the below code. However, the generated and received signatures do not match.
var hmac = crypto.createHmac('sha256', "appSecret"); //Key hidden for posting here
hmac.update(request.body.orderId + request.body.orderAmount+request.body.referenceId+request.body.txStatus+request.body.paymentMode+request.body.txMsg+request.body.txTime);
let generatedSignature = hmac.digest('hex');
let isSignatureValid = generatedSignature == request.body.cashfreeSignature;
console.log(isSignatureValid);
Have you tried comparing the base64 encoding as opposed to the hex value?
Instead of
let generatedSignature = hmac.digest('hex');
use
let generatedSignature = hmac.digest('base64');

Can't signing a Message using sha512 in python at iconomi

I am trying to send an authentificated message over an API at iconomi.com.
I am used to sign message when dealing with other exchange API, but can't be authentificated with this specific one.
I read the official documentation for authentification:
You generate the ICN-SIGN header by creating a sha512 HMAC using the
base64-decoded secret key on the prehash string timestamp + method +
requestPath + body (where + represents string concatenation) and
base64-encode the output, where:
the timestamp value is the same as the ICN-TIMESTAMP header. the body
is the request body string or omitted if there is no request body
(typically for GET requests). method must always be in upper case
Example: base64_encode(HMAC_SHA512(secret_key, timestamp + upper_case(method) + requestPath + body))
I found also a java client example on the official github, please see bellow signature generation in java :
private String generateServerDigest(String method, String uri, long timestamp, String body) {
//return timestamp + request.getMethodValue() + uri + body;
String checkDigestString = timestamp + method + uri + body;// "GET+/v1/daa-list+123123123"; //timestamp in epoch milliseconds
// hash server composited digest with algorithm and apikeys secret
SecretKeySpec signingKey = new SecretKeySpec(apiSecret.getBytes(), "HmacSHA512");
Mac mac;
try {
mac = Mac.getInstance(signingKey.getAlgorithm());
mac.init(signingKey);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
log.warn("Could not ={}", signingKey.getAlgorithm());
return null;
}
return Base64.getEncoder().encodeToString(mac.doFinal(checkDigestString.getBytes()));
}
Please note that checkDigestString code timestamp + method + uri + body and comment GET+/v1/daa-list+123123123 are already different on the official doc.
And this is my python implementation attempt :
def sign(timestamp,method,requestPath,body):
global api_secret
base64_decoded_secret_key = base64.b64decode(api_secret)
content_to_hash = (str(timestamp) + method.upper() + requestPath + body).encode('utf-8')
sign_digest = hmac.new(base64_decoded_secret_key, content_to_hash , hashlib.sha512).digest()
return base64.b64encode(sign_digest).decode('utf-8')
When I try this signature method with requestPath = "/v1/user/balance" (which required to be authentificated), it fail without error...
Does any one used with both java and python may help me to convert this signature method to python ?
This code will work for GET:
import time,requests
import hashlib,hmac,base64
api_key = "my api key"
api_secret = "my api secret"
defaut_encoding = "utf8"
uri = "https://api.iconomi.com"
requestPath = "/v1/user/balance"
api_url_target = uri+requestPath # https://api.iconomi.com/v1/user/balance
method="GET"
body=""
icn_timestamp = int(1000.*time.time())
message = (str(icn_timestamp) + method.upper() + requestPath + body).encode(defaut_encoding)
signature_digest = hmac.new(api_secret.encode(defaut_encoding), message, hashlib.sha512).digest() #here digest is byte
b64_signature_digest= base64.b64encode(signature_digest).decode(defaut_encoding)
headers_sign= {
"ICN-API-KEY":api_key,
"ICN-SIGN":b64_signature_digest,
"ICN-TIMESTAMP":str(icn_timestamp)
}
s=requests.session()
res = s.get(api_url_target,headers=headers_sign,timeout=3, verify=True).content
print (res)
Update for #Karl comment, this code will work for POST:
import time,requests
import hashlib,hmac,base64,json
api_key = "my api key"
api_secret = "my api secret"
ticker = "my ticker strategy"
defaut_encoding = "utf8"
uri = "https://api.iconomi.com"
requestPath = "/v1/strategies/"+ticker+"/structure"
api_url_target = uri+requestPath # https://api.iconomi.com/v1/strategies/{my ticker strategy}/structure
method="POST"
body="{'ticker': ticker, 'values': [{'rebalancedWeight': 1., 'targetWeight':1., 'assetTicker': 'XMR', 'assetName': 'Monero', 'assetCategory': 'Privacy'}]}"
icn_timestamp = int(1000.*time.time())
message = (str(icn_timestamp) + method.upper() + requestPath + body).encode(defaut_encoding)
signature_digest = hmac.new(api_secret.encode(defaut_encoding), message, hashlib.sha512).digest() #here digest is byte
b64_signature_digest= base64.b64encode(signature_digest).decode(defaut_encoding)
headers_sign= {
"ICN-API-KEY":api_key,
"ICN-SIGN":b64_signature_digest,
"ICN-TIMESTAMP":str(icn_timestamp)
}
s=requests.session()
res = s.post(api_url_target,headers=headers_sign,json = json.loads(body), timeout=3, verify=True).content
print (res)

Sign and verify using ed25519 in near protocol

I am trying to sign the message in javascript using signMessage and verify it with python for implementing jwt authentication.
This is the code for signing message in javascript using near-api-js
window.signer = await new nearlib.InMemorySigner(window.walletAccount._keyStore)
const mysign = await window.signer.signMessage("Amiya",
window.walletAccount._authData.accountId, window.walletAccount._networkId)
let mypubdata = ""
mysign.publicKey.data.forEach( function (item,index){
if(item < 16) {
mypubdata = mypubdata + '0' + item.toString(16)
}
else {
mypubdata = mypubdata + item.toString(16)
}
})
console.log("public key", mypubdata)
let mysignature = ""
mysign.signature.forEach( function (item,index){
if(item < 16) {
mysignature = mysignature + '0' + item.toString(16)
}
else {
mysignature = mysignature + item.toString(16)
}
})
console.log("signature", mysignature)
Output gives:
public key fe20d3e271876c8329c74dcdbe95e32586ee5cf67def1c0cc9e0b8d0e4285813
signature 61d864f40667075da6f920f811def3b83330a6cce49b7bd24eb4711f29abcf55d6d2eaf6f67bf74f20a2f79598f7fd42b4f70db41446d73d596b58d31825710c
This is my python code for backend:
import ed25519
import hashlib
pubKey = ed25519.VerifyingKey(b"fe20d3e271876c8329c74dcdbe95e32586ee5cf67def1c0cc9e0b8d0e4285813", encoding="hex")
print("Public key (32 bytes): ", pubKey.to_ascii(encoding='hex'))
signature = "61d864f40667075da6f920f811def3b83330a6cce49b7bd24eb4711f29abcf55d6d2eaf6f67bf74f20a2f79598f7fd42b4f70db41446d73d596b58d31825710c"
msg = hashlib.sha256(b"Amiya").hexdigest()
print(msg)
try:
pubKey.verify(signature, msg, encoding='hex')
print("The signature is valid.")
except:
print("Invalid signature!")
But I am unable to make it work, it gives an invalid signature.
Formalizing the answer given by #topaco in the comment above:
Try digest() instead of hexdigest() – Topaco May 27 at 18:13

Python OAuth WooCommerce

I am trying to use a WooCommerce Python client to make a POST request but
I get "Provided Signature does not match"
The client I use is from:
WooCommerce API OAuth in python
This is my client:
#!/usr/bin/env python
import requests
import random
import string
import time
from hashlib import sha1
import hmac
import binascii
import re
import collections
from urllib import quote, urlencode
def uksort(dictionary):
return collections.OrderedDict(sorted(dictionary.items(), cmp = cmp))
class WooCommerce(object):
def __init__(self, consumer_key, consumer_secret, endpoint):
self.consumer_key = consumer_key
self.consumer_secret = consumer_secret
self.endpoint = endpoint
def _make_request(self, resource, params, method = "GET"):
oauth_params = {
"oauth_consumer_key": self.consumer_key,
"oauth_nonce": self._gen_nonce(),
"oauth_timestamp": self._gen_timestamp(),
"oauth_signature_method": "HMAC-SHA1",
}
oauth_params["oauth_signature"] = self._gen_signature(resource, dict(params.items() + oauth_params.items()), method)
params = dict(params.items() + oauth_params.items())
if method == "GET":
print self.endpoint + resource + "?" + urlencode(params)
elif method == "POST":
print self.endpoint + resource + "?" + urlencode(params)
req = urllib.request.Request(self.endpoint + resource + "?" + urlencode(params))
open = urllib.request.urlopen(req)
requestContent = open.read()
#print(open)
def _gen_nonce(self):
ran_string = ''.join(random.choice(string.ascii_uppercase + string.digits) for i in range(32)).encode("base64")
alnum_hash = re.sub(r'[^a-zA-Z0-9]', "", ran_string)
return alnum_hash
def _gen_timestamp(self):
return int(time.time())
def _gen_signature(self, resource, params, method):
base_request_uri = quote(self.endpoint + resource, safe = "")
normalized_params = self._normalize_params(params)
sorted_params = uksort(normalized_params)
query_string = "%26".join([key + "%3D" + value for key, value in sorted_params.iteritems()])
raw_string = method + "&" + base_request_uri + "&" + query_string
hashed = hmac.new(self.consumer_secret, raw_string, sha1)
return binascii.b2a_base64(hashed.digest()).rstrip("\n")
def _normalize_params(self, params):
normalized = {}
for key, value in params.iteritems():
key = quote(str(key), safe = "")
value = quote(str(value), safe = "")
normalized[key] = value
return normalized
And I use it like this from another class:
woo_client = WooCommerce('ck_7bb1951bee7454b2e29bf5eef9205e0e', 'cs_155cd9420201c0a7e140bebd6a9794c7', 'http://dima.bg/wc-api/v2')
data = {
"product": {
"title": "testname",
}
}
result = self.woo_client._make_request("/products/", data, 'POST')
Can you see something wrong with my URL ? Thanks for your time.
http://xxxxxxxxx.xx/wc-api/v2/products/?product=%7B%27title%27%3A+%27testname%27%7D&oauth_nonce=NThWODczRFIyWkxRNFZOVkUxNFdRSVo0QjFSNllIVFk&oauth_timestamp=1423647865&oauth_consumer_key=ck_7bb1951bee7454b2e29bf5eef9205e0e&oauth_signature_method=HMAC-SHA1&oauth_signature=3PSnEEf08gFthIRAr8AUKQiDjco%3D
I used your code as a starting point for my own solution to this problem and had some success! Here's what I did:
import requests
import random
import string
import time
from hashlib import sha1
import hmac
import binascii
import re
from urllib import quote, urlencode
import httplib2
from collections import OrderedDict
def key_compare(a, b):
return cmp(a[0], b[0])
class Restful_Client(object):
"""docstring for Restful_Client"""
def __init__(self, endpoint, consumer_key, consumer_secret):
super(Restful_Client, self).__init__()
self.consumer_key = consumer_key
self.consumer_secret = consumer_secret
self.endpoint = endpoint
def make_request(self, resource, params, method='GET' ):
oauth_params = {
'oauth_consumer_key': self.consumer_key,
'oauth_nonce': self.gen_nonce(),
'oauth_timestamp': self.gen_timestamp(),
'oauth_signature_method': 'HMAC-SHA1',
# 'oauth_version':'1.0'
}
oauth_params['oauth_signature'] = self.gen_signature(
resource,
OrderedDict( params.items() + oauth_params.items() ),
method
)
params = OrderedDict( params.items() + oauth_params.items() )
clean_params = self.sort_params(self.normalize_params(params))
uri = endpoint + resource
p_string = urlencode(clean_params)
print 'p string:'
print '\n'.join(p_string.split('&'))
return httplib2.Http().request(uri + '?' + p_string)
def gen_signature(self, resource, params, method):
base_request_uri = quote(self.endpoint + resource, safe = "")
clean_params = self.sort_params(
self.normalize_params(
self.normalize_params(
params
)
)
)
query_string = '%26'.join([
key + '%3D' + value\
for key, value in clean_params.iteritems()
])
raw_string = '&'.join([method, base_request_uri, query_string])
print "raw string: "
print '\n'.join(raw_string.split('%26'))
hashed = hmac.new(self.consumer_secret, raw_string, sha1)
return binascii.b2a_base64( hashed.digest() )[:-1]
def normalize_string(self, string):
return quote(str(string), safe="")
def normalize_params(self, params):
return OrderedDict( [
(self.normalize_string(key), self.normalize_string(value))\
for key, value \
in params.iteritems()
])
def sort_params(self, params):
return OrderedDict(sorted(
params.iteritems(),
cmp=key_compare
))
def gen_timestamp(self):
return int(time.time())
# return 1429451603
def gen_nonce(self):
return hex(self.gen_timestamp())
#todo: make this more secure
if __name__ == "__main__":
store_url = '<STORE URL HERE>'
api_base = 'wc-api'
api_ver = 'v2'
endpoint = "%s/%s/%s/" % (store_url, api_base, api_ver)
consumer_key = '<CK HERE>'
consumer_secret = '<CS HERE>'
resource = 'customers'
parameters = {
# 'fields':'id,first_name'
}
rc = Restful_Client(endpoint, consumer_key, consumer_secret)
r, c = rc.make_request(resource, parameters, 'GET')
print r
print c
What I would suggest is ensuring that the parameters are encoded the correct number of times, I found that the parameters needed to be "double encoded" to work. It looks like in this case your parameters (the key and value strings) are not "double encoded" as suggested in the API doc http://woothemes.github.io/woocommerce-rest-api-docs/#authentication
You can test this hypothesis by trying a simple GET request without any parameters like the one in my code. if that works then that might be your problem. Good luck!

Categories