class SelfSDK::Crypto
Public Class Methods
new(client, device, storage_folder, storage_key)
click to toggle source
# File lib/crypto.rb, line 7 def initialize(client, device, storage_folder, storage_key) @client = client @device = device @storage_key = storage_key @storage_folder = "#{storage_folder}/#{@client.jwt.key_id}" if File.exist?(account_path) # 1a) if alice's account file exists load the pickle from the file @account = SelfCrypto::Account.from_pickle(File.read(account_path), @storage_key) else # 1b-i) if create a new account for alice if one doesn't exist already @account = SelfCrypto::Account.from_seed(@client.jwt.key) # 1b-ii) generate some keys for alice and publish them @account.gen_otk(100) # 1b-iii) convert those keys to json keys = @account.otk['curve25519'].map{|k,v| {id: k, key: v}}.to_json # 1b-iv) post those keys to POST /v1/identities/<selfid>/devices/1/pre_keys/ res = @client.post("/v1/apps/#{@client.jwt.id}/devices/#{@device}/pre_keys", keys) raise 'unable to push prekeys, please try in a few minutes' if res.code != 200 # 1b-v) store the account to a file File.write(account_path, @account.to_pickle(storage_key)) end end
Public Instance Methods
decrypt(message, sender, sender_device)
click to toggle source
# File lib/crypto.rb, line 79 def decrypt(message, sender, sender_device) session_file_name = session_path(sender, sender_device) if File.exist?(session_file_name) # 7a) if carol's session file exists load the pickle from the file session_with_bob = SelfCrypto::Session.from_pickle(File.read(session_file_name), @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 = SelfCrypto::GroupMessage.new(message.to_s).get_message("#{@client.jwt.id}:#{@device}") # 7b-ii) use the initial message to create a session for bob or carol session_with_bob = @account.inbound_session(m) # 7b-iii) remove the session's prekey from the account @account.remove_one_time_keys(session_with_bob) current_one_time_keys = @account.otk['curve25519'] # 7b-iv) if the number of remaining prekeys is below a certain threshold, publish new keys if current_one_time_keys.length < 10 @account.gen_otk(100) keys = Array.new @account.otk['curve25519'].each do |k,v| keys.push({id: k, key: v}) if current_one_time_keys[k].nil? end res = @client.post("/v1/apps/#{@client.jwt.id}/devices/#{@device}/pre_keys", keys.to_json) raise 'unable to push prekeys, please try in a few minutes' if res.code != 200 end File.write(account_path, @account.to_pickle(@storage_key)) end # 8) create a group session and set the identity of the account you're using gs = SelfCrypto::GroupSession.new("#{@client.jwt.id}:#{@device}") # 9) add all recipients and their sessions gs.add_participant("#{sender}:#{sender_device}", session_with_bob) # 10) decrypt the message ciphertext pt = gs.decrypt("#{sender}:#{sender_device}", message).to_s # 11) store the session to a file File.write(session_file_name, session_with_bob.to_pickle(@storage_key)) pt end
encrypt(message, recipient, recipient_device)
click to toggle source
# File lib/crypto.rb, line 35 def encrypt(message, recipient, recipient_device) session_file_name = session_path(recipient, recipient_device) if File.exist?(session_file_name) # 2a) if bob's session file exists load the pickle from the file session_with_bob = SelfCrypto::Session.from_pickle(File.read(session_file_name), @storage_key) else # 2b-i) if you have not previously sent or recevied a message to/from bob, # you must get his identity key from GET /v1/identities/bob/ ed25519_identity_key = @client.device_public_key(recipient, recipient_device) # 2b-ii) get a one time key for bob res = @client.get("/v1/identities/#{recipient}/devices/#{recipient_device}/pre_keys") if res.code != 200 b = JSON.parse(res.body) ::SelfSDK.logger.error "identity response : #{b['message']}" raise "could not get identity pre_keys" end one_time_key = JSON.parse(res.body)["key"] # 2b-iii) convert bobs ed25519 identity key to a curve25519 key curve25519_identity_key = SelfCrypto::Util.ed25519_pk_to_curve25519(ed25519_identity_key.raw_public_key) # 2b-iv) create the session with bob session_with_bob = @account.outbound_session(curve25519_identity_key, one_time_key) end # 3) create a group session and set the identity of the account youre using gs = SelfCrypto::GroupSession.new("#{@client.jwt.id}:#{@device}") # 4) add all recipients and their sessions gs.add_participant("#{recipient}:#{recipient_device}", session_with_bob) # 5) encrypt a message ct = gs.encrypt(message).to_s # 6) store the session to a file File.write(session_file_name, session_with_bob.to_pickle(@storage_key)) ct end
Private Instance Methods
account_path()
click to toggle source
# File lib/crypto.rb, line 133 def account_path "#{@storage_folder}/account.pickle" end
session_path(selfid, device)
click to toggle source
# File lib/crypto.rb, line 137 def session_path(selfid, device) "#{@storage_folder}/#{selfid}:#{device}-session.pickle" end