I’ve been testing my Content-Signature framework discussed earlier and wanted to see if I could exchange digital signatures generated and verified from both Python and Java code. After a bit of research here’s what I’ve found so far on how to do this.
Generate keys with openssl
The first step is to generate a private key and a certificate using the openssl program. This is a common utility. Do a search if it is not available on your computer and you’ll find support and instructions to install on various platforms. It came with my macbook pro (I think maybe with Darwin tools). You’ll have to generate the keys in both .pem format (for Python) and .der format (for Java).
# generate pems $ openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert-private.pem -out mycert.pem # create private key .der file $ openssl pkcs8 -topk8 -nocrypt -in mycert-private.pem -out mycert-private.der -outform der # create certificate .der file $ openssl x509 -in mycert.pem -out mycert.der -outform der
From this you should have 2 sets of files: mycert-private.pem, mycert-private.der and mycert.pem and mycert.der
Import private key sign in Java
Here’s a nice tool for loading in the .der files created into a Java KeyStore. I’ve extracted some of the code so that you can see the whole manual, programmatic process of importing a private key and signing a message.
import org.jboss.resteasy.util.Hex; import java.io.DataInputStream; import java.io.*; import java.security.*; import java.security.cert.*; import java.security.spec.PKCS8EncodedKeySpec; public class ExampleSignTest { @Test public void testDerFile() throws Exception { // import private key InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("mycert-private.der"); DataInputStream dis = new DataInputStream(is); byte[] derFile = new byte[dis.available()]; dis.readFully(derFile); KeyFactory kf = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(derFile); PrivateKey privateKey = kf.generatePrivate(spec); Signature instance = Signature.getInstance("SHA256withRSA"); instance.initSign(privateKey); instance.update("from-java".getBytes()); byte[] signatureBytes = instance.sign(); System.out.println("Signature: "); System.out.println(Hex.encodeHex(signatureBytes)); } }
The code prints out the signature in hex using a simple routine from Resteasy.
Import certificate and verify in Java
Here’s an example of verifying:
@Test public void testDerFile() throws Exception { CertificateFactory cf = CertificateFactory.getInstance("X.509"); is = Thread.currentThread().getContextClassLoader().getResourceAsStream("mycert.der"); Certificate cert = cf.generateCertificate(is); PublicKey publicKey = cert.getPublicKey(); String hexSignature = "4e3014a3a0ff296c07927e846221ee68f70e0b06ed54a1fe974944ea17b836b92279635a7e0bb6b8923df94f4023de95ef07fa76506888897a88ac440eb185b6b117f4c906cba989ffb4e1f81c6677db12e7dc22d51d9369df92165709817792dc3e647dae6b70a0d84c386b0228c2442c9a6a0107381aac8e4cb4c367435d52"; // loading CertificateChain Signature verify = Signature.getInstance("SHA256withRSA"); verify.initVerify(publicKey); verify.update("from-python".getBytes()); Assert.assertTrue(verify.verify(Hex.decodeHex(pythonHexSignature))); }
The code has hardcoded a generated signature produced from signing the “from-python” string.
Import private key and sign in Python
The Python code requires the M2Crypto library. I tried PyCrypto, but I could get it to work. My code was tested on macbook pro with Python 2.6.1 M2Crypto version 0.21.1. Also notice that the .pem files are used instead of .der. I couldn’t figure out if M2Crypto fully supported .der so I just used the .pems.
from M2Crypto import EVP, RSA, X509 import binascii key = EVP.load_key("mycert-private.pem") key.reset_context(md='sha256') key.sign_init() key.sign_update("from-python") signature = key.sign_final() print "Signature:" print binascii.b2a_hex(signature)
Importing certificate and verifying in Python
Here’s the verification:
rom M2Crypto import EVP, RSA, X509 import binascii hexSignature = "0a11ab4ebcd2b0803d6e280a1d45b5b5d5d53688949f5a4f2d6436f15df3b10633c79760b9fe3b64eb9d84371c35e8b7d946052dfdd99ebb5cf7f3092762e1a91b261117e6675f2d28afe2ec4\ d90abfe3559a1259d2c66f3dc42ca3bfce7498705833445170bd8c293d60448b6c599abfe2d06882d3fff9ef887379eb7da3fe0" java_sig = binascii.a2b_hex(hexSignature) cert = X509.load_cert("mycert.pem") pubkey = cert.get_pubkey() pubkey.reset_context(md="sha256") pubkey.verify_init() pubkey.verify_update("from-java") assert pubkey.verify_final(java_sig) == 1
Hope you enjoy. If you know a better way to set up the certs and key files, let me know. Using openssl was the best way I could find.
Mar 10, 2011 @ 15:47:27
If you’re using Java 6, another way to import keys and certificates into a KeyStore is to use openssl to convert the key and certificate into a PKCS12 file. You need to make sure your key and certificate are in PEM format first (which you can do with openssl as well). Once you have the PEM encoded key and certificate, create a PKCS12 file with this command:
openssl pkcs12 -export -in my_cert.pem -inkey my_key.pem -out mybundle.p12
Once you have the PKCS12 file, you can import that as a PKCS12 keystore into a pre-existing keystore with the keytool:
keytool -importkeystore -deststorepass XXX -destkeypass XXX -destkeystore my-keystore.jks -srckeystore mybundle.p12 -srcstoretype PKCS12 -srcstorepass XXX -alias 1 -destalias my_new_keycert_alias
The “-alias 1” flag is essential as it tells the keytool which certificate to pull out of the pkcs12 file – even though there’s only one, keytool is rather dumb about it.
» links for 2011-03-10 (Dhananjay Nene)
Mar 10, 2011 @ 20:01:51
Distributed Weekly 93 — Scott Banwart's Blog
Mar 11, 2011 @ 13:59:22
Apr 04, 2014 @ 18:02:31
If you live in the Bay Are, I’ll buy you coffee. You saved my day here.
This is the line I was missing in my sign verification:
pubkey.reset_context(md=”sha256″)
Instead, I was computing the sh256 digest of the data and feeding it to pub_key.verify_update directly and verify was failing. Not sure why that is the case.
Thanks so much!