Skip to content

joinself/self-crypto-ruby

Repository files navigation

Self Crypto Ruby

Build Status

Provides end to end group encryption using self-olm and self-omemo

Installation

This gem requires Self's fork of OLM (self-olm) and OMEMO (self-omemo) to be available before installing.

The gem name is 'self_crypto'. The target needs to be able to build native extensions.

Once installed, require as:

require 'self_crypto'

If using locally (i.e. you check out this repository) you may need to manually compile and clean the extensions like this:

bundle exec rake compile
bundle exec rake clean

Characteristics

  • Interfaces are not thread safe
  • OLM always encodes binary as base64
  • Account is unlikely to scale for a large number of one-time-keys

Example

Setup alice's account:

require 'file'
require 'self_crypto'

include SelfCrypto

# Setup alices account. This should be stored in memory for all communications

if File.exist?('account.pickle')
  # 1a) if alice's account file exists load the pickle from the file
  alice = Account.from_pickle(File.read('account.pickle'), STORAGE_KEY)
else
  # 1b-i) if create a new account for alice if one doesn't exist already
  alice = Account.from_seed(ALICES_IDENTITY_KEY)

  # 1b-ii) generate some keys for alice and publish them
  alice.gen_otk(100)

  # 1b-iii) convert those keys to json
  keys = alice.otk['curve25519'].map{|k,v| {id: k, type: v}}.to_json

  # 1b-iv) post those keys to POST /v1/identities/alice/devices/1/pre_keys/
  post('/v1/identities/alice/devices/1/pre_keys', keys)

  # 1b-v) store the account to a file
  File.write('account.pickle', alice.to_pickle(STORAGE_KEY))
end

Send a message from alice to bob:

# Send a message to bob:1

if File.exist?('bob:1-session.pickle')
  # 2a) if bob's session file exists load the pickle from the file
  session_with_bob = Session.from_pickle(File.read('bob:1-session.pickle'), STORAGE_KEY)
else
  # 2b-i) if you have not previously sent or received a message to/from bob,
  #       you must get his identity key from GET /v1/identities/bob/
  ed25519_identity_key = JSON.parse(get('/v1/identities/bob/public_keys/')).first['key']

  # 2b-ii) get a one time key for bob
  one_time_key = JSON.parse(get('/v1/identities/bob/devices/1/pre_key'))['key']

  # 2b-iii) convert bobs ed25519 identity key to a curve25519 key
  curve25519_identity_key = Util.ed25519_pk_to_curve25519(ed25519_identity_key)

  # 2b-iv) create the session with bob
  session_with_bob = alice.outbound_session(curve25519_identity_key, one_time_key)

  # 2b-v) store the session to a file
  File.write('bob:1-session.pickle', session_with_bob.to_pickle(STORAGE_KEY))
end

# 3) create a group session and set the identity of the account youre using
ags = GroupSession.new('alice:1')

# 4) add all recipients and their sessions
ags.add_participant('bob:1', session_with_bob)

# 5) encrypt a message
ct = ags.encrypt('hello')

# 6) do something with the message
puts ct.to_s

Receive a message from carol:

# Receive a message from carol:1

ct = "json encoded group message..."

if File.exist?('carol:1-session.pickle')
  # 7a) if carol's session file exists load the pickle from the file
  session_with_carol = Session.from_pickle(File.read('carol:1-session.pickle'), STORAGE_KEY)
else
  # 7b-i) if you have not previously sent or received a message to/from bob,
  #       you should extract the initial message from the group message intended
  #       for your account id.
  m = GroupMessage.new(ct.to_s).get_message('alice:1')

  # 7b-ii) use the initial message to create a session for carol
  session_with_carol = alice.inbound_session(m)

  # 7b-iii) store the session to a file
  File.write('carol:1-session.pickle', session_with_carol.to_pickle(STORAGE_KEY))
end

# 8) create a group session and set the identity of the account you're using
ags = GroupSession.new('alice:1')

# 9) add all recipients and their sessions
ags.add_participant('carol:1', session_with_carol)

# 10) decrypt the message ciphertext
pt = bgs.decrypt("alice:1", ct)

# 11) do something with the message
puts ct.to_s

Running Tests

bundle exec rake test

What is an Olm?

https://en.wikipedia.org/wiki/Olm.

License

Apache 2.0