Under the hood: Public key login

This blog-post is about a new login method. It’s based on asymetric encryption and will help us to make user-authentication easier in some circumstances.

So what’s the idea? Most people reading this will know about the feature on github, where one can register an ssh-key. That makes working with git more easy, as the user can then automatically login with git, without typing in his password.

It’s even better. The user only needs one key-pair and can use it on many different servers, services etc. without needing to worry that his password gets stolen. Even if github gets hacked or some evil administrator wants to read the password, he doesn’t have a chance. The server only knows the public key.

The user has a key-pair, consisting of a public and a private key. The public key can really be public, everyone can now about. The private key should, under all circumstances, kept private.

So what usecase does this have for loklak? One thing is IoT. We can create a key-pair for a device once and easily give it access to a loklak server without needing to create a new password and store it on the device. All we need is the public key of the device, that we then register on as many loklak servers as we want.

Another idea would be a trust system between loklak instances. If we collaborate with different loklak instances from people we don’t know, key-pairs are a good way to authenticate and remember each other.

How to use?

There’s a new app key registration app where you can either upload an existing public key or let the server create a new key pair for you. The public key is stored on the server while the private key should be saved by the client. The app will also create a key hash, basicly the sha265 hash of the public key in DER format.

The app will display the keys in two different formats:

  • DER+BASE64 (a format that can easily used in java projects)
  • PEM (a format that can be used with openssl

Either way it’s the same key. The idea now is that the client says he wants to login with a certain email and a specific key (he only sends over the key-hash, to save traffic). The server replies with a challenge (just a random string). The client has now to create a valid signature of the challenge with his private key (and send it back to the server). The server verifies the signature and logs the user in (actually he creates an access-token for api-access, as browser logins will usually use a password).

An example:

Client calls:

https://loklak.org/api/login.json?login[email protected]&keyhash=4GV3dPkeQm0XPksr69DKy0LD7ecBOYVX1YN6xTstp9Y=

Server replies:

{
  "session": {"identity": {
    "type": "host",
    "name": "23.120.120.1",
    "anonymous": true
  }},
  "challenge": "dmP4jv9oG7Jor3941BeiQRFzOOUsBA",
  "sessionID": "lAclhJxljT3vnMuFzjDpm6rxzdLd1S",
  "message": "Found valid key for this user. Sign the challenge with you public key and send it back, together with the sessionID"
}

The client calculates the signature:

String challenge = "dmP4jv9oG7Jor3941BeiQRFzOOUsBA";
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(privateKey);
sig.update(challange.getBytes());
result = new String(Base64.getEncoder().encode(sig.sign()));

And sends the answer back:

https://loklak.org/api/login.json?sessionID=lAclhJxljT3vnMuFzjDpm6rxzdLd1S&response=Z0+j17suLN0Ow7U40ZCnZkUrespH3JJpkI/4DL647KQBfz4riRzONphXx1zJaCRaCKUbJ9l6+xyoiOumpwaXZe61jIJpFQ3N0qKjcSruzArV58d2CMPE3MWUvDu4YIYcQrj/ycusMHCTliyRG9O0BHKwZtBQAqHYc4nd3qxnfenOi806+ekfmT3MnbuiooG5NBF8tQGto7DyVCATlSvOngUCGYAeWNZfNr5Xt7EF+fWOIM9spuqV0ms0kS820Tota9+xEq+SS07ER7qR15thhpdysrb/2GojUjMYou7B4Y0ucLGMy6tOk+jl6w7o7TOP7qxcMxeygjKsmbfU6ouN5g==

The server will then response with an access-token.

With openssl, the process should be fundamentally similar:

openssl dgst -sha256 -sign privkey.pem -out response.txt challenge.txt

and then some BASE64 encoding on response.txt.

Currently, only RSA keys (in the sizes 1024, 2048 and 4096) can be registered or created, but in the future we may support eliptic-curve signatures, which would reduce key- and signature sizes and also the needed cpu-time.

Under the hood: Public key login