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
Related
I made a python api that I'm trying to get my app to connect to, but for the login function I need to send the username and password but I'm not sure how to do this. This is the python code:
username = data.get('username')
email = data.get('email')
password = data.get('password')
And the Kotlin Code:
private fun sendData(username:String, password:String): Thread {
return Thread {
val url = URL("https://127.0.0.1:5000/login")
val connection = url.openConnection() as HttpsURLConnection
connection.setRequestProperty("username", username)
connection.setRequestProperty("password", password)
if (connection.responseCode == 200) {
val inputSystem = connection.inputStream
println(inputSystem.toString())
Toast.makeText(applicationContext, "It worked", Toast.LENGTH_SHORT).show()
}
else {
var code: String = "ERROR"
Toast.makeText(applicationContext, "NO CONNECTION", Toast.LENGTH_SHORT).show()
}
}
}
The connection is opened but I can get any data across and I haven't tried anything so far as I can't find good documentation on this.
You could, for example, first set up a class to handle your credentials:
class LoginData(
val userID: String,
val pw: String
){
/** Returns a hashmap of the data stored in the class object. */
fun getHashmap(): Map<String,String> {
val params = HashMap<String,String>()
params["username"] = userID
params["password"] = pw
return params
}
/** Obtains a JSONObject of the data stored in the class object. */
fun getJson(): JSONObject {
val params = this.getHashmap()
return JSONObject(params)
}
}
And then, utilising Volley (don't forget to add it to your build gradle: implementation 'com.android.volley:volley:1.2.0'), do something like this:
fun sendData(username: String?, password: String?) {
val url = "https://127.0.0.1:5000/login"
var loginData = LoginData(
userID = username!!,
pw = password!!
)
val queue = Volley.newRequestQueue(this)
val jsonRequest = JsonObjectRequest(
Request.Method.POST,
url,
loginData.getJson(),
Response.Listener {
response -> handleResponse(response)//do something with the response
},
Response.ErrorListener { error -> println("That didn't work: $error")})
queue.add(jsonRequest)
}
with handleResponse() containing your logic to evaluate what comes back from the server:
fun handleResponse(response: JSONObject) {
//your evaluation logic
}
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()
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)
I am trying to replicate the following lines of python code from the https://github.com/joshfraser/robinhood-to-csv repo from GitHub in order to read my transaction history.
orders = robinhood.get_endpoint('orders')
paginated = True
page = 0
while paginated:
for i, order in enumerate(orders['results']):
executions = order['executions']
instrument = robinhood.get_custom_endpoint(order['instrument'])
fields[i + (page * 100)]['symbol'] = instrument['symbol']
for key, value in enumerate(order):
if value != "executions":
fields[i + (page * 100)][value] = order[value]
if order['state'] == "filled":
trade_count += 1
for key, value in enumerate(executions[0]):
fields[i + (page * 100)][value] = executions[0][value]
elif order['state'] == "queued":
queued_count += 1
# paginate
if orders['next'] is not None:
page = page + 1
orders = robinhood.get_custom_endpoint(str(orders['next']))
else:
paginated = False
Where we also have
def get_endpoint(self, endpoint=None):
res = self.session.get(self.endpoints[endpoint])
return json.loads(res.content.decode('utf-8'))
I have thus been working on the following iOS code. I work with this code in an XCode playground so feel free to make one to follow along
import UIKit
import PlaygroundSupport
let LoginEndpoint:String = "https://api.robinhood.com/api-token-auth/"
let LoginRequestData:[String : String] = ["username": "EmailAdress", "password": "Password"]
let OrdersEndpoint:String = "https://api.robinhood.com/orders/"
func httpReq(type: String, url: String, body:[String : String], header:[String : String]) -> ([String : Any]?, Data?, String?){
let url = URL(string: url)
var returnData:([String : Any]?, Data?, String?)? = nil
if let url = url {
var request = NSMutableURLRequest(url: url) as URLRequest
request.httpMethod = type
var postString = ""
for (key, value) in body {
if (postString != "") {
postString += "&"
}
postString += "\(key)=\(value)"
}
request.httpBody = postString.data(using: .utf8)
for (key, value) in header {
request.addValue(value, forHTTPHeaderField: key)
}
let _ = URLSession.shared.dataTask(with: request, completionHandler: {(data, response, error) in
if let data = data {
do {
let jsonSerialized = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any]
returnData = (jsonSerialized, data, nil)
} catch (_) {
returnData = (nil, data, "JSON Parse Erro")
}
} else if let error = error {
returnData = (nil, nil, error.localizedDescription)
}
}).resume()
}
while (returnData == nil) {}
return returnData!
}
let tokenQuery = httpReq(type: "POST", url: LoginEndpoint, body: LoginRequestData, header: [:])
if let token = tokenQuery.0?["token"] {
print("token \(token)")
let historyQuery = httpReq(type: "GET", url: OrdersEndpoint, body: [:], header: ["Authorization": "Token \(token)"])
if let results = historyQuery.0?["results"], let countString = historyQuery.0?["count"] {
}
}
RunLoop.main.run()
PlaygroundPage.current.needsIndefiniteExecution = true
So as you can see I am using the auth token to get to the orders endpoint. I am indeed getting a good response from the orders endpoint but I have no clue how to interpret it.
It would seem from the python code that it is returning an array of JSON objects however I cant figure out how to get to that array in swift. I am not even sure if I am decoding it properly. The funny thing is when you look at the object returned in Playgrounds it would seem XCode knows that there is an array going on. How do I get to it?
Can't really get a good idea of the information being returned by your service, because of the lack of credentials.
However, check out SwiftyJSON. It's a really good library, and is extremely helpful with handling JSON data in Swift. It should solve your JSON handling issues.
So, I'm going to be having a service that posts fields to my app and have to do the following:
When an action occurs within your account, several values are passed
along in the Instant Notification query string (see URL Parameters).
While building the string we create a sha1, or a hash of the values
passed, and your Secret Key. The result is the cverify parameter. Upon
receipt of the query string parameters, your system must also create a
sha1, or a hash of the values passed, and your Secret Key.
The validity of the data received is evaluated by using the cverify
parameter we send and the value produced in your system. Only if there
is an exact match between the two values can you be certain the
information received has not been tampered with.
I'm guessing I should use the crypto module. But, not sure how to do the rest of this. The params would come in via the req.body I know... but, not sure about the rest.
Below is their example from python
import hashlib
##
# Verify cverify from an ipn.
# #param post_params: A dictionary of all POST parameters from the notification
# #return: True if the cverify parameter is valid, false otherwise
def ipnVerification(post_params):
secret_key = "YOUR SECRET KEY"
pop = ""
ipn_fields = []
for key in post_params.keys():
if key == "cverify":
continue
ipn_fields.append(key)
ipn_fields.sort()
for field in ipn_fields:
pop += post_params[field] + "|"
pop += secret_key
return post_params["cverify"] == hashlib.sha1(pop).hexdigest()[:8].upper()
This is what I have so far:
var secretKey = 'My Secret Key';
module.exports = {
validateRequest: function(req){
var params = []
for (param in req.body) {
if (param == "cverify")
continue;
params.push(param);
}
params.sort();
var pop = "";
for (param in params) {
pop += req.body.param + "|";
}
pop += secretKey;
var cverify = req.body.cveryify;
// do crypto stuff
console.log(params);
}
}
If I understand the code correctly:
var secretKey = 'My Secret Key';
module.exports = {
validateRequest : function(req) {
/* shorter version of what you have already:
var keys = Object.keys(req.body)
.filter(function(key) { return key !== 'cverify'; })
.sort();
var pop = keys.map(function(key) {
return body[key];
}).join('|') + '|' + secretKey;
*/
...
var sha1 = require('crypto').createHash('sha1');
sha1.update(pop);
var digest = sha1.digest('hex').substring(0, 8).toUpperCase();
return digest === req.body.cverify;
}
};