2

我正在尝试使用 Signature API (JSON) 签署一个小缓冲区,作为集成到我的项目中的 POC。我正在使用 CoSign 试用开发者帐户服务器。签名已成功创建,但在尝试验证缓冲区时,响应包含以下(不是很有用)错误:

{u'ErrData': {u'Code': -24,
          u'InnerCode': -1878850959,
          u'Message': u'Failed to verify buffer.',
          u'Module': u'VerifyBuffer'},
 u'Success': False}

我已按照此页面上的文档进行操作:

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

我在 python 中附加我的代码(用户名和密码已删除)

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)

我也尝试使用 BufferHash 参数并自己计算哈希,但发生了同样的错误。

4

3 回答 3

2

感谢 Almog 和 ALX,您的回答有所帮助。不幸的是,我不能赞成你的答案,没有足够的 stackoverflow 声誉。

我已经解决了一些其他细节,例如创建 pkcs#1 签名并验证它。我在这里发布完整的清理源代码以供其他人将来参考。我的结论是,使用 REST API 的源代码示例确实会有所帮助,无论使用哪种语言 - 所以我建议在文档站点的示例页面中的某处编写一个甚至使用我的源代码示例。

再次感谢你的帮助。

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"
于 2015-02-19T10:09:46.187 回答
2

从 signBuffer 函数返回的签名包含 \r\n 字符,在调用 verifyBuffer 之前从签名中删除这些字符应该可以解决问题。

于 2015-02-18T17:30:54.940 回答
2

要使代码正常运行,您需要做的就是:

  1. 将您预定义的请求标头传递给请求本身-

    urllib2.Request(url, json.dumps(message), self.HEADERS)
    
  2. 请注意,返回的签名的 base64 编码数据包含多余的 \r\n 字符(这是一个已知问题,将在以后的版本中修复)。只需在将数据传递给验证操作之前删除这些字符。例如-

    client.verifyBytes(value, response1[u'Data'][u'Signature'].replace("\r\n", ""))
    
于 2015-02-18T17:41:33.223 回答