0.0
Low commit activity in last 3 years
No release in over a year
Group end to end encryption for self
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

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