ECDSA signatures with node.js and Swift
Tags: swift, node, elipticcurve, macos
Published: 2019-12-05 03:29:34

---
title: ECDSA signatures with node.js and Swift
published: true
date: 2019-11-19 21:41:24 UTC
tags: Swift,NodeJS,ElipticCurve,macOS
canonical_url: 
---

In the process of de-risking some business model questions for [Digamo](https://dev.to/_danilo/post-mortem-digamo-beta-20ma-temp-slug-7148590), I went looking for an open source project that would allow us to generate and verify license keys. We’re not sure what our business model will be there, but understanding the technical costs of licensing is important to making decisions.

While this is a problem that [has](https://github.com/bdrister/AquaticPrime) been [solved](https://github.com/vslavik/ellipticlicense), I didn’t find anything especially modern, well-maintained, or documented—and nothing in Swift or Node, the stuff I’m using for everything else right now.

Some research did suggest that asymmetric cryptography was the way to go, using a private key to sign a registration string, and a public key distributed with the app to verify the signature. This was also the approach used in the older projects that tried to solve this problem for Mac apps.

Still, I found precious little documentation or tutorials to walk me through the implementation. All the signing examples took place within the same context, rather than between client and server. Here’s an approach that appears to be working, using Node and a Swift Mac app.

## Try the demo

Generate a signed message file here: [https://eccsign-server.glitch.me](https://eccsign-server.glitch.me)

Download, build and run the macOS verification app here: [https://github.com/daniloc/eccsignaturetest](https://github.com/daniloc/eccsignaturetest)

Once the app is running, you can double-click the signed message files from the Glitch app to automatically load them. File free to tamper with the content of the `plaintext` field by opening a file in your favorite text editor, then try to verify again. Tampering should cause the verification step to fail.

The public and private keys are included for your inspection and experimentation, as a “known-good” configuration. **In your own projects you should use care to ensure your private key is not distributed.**

## Generate encryption keys

Per [the instructions from IBM’s BlueECC project](https://developer.ibm.com/swift/2019/03/04/blueecc-elliptic-curve-cryptography/), here’s how you get started:

On macOS you can install OpenSSL using `brew`:

`brew install openssl`

Once you have installed OpenSSL, create your private key:

`openssl ecparam -name prime256v1 -genkey -noout -out ec256priv.pem`

Using the private key, create your public key:

`openssl ec -in ec256priv.pem -pubout -out ec256pub.pem`

It seems you want to use the `prime256v1` curve—other algorithms have some cross-platform issues.

This will leave you with a private and public key. The private key goes on your server to generate signatures. The public key can be distributed with your app to verify those signatures.

## Signing with Node.js

The npm module `EC-Key` will make it easy to load your key:

`let ECKey = require("ec-key");`

`let pem = fs.readFileSync("./privatekey.pem"); let eccPrivateKey = new ECKey(pem, "pem")`

Here my implementation gets a little clunky—there may be better ways to do this, but at least it seems pretty flexible. Create a JavaScript object with whatever keys and content you want:

`var objectToSign = {} objectToSign.message = message let date = new Date().toJSON() objectToSign.date = date`

Convert that into a JSON string:

`let outputString = JSON.stringify(objectToSign)`

Then, create a signature from that string:

`let signature = eccPrivateKey.createSign("SHA256").update(outputString).sign("base64")`

And pack the plaintext string and signature into a second object:

`let outputObject = {} outputObject.plaintext = outputString outputObject.signatureBase64 = signature`

You can then convert the output to JSON and have the user download the file.

See the whole thing in action with [this Glitch project](https://glitch.com/edit/#!/eccsign-server).

## Verification in Swift

Add the BlueECC package to your project. Install [manually](https://github.com/IBM-Swift/BlueECC), or use the Swift Package Manager. In Xcode, choose **File \> Swift Packages \> Add Package Dependency…**

![](https://frisco-uplink.com/wp-content/uploads/2019/11/Screen-Shot-2019-11-19-at-4.10.26-PM.png)

Search for “CryptorECC,” and pick “BlueECC.”

![](https://frisco-uplink.com/wp-content/uploads/2019/11/Screen-Shot-2019-11-19-at-4.12.01-PM.png)

Add your public key file to your project, and `import CryptorECC`  
to the file where you’re working. Then you can grab the public key like this:

`let filepath = Bundle.main.path(forResource: "ec256pub", ofType: "pem")!`

`let keyString = try? String(contentsOfFile: filepath)`

`let publicKey = try ECPublicKey(key: keyString)`

With the public key loaded from your bundle into memory, you can now verify a signature with it:

`let signature = try ECSignature(asn1: Data(base64Encoded: signatureBase64)!)`

(`signatureBase64` is the output from `createSign()` above)

`let verified = signature.verify(plaintext: plaintext, using: publicKey)`

The constant `verified` will tell you if the plaintext and signature match.

Here’s a [Mac app](https://github.com/daniloc/eccsignaturetest) you can build and run to see this in action.

## Feedback

Is this a good approach? See anywhere it could work better? Drop me a line.