Sunday, 12 October 2014

Private Key for Digital Signature, KeyStore, PKCS#12

The following demonstrates the use of the Java security API to digitally sign a document.
Before we get to the Scala code, we must first use Java's keytool to create a self-signed certificate.
In real-life, you'd probably buy one from Verisign for example. The archive file format chosen is PKCS12.
keytool -genkey
        -alias tj
        -keystore mykeystore
        -storepass storepass
        -validity 365
        -keyalg RSA
        -keysize 2048
        -storetype pkcs12
Once you have answered the questions, you can list the aliases using the following command:
keytool -keystore mykeystore 
        -storepass storepass 
        -storetype pkcs12
Should output:
Keystore type: PKCS12
Keystore provider: SunJSSE

Your keystore contains 1 entry

tj, Oct 12, 2014, PrivateKeyEntry,
Certificate fingerprint (SHA1): 52:6B:0D:05:9E:CE:5A:CA:5E:EF:74:C9:51:FE:46:8D:E6:CE:4F:11
Let's get to the coding part. We will extract the private key from the store to digitally sign a document. I usually first create a digest from the initial document and store this digest as base 64. But there is no need for this step.
  def createDigest(legalDocument: String): Array[Byte] = {
    val md = MessageDigest.getInstance("SHA-256")
to be called like this:
val alias = "tj"
val password = "storepass".toCharArray
val legalDoc = createDigest("This is a legal document I must digitally sign")
legalDoc is an array of bytes - it contains a SHA-256 digest from the initial document.

The code to list the keystore entries, just to make sure we are on the right path:
  def listStoreEntries(password: Array[Char]): KeyStore = {
    val keyStoreDefaultType = KeyStore.getDefaultType
    val keyStore = KeyStore.getInstance("pkcs12")
    keyStore.load(new FileInputStream("mykeystore"), password)

    val aliases = keyStore.aliases()
    while(aliases.hasMoreElements) {
      val alias = aliases.nextElement()
      log(s" Alias: $alias")

listStoreEntries returns the initialized keystore. Let's now sign the legal document and return a base 64 encoded digital signature:
  def signLegalDocument(keystore: KeyStore, alias: String, password: Array[Char], legalDoc: Array[Byte]): String = {
    val privateKey = keystore.getKey(alias, password)
    val dsig = Signature.getInstance("MD5withRSA")
    val signature = dsig.sign()
And the code to verify the signature:
  def verifyDigitalSignature(keystore: KeyStore, alias: String, legalDoc: Array[Byte], signature: String): Unit = {
    val certificate = keystore.getCertificate(alias)
    val x509Certificate = certificate.asInstanceOf[X509Certificate]
    val publicKey = x509Certificate.getPublicKey
    val dsig = Signature.getInstance("MD5withRSA")

    val sig = Base64.getDecoder.decode(signature)
    val verifiedSig = dsig.verify(sig)
    log(s"Has the legal document signature successfully been verified? $verifiedSig")
    require(verifiedSig == true)
The whole main method:
  def main(args: Array[String]) {
    val alias = "tj"
    val password = "storepass".toCharArray
    val legalDoc = createDigest("This is a legal document I must digitally sign")
    val keyStore = listStoreEntries(password)

    val signature = signLegalDocument(keyStore, alias, password, legalDoc)
    verifyDigitalSignature(keyStore, alias, legalDoc, signature)

  def log(ref: Any) = println(ref)
How do I import my self-signed certificate into Windows cert manager?
Just rename the keystore from mykeystore to mykeystore.pfx On Windows, simple double-click on it and follow the instructions.
Open certmgr.msc via the run command or from a DOS console - under Certificates - Currrent User, Personal, Certificates you should see your previously create certificate using Java's keytool.

No comments:

Blog Archive