Basic GPG operations over HTTP with simple group/alias management, i.e. GPG as a service
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.bundle
lib
.gitignore
Gemfile
Gemfile.lock
LICENSE
README.md
README.md.erb
Rakefile
app.rb
config.ru
demo.gif
heroku.yml
licensezero.json
test.sh

README.md

What is it?

Basic GPG operations over HTTP. Main useful feature in my opinion is group/alias management. It's possible to create various groups of identities like dev, ops, frontend, backend, etc. and then have messages encrypted for the entire group without having to spell out every identity in the group.

demo

Why is it?

Managing keys and messages among a set of people can sometimes be tricky. Centralizing the place that the keys are stored simplifies the process of encrypting messages for a group of people and distributing the encrypted messages.

Note that only public keys are stored on the server running the service. Users will still need to download and decrypt the messages themselves and the messages expire after an hour. The default expiration period can be changed in app.rb.

How to run?

For local testing purposes

$ bundle
$ bundle exec rackup

For production deployments get in touch (artisan@cloudbootup.com) and I'm happy to help out.

Tutorial

NOTE: This is just for demonstrating how to use the endpoints. In a production environment you would have to run this behind a reverse proxy with SSL. Sending cleartext messages over an unencrypted channel defeats the whole purpose of encrypting the messages.

There are only 4 endpoints: /key, /group, /encrypt, /message. It's designed for a very basic workflow of importing some keys, encrypting some messages for a set of recipients, and distributing the locations of encrypted messages to the recipients so they can download the encrypted messages. Groups/aliases are a slightly more advanced use case so I'll go over it in the API section.

To import a key or a set of keys you'll have to get the public keys from somewhere. For demonstration purposes I'm just going to export and import my own GPG keyring

$ gpg --export --armor > keys
$ curl -XPOST --data-binary @keys localhost:9292/key
output: gpg: key E8635C82032C50EE: "keybase.io/davidk01 <davidk01@keybase.io>" not changed
gpg: Total number processed: 1
gpg:              unchanged: 1

status: pid 8951 exit 0

The above indicates that we successfully imported whatever keys we wanted to import. In a production setting you'd run the server somewhere where other people could access it for uploading their own keys.

Now that there are keys we can start encrypting messages

$ curl -XPOST --data 'test message' localhost:9292/encrypt/davidk01@keybase.io,davidk01@keybase.io
{
  "operation": "encrypt",
  "output": [
    {
      "recipient": "davidk01@keybase.io",
      "message": "8f8868e1f346c9b6cf16a79dce6040b27c3a2a325b1ca39c8ed920dcd6c82c28",
      "status": "pid 2512 exit 0"
    },
    {
      "recipient": "davidk01@keybase.io",
      "message": "8f8868e1f346c9b6cf16a79dce6040b27c3a2a325b1ca39c8ed920dcd6c82c28",
      "status": "pid 2516 exit 0"
    }
  ]
}

NOTE: If you want to encrypt a file then you can use --data-binary @message instead of --data 'message'

The list of recipients for encryption is a comma separated URL component. In this case I just supplied myself as a recipient twice. The important part is the message hash. That's what we need to retrieve the message

$ curl localhost:9292/message/8f8868e1f346c9b6cf16a79dce6040b27c3a2a325b1ca39c8ed920dcd6c82c28
-----BEGIN PGP MESSAGE-----

hQEMA+p0RUDeWCZzAQf+LYdMoqs24HJ+rfnvgl7fGy9L30vzHTKO0OpTB/2quXny
D3Ofer1h9PEWFSn1W0SUfr3kVexFhYMnFSN21v6AK/tUJYzFgrA9G9BGssygucPS
QnyDsMPwUYALw3nBbry69KncZ6yomFU9oEHnJyDqMSq5tdWoBtlKT5Uvm1wc/UJB
cFwZOqIAbz3LK1BfeD9MZrRV/mmrnrlwb/L1Bw5wDTkhJjyYJL5T2uRs2SvDGiDJ
mOhggJIA/9500uYoJog8HVdKtNvk+yv/mbGnKpzyOu4UT3XUbFjYBPqjcW5Cb/lT
xcL6Rmf0nbiwW/43rLMGHGKU4bbl+Gy2PUh2S0/wf9JhAWioORipmyPzhUtc+pq4
3Tx4fRFEvav0au+Is2yfXZrRRekbQmXqIsIP0tHEA9kONGswRRE1EjMKMwoTigm4
vm4aQEcOXNOwx6bS0delX2CeBEMFMrCnC2wUWRuT6eRoDQ==
=7Pt4
-----END PGP MESSAGE-----

That message was encrypted for me so I can decrypt it and verify everything is working as expected

$ gpg2 -d
-----BEGIN PGP MESSAGE-----

hQEMA+p0RUDeWCZzAQf+LYdMoqs24HJ+rfnvgl7fGy9L30vzHTKO0OpTB/2quXny
D3Ofer1h9PEWFSn1W0SUfr3kVexFhYMnFSN21v6AK/tUJYzFgrA9G9BGssygucPS
QnyDsMPwUYALw3nBbry69KncZ6yomFU9oEHnJyDqMSq5tdWoBtlKT5Uvm1wc/UJB
cFwZOqIAbz3LK1BfeD9MZrRV/mmrnrlwb/L1Bw5wDTkhJjyYJL5T2uRs2SvDGiDJ
mOhggJIA/9500uYoJog8HVdKtNvk+yv/mbGnKpzyOu4UT3XUbFjYBPqjcW5Cb/lT
xcL6Rmf0nbiwW/43rLMGHGKU4bbl+Gy2PUh2S0/wf9JhAWioORipmyPzhUtc+pq4
3Tx4fRFEvav0au+Is2yfXZrRRekbQmXqIsIP0tHEA9kONGswRRE1EjMKMwoTigm4
vm4aQEcOXNOwx6bS0delX2CeBEMFMrCnC2wUWRuT6eRoDQ==
=7Pt4
gpg: encrypted with 2048-bit RSA key, ID EA744540DE582673, created 2014-05-24
      "keybase.io/davidk01 <davidk01@keybase.io>"
test message

API

Above tutorial only covered the most basic use case. Below is a more thorough overview of the endpoints with example commands and outputs.

/key

Importing keys

$ gpg2 --export --armor > key
$ curl -XPOST --data-binary @key localhost:9292/key
gpg: key E8635C82032C50EE: "keybase.io/davidk01 <davidk01@keybase.io>" not changed
gpg: key 65D722E36D954637: "Cool Dev <cool.dev@coolco.com>" not changed
gpg: Total number processed: 2
gpg:              unchanged: 2

Listing specific keys

$ curl localhost:9292/key/davidk01@keybase.io
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBFOAHFEBEADWRv5hT0/1vJDAJNzMT/27O+3jeVaxIAGtnCqDnzCWqZ00zp4T
iBC+bS+Zy2CpQKbvu7nqM2m2kANb0mtLnUIMqVJ6hGe7ge26HsnePH0F6EQr50QE
...
xjhbujeBktEu5eNZivok685K2ZdjV3DOEIX+IGr8Kzndx+7Tmk3RGSU=
=TO6L
-----END PGP PUBLIC KEY BLOCK-----
$ curl localhost:9292/key/cool.dev@coolco.com
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQGNBFvT6eQBDAC5zTHjcFkw0Tbw7o/+nYF4AnmFo/Lb+KwtsRh+mtZTSUysB7BN
86/Hxe6ibhDd1yhdTpExXQJrkx5UWv9FGZ65d2Bih1Y4IZd/N6u6NHWcsLZvPAAb
...
yPjCUKDn81xV1rVmSxPLVo4mtvVS4g==
=Uvzy
-----END PGP PUBLIC KEY BLOCK-----

Listing all keys

$ curl localhost:9292/key
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBFOAHFEBEADWRv5hT0/1vJDAJNzMT/27O+3jeVaxIAGtnCqDnzCWqZ00zp4T
iBC+bS+Zy2CpQKbvu7nqM2m2kANb0mtLnUIMqVJ6hGe7ge26HsnePH0F6EQr50QE
...
XFXWtWZLE8tWjia29VLi
=pQ3Y
-----END PGP PUBLIC KEY BLOCK-----

/group

Creating groups

$ curl -XPOST -d davidk01@keybase.io localhost:9292/group/one
{
  "operation": "group",
  "group": "7692c3ad3540bb803c020b3aee66cd8887123234ea0c6e7143c0add73ff431ed",
  "identities": [
    "davidk01@keybase.io"
  ]
}
$ curl -XPOST -d cool.dev@coolco.com localhost:9292/group/two
{
  "operation": "group",
  "group": "3fc4ccfe745870e2c0d99f71f30ff0656c8dedd41cc1d7d3d376b0dbe685e2f3",
  "identities": [
    "cool.dev@coolco.com"
  ]
}

Modifying groups

$ curl -XPATCH -d cool.dev@coolco.com localhost:9292/group/one
{
  "operation": "group",
  "identities": [
    "cool.dev@coolco.com"
  ]
}
$ curl -XPATCH -d davidk01@keybase.io localhost:9292/group/two
{
  "operation": "group",
  "identities": [
    "davidk01@keybase.io"
  ]
}

Listing specific groups

$ curl localhost:9292/group/one
{
  "operation": "group",
  "groups": {
    "one": [
      "davidk01@keybase.io",
      "cool.dev@coolco.com"
    ]
  }
}
$ curl localhost:9292/group/two
{
  "operation": "group",
  "groups": {
    "two": [
      "cool.dev@coolco.com",
      "davidk01@keybase.io"
    ]
  }
}

Listing all groups

$ curl localhost:9292/group
{
  "operation": "group",
  "groups": {
    "two": [
      "cool.dev@coolco.com",
      "davidk01@keybase.io"
    ],
    "one": [
      "davidk01@keybase.io",
      "cool.dev@coolco.com"
    ],
    "cool": [
      "davidk01@keybase.io",
      "cool.dev@coolco.com"
    ]
  }
}

Deleting specific groups

$ curl -XDELETE localhost:9292/group/one
{
  "operation": "group",
  "deleted": "one"
}
$ curl -XDELETE localhost:9292/group/two
{
  "operation": "group",
  "deleted": "two"
}

/encrypt

Encrypting messages for users

$ curl -XPOST -d 'test' localhost:9292/encrypt/davidk01@keybase.io
{
  "operation": "encrypt",
  "output": {
    "davidk01@keybase.io": {
      "message": "12782af985860670b81458ad6c11778d9f63ae5be25753c1c1b0a888f4c8075d",
      "status": 0
    }
  }
}
$ curl -XPOST -d 'test' localhost:9292/encrypt/cool.dev@coolco.com
{
  "operation": "encrypt",
  "output": {
    "cool.dev@coolco.com": {
      "message": "dbbeb892217a3e7e5cb134fd5b12d35fbf0599b9b084cd193413290c7f6ee985",
      "status": 0
    }
  }
}
$ curl -XPOST -d 'test' localhost:9292/encrypt/davidk01@keybase.io,cool.dev@coolco.com
{
  "operation": "encrypt",
  "output": {
    "davidk01@keybase.io": {
      "message": "12782af985860670b81458ad6c11778d9f63ae5be25753c1c1b0a888f4c8075d",
      "status": 0
    },
    "cool.dev@coolco.com": {
      "message": "dbbeb892217a3e7e5cb134fd5b12d35fbf0599b9b084cd193413290c7f6ee985",
      "status": 0
    }
  }
}

Encrypting messages for groups

$ curl -XPOST -d 'test' localhost:9292/encrypt/one
{
  "operation": "encrypt",
  "output": {
    "davidk01@keybase.io": {
      "message": "12782af985860670b81458ad6c11778d9f63ae5be25753c1c1b0a888f4c8075d",
      "status": 0
    },
    "cool.dev@coolco.com": {
      "message": "dbbeb892217a3e7e5cb134fd5b12d35fbf0599b9b084cd193413290c7f6ee985",
      "status": 0
    }
  }
}
$ curl -XPOST -d 'test' localhost:9292/encrypt/two
{
  "operation": "encrypt",
  "output": {
    "cool.dev@coolco.com": {
      "message": "dbbeb892217a3e7e5cb134fd5b12d35fbf0599b9b084cd193413290c7f6ee985",
      "status": 0
    },
    "davidk01@keybase.io": {
      "message": "12782af985860670b81458ad6c11778d9f63ae5be25753c1c1b0a888f4c8075d",
      "status": 0
    }
  }
}
$ curl -XPOST -d 'test' localhost:9292/encrypt/one,two
{
  "operation": "encrypt",
  "output": {
    "davidk01@keybase.io": {
      "message": "12782af985860670b81458ad6c11778d9f63ae5be25753c1c1b0a888f4c8075d",
      "status": 0
    },
    "cool.dev@coolco.com": {
      "message": "dbbeb892217a3e7e5cb134fd5b12d35fbf0599b9b084cd193413290c7f6ee985",
      "status": 0
    }
  }
}

Encrypting messages for users and groups

$ curl -XPOST -d 'test' localhost:9292/encrypt/davidk01@keybase.io,two
{
  "operation": "encrypt",
  "output": {
    "davidk01@keybase.io": {
      "message": "12782af985860670b81458ad6c11778d9f63ae5be25753c1c1b0a888f4c8075d",
      "status": 0
    },
    "cool.dev@coolco.com": {
      "message": "dbbeb892217a3e7e5cb134fd5b12d35fbf0599b9b084cd193413290c7f6ee985",
      "status": 0
    }
  }
}
$ curl -XPOST -d 'test' localhost:9292/encrypt/cool.dev@coolco.com,one
{
  "operation": "encrypt",
  "output": {
    "cool.dev@coolco.com": {
      "message": "dbbeb892217a3e7e5cb134fd5b12d35fbf0599b9b084cd193413290c7f6ee985",
      "status": 0
    },
    "davidk01@keybase.io": {
      "message": "12782af985860670b81458ad6c11778d9f63ae5be25753c1c1b0a888f4c8075d",
      "status": 0
    }
  }
}

/message

Getting messages

$ curl localhost:9292/message/12782af985860670b81458ad6c11778d9f63ae5be25753c1c1b0a888f4c8075d
-----BEGIN PGP MESSAGE-----

hQEMA+p0RUDeWCZzAQf+J1+xPCPikXCiL9N6eEiw18uV6yBqnAIaDwleHIQ5zaJR
S3wuM5MGZsT41N280VEgEMmdiStKQRmEnUXGhtLP8XH6i16/6QNOgLWDMzRN1ZcG
W7ibXRP8Lgok8QVcqv/DU+9rMF/xPFIATkSb0s7p1HIp0+chkMYyV3y3ORiP1BR/
nh4OgVcp62b43pFjB0uTZkp9sImJmxs5rTLWroJAvI4dX892sdO+8Q+T6uTZijDS
he9/dJqtenCt4BMM3+54GJl5I6y99JxzT2IHt9J/j8SR7bLCTSmwJ93B+OjjB+ds
gW7rQuBBV+0sgqR5bIR7ySN5AGpM8fUBcuDzoC/VgtI5AaQz+ruorUpZFw1Dozu1
bBY2K3p7FjBFyV9Ij+YtGzJG6U4Vs4vYDITNd4gbkorTvBhnMXd6AZee
=pDQz
-----END PGP MESSAGE-----
$ curl localhost:9292/message/dbbeb892217a3e7e5cb134fd5b12d35fbf0599b9b084cd193413290c7f6ee985
-----BEGIN PGP MESSAGE-----

hQGMA1GQsEyblqsIAQwAmIDioqReEbft/CApAqdWGUzDsR6QvEXWh+BKO4Ev1qTn
Oxb2YZOIBtI+eE6OEq+uYp2tqFKWxDJ6pNTBDyg6LxcGaUMZrEalDesGpkIASXhs
CUXiqYRPj70PHbVKQbE8Adgxnp7AXhEcEUxeTOiIWdcglIe4Pw2lqLY6y5obSp2Y
/aKtDThhtqGB2qiA+HT0cXLnetvfv3uOG/B5FCf5iVJ6bVLky2D+QcOUyVmxebw6
cq41vs216zu/6cDY1/xYoOA1luYVjYpzAnuPAYsNmQPp0Uk6flxHzPrl4gUfgtoi
pk9b7LqqSTsSOAZ5ID1Uf01TOQ/fKm+JRY1sIuIQg3vYIEylg+pM2rs8eH2F37LT
2svlYHXGjCbGSGn54d+VBnDBX/v0y7upY4Wj38MhZlftO2oFKB77h9eMydbJaFBt
z8Tlb/SviTQhtx7uPMabhZuEs+LGiLXqjcHmgOoPWwc1insV9niCLMb9XPC/TaIc
YHsvBjebTzDi0HsklWrY0j8B01oxa0ZL48ieMebE032FCung9J1njIevPPZ5wFLb
tSAUBQba9LdJ0djftTHmjACEP2LIRJaouU0JESP3AWw=
=ATMk
-----END PGP MESSAGE-----

Deleting messages

$ curl -XDELETE localhost:9292/message/12782af985860670b81458ad6c11778d9f63ae5be25753c1c1b0a888f4c8075d
12782af985860670b81458ad6c11778d9f63ae5be25753c1c1b0a888f4c8075d
$ curl -XDELETE localhost:9292/message/dbbeb892217a3e7e5cb134fd5b12d35fbf0599b9b084cd193413290c7f6ee985
dbbeb892217a3e7e5cb134fd5b12d35fbf0599b9b084cd193413290c7f6ee985