I'm writing a client in Python2 with the python-crypto API to digitally sign an XML file and I have a service written in Scala that is suppose to verify the signature. My Python code looks something like this:
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA
from os import urandom
import logging
...
...
To generate the keys (keysize is 2048):
self.__key = RSA.generate(self.keySize,urandom)
self.__private_key = self.__key.exportKey()
self.__public_key = self.__key.publickey().exportKey()
with open(pubPath,'w') as fpub:
logging.info("Writing Public Key to %s" % pubPath)
fpub.write(self.__public_key)
with open(priPath,'w') as fpri:
logging.info("Writing Private Key to %s" % priPath)
fpri.write(self.__private_key)
And for reading in the keys:
self.__private_key = fpri.read()
self.__public_key = fpub.read()
self.__key = RSA.importKey(self.__private_key)
And to digitally sign
logging.debug('Data to sign: "%s"' % data)
digest = SHA.new(data.strip()).digest()
return str(self.__key.sign(digest, None)[0])
Then in Scala/Java, I use the following:
package com.example.security
import com.example.action.ActionRequest
import java.io.BufferedInputStream
import java.security.spec.X509EncodedKeySpec
import java.security.KeyFactory
import java.security.PublicKey
import java.security.Signature
import org.apache.log4j.Logger
class SignatureSecurityManageer extends SecurityManagerTrait {
def loadPublicKey() : PublicKey = {
val stream : BufferedInputStream = new BufferedInputStream(this.getClass().getResourceAsStream("/com/example/security/key.der"))
var key = new Array[Byte](stream.available())
stream.read(key)
KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(key))
}
def securityFilter(req : ActionRequest) : Boolean = {
var parts = req.data.split("\n\n")
var log : Logger = Logger.getLogger(this.getClass());
log.trace("Data \"%s\"".format(parts(0)))
log.trace("Sig \"%s\"".format(parts(1)))
var sg = Signature.getInstance("SHA1withRSA");
sg.initVerify(loadPublicKey())
sg.update(parts(0).trim().getBytes())
sg.verify(parts(1).trim().getBytes())
}
}
I transform the PEM public key generated by the client into a binary public key so it can be read by Java:
openssl rsa -in src/com/example/security/key.pub -inform PEM -out src/com/example/security/key.der -outform DER -pubin
In the transport, I separate the XML and the signature with double new lines. I realize trailing whitespace can present problems so I added those strip/trims above and I check the logs and verify that the data is identical:
Python Client:
2012-04-09 14:24:51,089: Data to sign: "<?xml version="1.0" ?><AgraData><package id="Local-Laptop" timestamp="1333945491074"><sensors><sensor id="SUMTEMP001" type="Temperature" units="C"><data>8</data></sensor><sensor id="SUMVOL001" type="Volume" units="l"><data>27</data></sensor><sensor id="SUMFLO001" type="FlowRate" units="l"><data>41.142</data></sensor></sensors></package></AgraData>"
Scala Service:
[2012-04-09 14:24:51,771] com.urbanalta.agrastore.security.SignatureSecurityManageer TRACE - Data "<?xml version="1.0" ?><AgraData><package id="Local-Laptop" timestamp="1333945491074"><sensors><sensor id="SUMTEMP001" type="Temperature" units="C"><data>8</data></sensor><sensor id="SUMVOL001" type="Volume" units="l"><data>27</data></sensor><sensor id="SUMFLO001" type="FlowRate" units="l"><data>41.142</data></sensor></sensors></package></AgraData>"
But within the Scala service, it returns false when I try to verify the signature. I think somewhere I'm not specifying the right signature/key type, but I'm not sure where.
This might be another instance of this submission where it's not just the digest but the AlgorithmIdentifier and the digest that are signed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With