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
-list
-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:11Let'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")
md.update(legalDocument.getBytes)
md.digest()
}
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")
}
keyStore
}
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")
dsig.initSign(privateKey.asInstanceOf[PrivateKey])
dsig.update(legalDoc)
val signature = dsig.sign()
Base64.getEncoder.encodeToString(signature)
}
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")
dsig.initVerify(publicKey)
val sig = Base64.getDecoder.decode(signature)
dsig.update(legalDoc)
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:
Post a Comment