Cosign Signature API (json, not SOAP) does not verify signature created by itself - cosign-api

I am attempting to sign a tiny buffer using the Signature API (JSON), as a POC for integration into my project. I am using the CoSign Trial developer account server. The signature is created successfully, but when attempting to verify the buffer, the response contains the following (not very useful) error:
{u'ErrData': {u'Code': -24,
u'InnerCode': -1878850959,
u'Message': u'Failed to verify buffer.',
u'Module': u'VerifyBuffer'},
u'Success': False}
i've followed the documentation from this page:
http://docs.arx.com/CoSign_APIs/doc_v7.1/Default.htm#doc_7.1/Verify Buffer.htm#_Toc398808255%3FTocPath%3DCoSign%2520Signature%7CAPI%7CSigning%2520and%2520Verifying%7C_____4
and i'm attaching my code in python (username and password erased)
import urllib2
import hashlib
import xml.dom.minidom
import base64
import pprint
import json
class Client:
SIGN_URL = 'https://prime.cosigntrial.com:8081/sapiws/SignBuffer'
VERIFY_URL = 'https://prime.cosigntrial.com:8081/sapiws/VerifyBuffer'
GET_CERTS_URL = 'https://prime.cosigntrial.com:8081/sapiws/UserCertificatesGet'
HEADERS = {'Content-Type': 'application/json; charset=utf-8'}
def __init__(self, username, password):
self._username = username
self._password = password
def signBytes(self, bytes):
obj = dict(
Username=self._username, Password=self._password,
BufferToSign=base64.b64encode(bytes))
return self._transaction(obj)
def verifyBytes(self, bytes, signature):
obj = dict(
BufferToSign=base64.b64encode(bytes), Signature=signature)
return self._transaction(obj, url=self.VERIFY_URL)
def getCertificates(self):
return self._transaction(dict(Username=self._username, Password=self._password), url=self.GET_CERTS_URL)
def signUsingHash(self, bytes):
digest = hashlib.sha512(bytes).digest()
obj = dict(
Username=self._username, Password=self._password,
BufferToSign=base64.b64encode(digest),
BufferHash=True, HashAlg="Sha512")
return self._transaction(obj)
def verifyUsingHash(self, bytes, signature):
digest = hashlib.sha512(bytes).digest()
obj = dict(
BufferToSign=base64.b64encode(digest), Signature=signature,
BufferHash=True)
return self._transaction(obj, url=self.VERIFY_URL)
def _transaction(self, message, url=SIGN_URL):
print "Y"*100
pprint.pprint(message)
request = urllib2.Request(url, json.dumps(message))
connection = urllib2.urlopen(request)
try:
return json.loads(connection.read())
finally:
connection.close()
client = Client(username="", password="")
value = "ABCDEFG"
response1 = client.signBytes(value)
print "X"*100
print response1
verified1 = client.verifyBytes(value, response1[u'Data'] [u'Signature'])
print "Z"*100
pprint.pprint(verified1)
i've also attempted to use the BufferHash argument and calculated the hash myself, but the same error occurs.

All you need to do to make your code run properly is:
Pass your predefined request headers to the request itself-
urllib2.Request(url, json.dumps(message), self.HEADERS)
Note that the returned base64-encoded data of the signature contains redundant \r\n characters (it is a known issue that will be fixed in a later release). Just remove those characters before passing the data to the verify operation. For example-
client.verifyBytes(value, response1[u'Data'][u'Signature'].replace("\r\n", ""))

Thanks Almog and ALX, your answers helped. Unfortunately, i can't upvote your answers, don't have enough stackoverflow reputation.
I've managed my way around few other details, like creating a pkcs#1 signature and verifying it. I'm posting here the full cleaned up source code for future reference for others. My conclusion is that a source code example of using the REST API would have really helped, no matter the language - so i suggest writing one or even using mine, somewhere in the examples page in the documentation site.
Thanks again for your help.
import urllib2
import hashlib
import base64
import json
import string
class Client:
_HEADERS = {'Content-Type': 'application/json; charset=utf-8'}
_ALGORITHMS = dict(
Sha256=lambda x: hashlib.sha256(x).digest(),
Sha384=lambda x: hashlib.sha385(x).digest(),
Sha512=lambda x: hashlib.sha512(x).digest())
_PKCS1_FLAGS = 0x80000
_ALGORITHM_FLAGS = dict(
Sha256=0x04000,
Sha384=0x08000,
Sha512=0x10000)
def __init__(self, username, password, hostname="prime.cosigntrial.com"):
self._username = username
self._password = password
self._signURL = 'https://%s:8081/sapiws/SignBuffer' % hostname
self._verifyURL = 'https://%s:8081/sapiws/VerifyBuffer' % hostname
self._getCertificatesURL = 'https://%s:8081/sapiws/UserCertificatesGet' % hostname
self._serverInfoURL = 'https://%s:8081/sapiws/ServerInfoGet' % hostname
def signBytes(self, bytes, algorithm="Sha512", pkcs1=False):
assert algorithm in self._ALGORITHMS, "'%s' is not Sha256|384|512" % algorithm
parameters = dict(
Username=self._username, Password=self._password,
BufferToSign=base64.b64encode(bytes), HashAlg=algorithm)
if pkcs1:
parameters['Flags'] = self._PKCS1_FLAGS
result = self._transaction(self._signURL, parameters)
if not result[u'Success']:
raise Exception("Sign buffer failed (%s)" % result)
return result[u'Data'][u'Signature']
def verifyBytes(self, bytes, signature, pkcs1Certificate=None, pkcs1Algorithm="Sha512"):
assert self._isBase64(signature), "Signature must be in base64 format"
parameters = dict(
BufferToSign=base64.b64encode(bytes), Signature=self._removeCRLF(signature))
if pkcs1Certificate is not None:
assert self._isBase64(pkcs1Certificate), "Certificate must be in base 64 format"
assert pkcs1Algorithm in self._ALGORITHM_FLAGS, "'%s' is no Sha256|384|512" % pkcs1Algorithm
parameters['Flags'] = self._PKCS1_FLAGS | self._ALGORITHM_FLAGS[pkcs1Algorithm]
parameters['Certificate'] = self._removeCRLF(pkcs1Certificate)
result = self._transaction(self._verifyURL, parameters)
if not result[u'Success']:
raise Exception("Verify buffer failed (%s)" % result)
return result[u'Data']
def signUsingHash(self, bytes, algorithm="Sha512", pkcs1=False):
assert algorithm in self._ALGORITHMS, "'%s' is not Sha256|384|512" % algorithm
digest = self._ALGORITHMS[algorithm](bytes)
parameters = dict(
Username=self._username, Password=self._password,
BufferToSign=base64.b64encode(digest),
BufferHash=True, HashAlg=algorithm)
if pkcs1:
parameters['Flags'] = self._PKCS1_FLAGS
result = self._transaction(self._signURL, parameters)
if not result[u'Success']:
raise Exception("Sign buffer failed (%s)" % result)
return result[u'Data'][u'Signature']
def verifyUsingHash(self, bytes, signature, algorithm="Sha512", pkcs1Certificate=None):
assert self._isBase64(signature), "Signature must be in base64 format"
assert algorithm in self._ALGORITHMS, "'%s' is not Sha256|384|512" % algorithm
digest = self._ALGORITHMS[algorithm](bytes)
parameters = dict(
BufferToSign=base64.b64encode(digest), Signature=self._removeCRLF(signature),
BufferHash=True)
if pkcs1Certificate is not None:
assert self._isBase64(pkcs1Certificate), "Certificate must be in base 64 format"
parameters['Flags'] = self._PKCS1_FLAGS
parameters['Certificate'] = self._removeCRLF(pkcs1Certificate)
result = self._transaction(self._verifyURL, parameters)
if not result[u'Success']:
raise Exception("Verify buffer failed (%s)" % result)
return result[u'Data']
def getCertificates(self):
result = self._transaction(
self._getCertificatesURL,
dict(Username=self._username, Password=self._password))
if not result[u'Success']:
raise Exception("Getting certificates failed (%s)" % result)
return result[u'Data'][u'Certificates']
def serverInfo(self):
result = self._transaction(self._serverInfoURL, {})
if not result[u'Success']:
raise Exception("Getting server info failed (%s)" % result)
return result[u'Data']
def _transaction(self, url, parameters):
request = urllib2.Request(url, json.dumps(parameters), self._HEADERS)
connection = urllib2.urlopen(request)
try:
return json.loads(connection.read())
finally:
connection.close()
def _isBase64(self, data):
valid = string.lowercase + string.uppercase + string.digits + "+/=\r\n"
return [x for x in data if x not in valid] == []
def _removeCRLF(self, s):
return s.replace("\r\n", "")
if __name__ == "__main__":
import pprint
USERNAME = "" # fill this
PASSWORD = "" # fill this
VALUE = "ABCDEFG"
client = Client(username=USERNAME, password=PASSWORD)
print "SERVER INFO:"
pprint.pprint(client.serverInfo())
print "USER CERTIFICATES:"
certificates = client.getCertificates()
pprint.pprint(certificates)
firstCertificate = certificates[0]['Certificate']
print "Signing bytes using pkcs#7:"
signedWith7 = client.signBytes(VALUE)
print "Signing bytes using pkcs#1:"
signedWith1 = client.signBytes(VALUE, pkcs1=True)
print "Signing hash using pkcs#7:"
signedHashWith7 = client.signUsingHash(VALUE)
print "Signing hash using pkcs#1:"
signedHashWith1 = client.signUsingHash(VALUE, pkcs1=True)
assert signedWith1 == signedHashWith1, \
"Expected signature from hash to be equals to be identical"
print "Verify bytes using pkcs#7:"
result = client.verifyBytes(VALUE, signedWith7)
assert result[u'IsValid'], "Expected to be valid"
pprint.pprint(result)
print "Verify bytes using pkcs#1:"
result = client.verifyBytes(VALUE, signedWith1, pkcs1Certificate=firstCertificate)
assert result[u'IsValid'], "Expected to be valid"
pprint.pprint(result)
print "Verify hash using pkcs#7:"
result = client.verifyUsingHash(VALUE, signedWith7)
assert result[u'IsValid'], "Expected to be valid"
pprint.pprint(result)
print "Verify hash, using hash signature, using pkcs#7:"
result = client.verifyUsingHash(VALUE, signedHashWith7)
assert result[u'IsValid'], "Expected to be valid"
pprint.pprint(result)
print "Verify hash using pkcs#1:"
result = client.verifyUsingHash(VALUE, signedWith1, pkcs1Certificate=firstCertificate)
assert result[u'IsValid'], "Expected to be valid"
pprint.pprint(result)
print "All tests passed"

The signature returned from signBuffer function contains \r\n characters, remove these characters from signature before calling to verifyBuffer should fix the issue.

Related

Error while validating User Input in Python

I am having problem validating the user input (I am asking user if they wish to continue with the program of calculating factorial). The code is as follows: (User input validation is towards the end of the main function and I have not included the factorial function)
def main():
valid_inp = False
usr_continue = True
while usr_continue:
while valid_inp == False:
usr_inp = int(input('Please ENTER a number: '))
if usr_inp < 0:
print('ERROR, INVALID INPUT')
else:
valid_inp = True
continue
result = factorial(usr_inp)
print(str(result) + '\n')
con_inp = str(input('Would you like to continue ? '))
if con_inp == 'Y' or con_inp == 'y':
usr_continue
elif con_inp == 'N' or con_inp == 'n':
print('Goodbye...')
break
main()
Make a function that only returns on valid input. Use an exception handler to deal with bad integer input, then validate the integer is the range you want:
from math import factorial
def get_nonnegative_integer(prompt):
while True:
try:
val = int(input(prompt)) # bad input for int such as "abc" will raise ValueError
if val >= 0: # good input will be range-checked
return val
else:
print('enter a number >= 0')
except ValueError:
print('invalid input for integer')
def main():
while True:
usr_inp = get_nonnegative_integer('Please enter a number: ')
result = factorial(usr_inp)
print(result)
con_inp = input('Would you like to continue(Y/n)? ').upper() # default Yes
if con_inp.startswith('N'):
print('Goodbye...')
break
main()

TypeError: POST data should be bytes or an iterable of bytes. It cannot be of type str

My Code.
#!/usr/bin/env python
#coding: utf-8
userid="NicoNicoCreate#gmail.com"
passwd="********"
import sys, re, cgi, urllib, urllib.request, urllib.error, http.cookiejar, xml.dom.minidom, time, urllib.parse
import simplejson as json
def getToken():
html = urllib.request.urlopen("http://www.nicovideo.jp/my/mylist").read()
for line in html.splitlines():
mo = re.match(r'^\s*NicoAPI\.token = "(?P<token>[\d\w-]+)";\s*',line)
if mo:
token = mo.group('token')
break
assert token
return token
def mylist_create(name):
cmdurl = "http://www.nicovideo.jp/api/mylistgroup/add"
q = {}
q['name'] = name.encode("utf-8")
q['description'] = ""
q['public'] = 0
q['default_sort'] = 0
q['icon_id'] = 0
q['token'] = token
cmdurl += "?" + urllib.parse.urlencode(q).encode("utf-8")
j = json.load( urllib.request.urlopen(cmdurl), encoding='utf-8')
return j['id']
def addvideo_tomylist(mid,smids):
for smid in smids:
cmdurl = "http://www.nicovideo.jp/api/mylist/add"
q = {}
q['group_id'] = mid
q['item_type'] = 0
q['item_id'] = smid
q['description'] = u""
q['token'] = token
cmdurl += "?" + urllib.parse.urlencode(q).encode("utf-8")
j = json.load( urllib.request.urlopen(cmdurl), encoding='utf-8')
time.sleep(0.5)
#Login
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
urllib.request.install_opener(opener)
urllib.request.urlopen("https://secure.nicovideo.jp/secure/login",
urllib.parse.urlencode( {"mail":userid, "password":passwd}) ).encode("utf-8")
#GetToken
token = getToken()
#MakeMylist&AddMylist
mid = mylist_create(u"Testlist")
addvideo_tomylist(mid, ["sm9","sm1097445", "sm1715919" ] )
MyError.
Traceback (most recent call last):
File "Nico3.py", line 48, in <module>
urllib.parse.urlencode( {"mail":userid, "password":passwd}) ).encode("utf-8")
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/urllib/request.py", line 162, in urlopen
return opener.open(url, data, timeout)
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/urllib/request.py", line 463, in open
req = meth(req)
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/urllib/request.py", line 1170, in do_request_
raise TypeError(msg)
TypeError: POST data should be bytes or an iterable of bytes. It cannot be of type str.
I've tried encode but it did not help.
I'm japanese accademic students.
It was not able to be settled by my knowledge.
I am aware of this similar question, TypeError: POST data should be bytes or an iterable of bytes. It cannot be str, but am too new for the answer to be much help.
You paren is in the wrong place so you are not actually encoding:
.urlencode({"mail":userid, "password":passwd}).encode("utf-8")) # <- move inside

python TypeError: expected string or buffer when parsing JSON from a file

I realize this problem has been answered for other folks but none of the threads are helping me solve it. I'm trying to parse a JSON structure and add all values in the sent_file when the keys match with the tweet_file. The error I'm getting
import sys
import json
def main():
sent_file = open(sys.argv[1])
tweet_file = open(sys.argv[2])
scores = {}
#tweet = {}
#tweet_text = {}
#hw()
#lines(sent_file)
#lines(tweet_file)
for line in sent_file:
term,score = line.split("\t")
scores[term] = int(score)
#print scores.items()
for tweets in tweet_file:
current_sent_value = 0
tweet = {} #this is a dict
#print type(tweets) str
tweet = json.loads(tweets)#[0] #this assignment changes tweet to a list. Why?
if 'text' in tweet:
tweet_text = {}
unicode_string = tweet['text']
encoded_string = unicode_string.encode('utf-8')
tweet_text = encoded_string.split()
for key in tweet_text:
for key in scores:
#print type(tweet_text) -- list
#print type(scores) --dict
if tweet_text.get(key) == scores.get(key): # get() does not work on a list. tweet_text is a list.
current_sent_value += scores(value)
print current_sent_value
if name == 'main':
main()
The error is here \assignment1\tweet_sentiment2.py", line 42, in main
if tweet_text.get(key) == scores.get(key): # get() does not work on a list. tweet_text is a list.
AttributeError: 'list' object has no attribute 'get'

Twisted will not send data back only if I use async DB ops

After struggling with inlineCallbacks and yield of twisted/txredisapi, I can save my data into redis. Thanks to author of txredisapi. Now I met a new issue, socket server will not send back to client before/after saving into DB.
Twisted offers simple socket server as following:
from twisted.internet import protocol, reactor
class Echo(protocol.Protocol):
def dataReceived(self, data):
self.transport.write(data) ### write back
class EchoFactory(protocol.Factory):
def buildProtocol(self, addr):
return Echo()
reactor.listenTCP(8000, EchoFactory)
recctor.run()
My code is similiar, only with additional DB ops.
#!/usr/bin/env python
import time
import binascii
import txredisapi
from twisted.internet import defer
from twisted.internet import protocol, reactor
from twisted.internet.protocol import Factory
from twisted.enterprise import adbapi
from twisted.python import log
from dmpack import Dmpack
from dmdb import Dmdb
from dmconfig import DmConf
dm = Dmpack()
conf = DmConf().loadConf()
rcs = txredisapi.lazyConnection(password=conf['RedisPassword'])
dbpool = adbapi.ConnectionPool("MySQLdb",db=conf['DbName'],user=conf['DbAccount'],\
passwd=conf['DbPassword'],host=conf['DbHost'],\
use_unicode=True,charset=conf['DbCharset'])
def getDataParsed(data):
realtime = None
period = None
self.snrCode = dm.snrToAscii(data[2:7])
realtime = data[7:167] # save it into redis
period = data[167:-2] # save it into SQL
return (snrCode, realtime, period)
class PlainTCP(protocol.Protocol):
def __init__(self, factory):
self.factory = factory
self.factory.numConnections = 0
self.snrCode = None
self.rData = None
self.pData = None
self.err = None
def connectionMade(self):
self.factory.numConnections += 1
print "Nr. of connections: %d\n" %(self.factory.numConnections)
self.transport.write("Hello remote\r\n") # it only prints very 5 connections.
def connectionLost(self, reason):
self.factory.numConnections -= 1
print "Nr. of connections: %d\n" %(self.factory.numConnections)
#defer.inlineCallbacks
def dataReceived(self, data):
global dbpool, rcs
(self.snrCode,rDat,pDat) = getDataParsed(data)
if self.snrCode == None or rDat == None or pDat == None:
err = "Bad format"
else:
err = "OK"
print "err:%s"%(err) # debug print to show flow control
self.err = err
self.transport.write(self.snrCode)
self.transport.write(self.err)
self.transport.write(rDat)
self.transport.write(pDat)
self.transport.loseConnection()
if self.snrCode != None and rDat != None and pDat != None:
res = yield self.saveRealTimeData(rcs, rDat)
res = yield self.savePeriodData(dbpool, pDat, conf)
print "err2:%s"%(err) # debug print to show flow control
#defer.inlineCallbacks
def saveRealTimeData(self, rc, dat):
key = "somekey"
val = "somedata"
yield rc.set(key,val)
yield rc.expire(key,30)
#defer.inlineCallbacks
def savePeriodData(self,rc,dat,conf):
query = "some SQL statement"
yield rc.runQuery(query)
class PlainTCPFactory(protocol.Factory):
def buildProtocol(self, addr):
return PlainTCP(self)
def main():
dmdb = Dmdb()
if not dmdb.detectDb():
print "Please run MySQL RDBS first."
sys.exit()
log.startLogging(sys.stdout)
reactor.listenTCP(8080, PlainTCPFactory())
reactor.run()
if __name__ == "__main__":
main()
And clip of my client, which is a simple client:
def connectSend(host="127.0.0.1",port=8080):
global packet
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((host, port))
s.sendall(''.join(packet))
data = s.recv(1024)
s.close()
print 'Received', repr(data)
except socket.error, err:
print "Remote socket is not available: %s"%str(err)
sys.exit(1)
The current status is:
If disable #defer.inlineCallbacks and yield opertions of dataReceived(), both self.transport.write() inside of connectionMode() and dataReceived() can output data to clients.
If we enabled #defer.inlineCallbacks and two yield DB ops of SQL/Redis, then self.transport.write() inside of connectionMode() prints every 5 connections, and dataReceived() will not output any data to clients.
the debug print statements will print on log regardless of #defer.inlineCallbacks anyway.
I was told that dataReceived() should not be #defer.inlineCallbacks. But it doesn't change anything if I removed that decoration.
I am thinking if gevent can help me out of this unpredicted behavior. I am twisted into an endless tornado, cyclone .....
Anyone who has similiar experience, please help me. Thanks.
By changing function as following, the code works.
#COMMENT OUT decorator of #defer.inlineCallbacks
def dataReceived(self, data):
global dbpool, rcs
(self.snrCode,rDat,pDat) = getDataParsed(data)
if self.snrCode == None or rDat == None or pDat == None:
err = "Bad format"
else:
err = "OK"
print "err:%s"%(err) # debug print to show flow control
self.err = err
self.transport.write(self.snrCode)
self.transport.write(self.err)
self.transport.write(rDat)
self.transport.write(pDat)
self.transport.loseConnection()
if self.snrCode != None and rDat != None and pDat != None:
self.saveRealTimeData(rcs, rDat)
self.savePeriodData(dbpool, pDat, conf)
# Removing yield before DB ops
print "err2:%s"%(err) # debug print to show flow control
#defer.inlineCallbacks
def saveRealTimeData(self, rc, dat):
print "saveRedis"
key = "somekey"
val = "somedata"
yield rc.set(key,val)
yield rc.expire(key,30)
#defer.inlineCallbacks
def savePeriodData(self,rc,dat,conf):
print "save SQL"
query = "some SQL statement"
yield rc.runQuery(query)
If we keep #defer.inlineCallbacks and yield in dataReceived. The connection is closed before second DB op. Therefore no data is output to connection. Maybe is caused by inlineCallbacks decorator.
By removing this, the flow control is simple and straightforward.
However, I still can get why I can not add inlineCallbacks if there are two deferred DB ops. This time they don't need deferred?

how to get tornadoredis listen value

I want to write a chat demo with tornado and redis. I use redis subscribe , but what I wrote is not work . when I run the code , iterm output
listening 8000
GroupChat here
getMsg here
None
None
And I PUBLISH testc helloword in redis-cli, iterm output:
[I 150401 18:30:57 web:1825] 304 GET /groupchat?key=testc (127.0.0.1) 2.40ms
Message(kind=u'message', channel=u'testc', body=u'helloword', pattern=u'testc')
I just want to get the Message in GroupChat.get , but I get None. anyone help me?
GroupChat code is here :
class GroupChat(tornado.web.RequestHandler):
def initialize(self):
print 'GroupChat here'
self.c = tornadoredis.Client(host=CONFIG['REDIS_HOST'], port=CONFIG['REDIS_PORT'], password=CONFIG['REDIS_AUTH'])
self.channelMsgModel = channelMsgModel(self.c)
#tornado.gen.coroutine
def get(self):
try:
key = self.get_argument('key')
info = yield self.channelMsgModel.getMsg(key)
print info
self.finish(info)
except Exception, e:
print e
pass
channelMsgModel code is here :
import tornado.gen
class channelMsgModel :
timeout = 10
def __init__(self, redisobj):
self.redisobj = redisobj
#tornado.gen.coroutine
def getMsg(self, key):
print 'getMsg here'
yield tornado.gen.Task(self.redisobj.subscribe, key)
info = self.redisobj.listen(self.on_message)
print info
raise tornado.gen.Return(info)
def on_message(self, msg):
if (msg.kind == 'message'):
print msg
return msg
elif (msg.kind == 'unsubscribe'):
self.redisobj.disconnect()
# raise tornado.gen.Return(False)
Use a toro.Queue (which will be included in Tornado itself in the upcoming version 4.2):
class channelMsgModel:
def __init__(self, redisobj):
self.redisobj = redisobj
self.queue = toro.Queue()
#gen.coroutine
def getMsg(self, key):
yield gen.Task(self.redisobj.subscribe, key)
self.redisobj.listen(self.on_message)
info = yield self.queue.get()
raise tornado.gen.Return(info)
def on_message(self, msg):
if (msg.kind == 'message'):
self.queue.put_nowait(msg)
elif (msg.kind == 'unsubscribe'):
self.redisobj.disconnect()