lime
Lime is a C++ library implementing Open Whisper System Signal protocol
lime.hpp
Go to the documentation of this file.
1 /*
2  lime.hpp
3  @author Johan Pascal
4  @copyright Copyright (C) 2017 Belledonne Communications SARL
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #ifndef lime_hpp
20 #define lime_hpp
21 
22 #include <memory> //smart ptrs
23 #include <unordered_map>
24 #include <map>
25 #include <vector>
26 #include <list>
27 #include <functional>
28 #include <string>
29 #include <mutex>
30 #include <ostream>
31 
32 namespace lime {
33 
37  enum class CurveId : uint8_t {
38  unset=0,
39  c25519=1,
40  c448=2,
41  c25519k512=3,
42  c25519mlk512=4,
43  c448mlk1024=5,
44  };
45 
47  enum class EncryptionPolicy {
48  DRMessage,
52  };
53 
59  enum class PeerDeviceStatus : uint8_t {
60  untrusted=0,
61  trusted=1,
62  unsafe=2,
63  fail,
65  unknown
67  };
68 
73  struct RecipientData {
74  const std::string deviceId;
81  std::vector<uint8_t> DRmessage;
82  bool done;
87  RecipientData(const std::string &deviceId) : deviceId{deviceId}, peerStatus{lime::PeerDeviceStatus::unknown}, DRmessage{}, done(false) {};
88  void dump(std::ostringstream &os, std::string indent=" ") const;
89  };
90 
92  enum class CallbackReturn : uint8_t {
93  success,
94  fail
95  };
103  using limeCallback = std::function<void(const lime::CallbackReturn status, const std::string message)>;
104 
105  /* X3DH server communication : these functions prototypes are used to post data and get response from/to the X3DH server */
113  using limeX3DHServerResponseProcess = std::function<void(int responseCode, const std::vector<uint8_t> &responseBody)>;
114 
123  using limeX3DHServerPostData = std::function<void(const std::string &url, const std::string &from, std::vector<uint8_t> &&message, const limeX3DHServerResponseProcess &reponseProcess)>;
124 
125  /* Forward declare the class managing one lime user and class managing database */
126  class LimeGeneric;
127  class Db;
128 
129  /****************************************************************************/
130  /* */
131  /* Lime Helpers functions */
132  /* */
133  /****************************************************************************/
134 
141  lime::CurveId string2CurveId(const std::string &algo);
147  std::string CurveId2String(const lime::CurveId algo);
154  std::string CurveId2String(const std::vector<lime::CurveId> algos, const std::string separator=",");
155 
161  std::string PeerDeviceStatus2String(const lime::PeerDeviceStatus status);
162 
166  bool lime_is_PQ_available(void);
167 
171  class DeviceId {
172  private:
173  std::string username;
174  lime::CurveId baseAlgo;
175  public:
176  DeviceId(const std::string &username, const lime::CurveId baseAlgo) : username{username}, baseAlgo{baseAlgo} {};
177  const std::string &getUsername() const {return username;}
178  const lime::CurveId &getAlgo() const {return baseAlgo;}
179  const std::string getAlgoString() const {return CurveId2String(baseAlgo);}
180  explicit operator std::string() const { return std::string{username}.append(" on ").append(CurveId2String(baseAlgo));}
181  bool operator==(const DeviceId &other) const {
182  return (username==other.username && baseAlgo == other.baseAlgo);
183  }
184  static std::size_t hash(const lime::DeviceId& d) {
185  std::hash<std::string> username_hash;
186  std::hash<lime::CurveId> baseAlgo_hash;
187  // combine the hash
188  return username_hash(d.username) ^ (baseAlgo_hash(d.baseAlgo) << 1);
189  }
190  };
191 
192  // a class holding all data structure to encrypt
194  const std::vector<uint8_t> m_associatedData;
195  std::vector<RecipientData> m_recipients;
196  const std::vector<uint8_t> m_plainMessage;
197  std::vector<uint8_t> m_cipherMessage;
199 
200  // constructor with associated data being a string or a buffer
201  EncryptionContext(const std::vector<uint8_t> &associatedData, const std::vector<uint8_t> &plainMessage, const lime::EncryptionPolicy encryptionPolicy=lime::EncryptionPolicy::optimizeUploadSize ) :
202  m_associatedData(associatedData), m_plainMessage(plainMessage), m_encryptionPolicy(encryptionPolicy) {};
203  EncryptionContext(const std::string &associatedData, const std::vector<uint8_t> &plainMessage, const lime::EncryptionPolicy encryptionPolicy=lime::EncryptionPolicy::optimizeUploadSize) :
204  m_associatedData(associatedData.cbegin(), associatedData.cend()), m_plainMessage(plainMessage), m_encryptionPolicy(encryptionPolicy) {};
205  // insert a recipient address
206  void addRecipient(const std::string &recipientAddress) { m_recipients.emplace_back(recipientAddress); }
207  void dump(std::ostringstream &os, std::string indent=" ") const;
208  };
209 
210  /****************************************************************************/
211  /* */
212  /* Lime API: all interactions use LimeManager Class */
213  /* */
214  /****************************************************************************/
215 
221  class LimeManager {
222  private :
223 
224  std::unordered_map<lime::DeviceId, std::shared_ptr<LimeGeneric>, decltype(&lime::DeviceId::hash)> m_users_cache; // cache of already opened Lime Session, identified by user Id (GRUU/algo)
225  std::mutex m_users_mutex; // m_users_cache mutex
226  std::shared_ptr<lime::Db> m_localStorage; // DB access information forwarded to SOCI to correctly access database
227  limeX3DHServerPostData m_X3DH_post_data; // send data to the X3DH key server
228  std::shared_ptr<LimeGeneric> load_user(const lime::DeviceId &localDeviceId, const bool allStatus=false); // helper function, get from m_users_cache or local Storage the requested Lime object
229  std::shared_ptr<LimeGeneric> load_user_noexcept(const lime::DeviceId &localDeviceId) noexcept; // helper function, get from m_users_cache or local Storage the requested Lime object
230 
231  public :
232 
250  void create_user(const std::string &localDeviceId, const std::vector<lime::CurveId> &algos, const std::string &x3dhServerUrl, const uint16_t OPkInitialBatchSize, limeCallback callback);
254  void create_user(const std::string &localDeviceId, const std::vector<lime::CurveId> &algos, const std::string &x3dhServerUrl, limeCallback callback);
255 
265  void delete_user(const DeviceId &localDeviceId, limeCallback callback);
266 
276  bool is_user(const std::string &localDeviceId, const std::vector<lime::CurveId> &algos);
280  bool is_user(const DeviceId &localDeviceId);
281 
325  void encrypt(const std::string &localDeviceId, const std::vector<lime::CurveId> &algos, std::shared_ptr<lime::EncryptionContext> encryptionContext, limeCallback callback);
326 
342  lime::PeerDeviceStatus decrypt(const std::string &localDeviceId, const std::string &recipientUserId, const std::string &senderDeviceId, const std::vector<uint8_t> &DRmessage, const std::vector<uint8_t> &cipherMessage, std::vector<uint8_t> &plainMessage);
347  lime::PeerDeviceStatus decrypt(const std::string &localDeviceId, const std::string &recipientUserId, const std::string &senderDeviceId, const std::vector<uint8_t> &DRmessage, std::vector<uint8_t> &plainMessage);
352  lime::PeerDeviceStatus decrypt(const std::string &localDeviceId, const std::vector<uint8_t> &associatedData, const std::string &senderDeviceId, const std::vector<uint8_t> &DRmessage, const std::vector<uint8_t> &cipherMessage, std::vector<uint8_t> &plainMessage);
358  lime::PeerDeviceStatus decrypt(const std::string &localDeviceId, const std::vector<uint8_t> &associatedData, const std::string &senderDeviceId, const std::vector<uint8_t> &DRmessage, std::vector<uint8_t> &plainMessage);
359 
380  void update(const std::string &localDeviceId, const std::vector<lime::CurveId> &algos, limeCallback callback, uint16_t OPkServerLowLimit, uint16_t OPkBatchSize);
384  void update(const std::string &localDeviceId, const std::vector<lime::CurveId> &algos, limeCallback callback);
385 
396  void get_selfIdentityKey(const std::string &localDeviceId, const std::vector<lime::CurveId> &algos, std::map<lime::CurveId, std::vector<uint8_t>> &Iks);
397 
427  void set_peerDeviceStatus(const std::string &peerDeviceId, const lime::CurveId algo, const std::vector<uint8_t> &Ik, lime::PeerDeviceStatus status);
428 
444  void set_peerDeviceStatus(const std::string &peerDeviceId, const std::vector<lime::CurveId> &algos, lime::PeerDeviceStatus status);
445 
454  lime::PeerDeviceStatus get_peerDeviceStatus(const std::string &peerDeviceId);
455 
465  lime::PeerDeviceStatus get_peerDeviceStatus(const std::list<std::string> &peerDeviceIds);
466 
474  void delete_peerDevice(const std::string &peerDeviceId);
475 
486  void stale_sessions(const std::string &localDeviceId, const std::vector<lime::CurveId> &algos, const std::string &peerDeviceId);
487 
497  void set_x3dhServerUrl(const std::string &localDeviceId, const std::vector<lime::CurveId> &algos, const std::string &x3dhServerUrl);
498 
508  std::string get_x3dhServerUrl(const DeviceId &localDeviceId);
509 
510  LimeManager() = delete; // no manager without Database and http provider
511  LimeManager(const LimeManager&) = delete; // no copy constructor
512  LimeManager operator=(const LimeManager &) = delete; // nor copy operator
513 
520  LimeManager(const std::string &db_access, const limeX3DHServerPostData &X3DH_post_data);
521 
522  ~LimeManager() = default;
523  };
524 
525 } //namespace lime
526 
527 #endif /* lime_hpp */
std::string get_x3dhServerUrl(const DeviceId &localDeviceId)
Get the X3DH key server URL for this identified user.
Definition: lime_manager.cpp:432
std::string PeerDeviceStatus2String(const lime::PeerDeviceStatus status)
Definition: lime_manager.cpp:484
DeviceId(const std::string &username, const lime::CurveId baseAlgo)
Definition: lime.hpp:176
std::vector< uint8_t > DRmessage
Definition: lime.hpp:81
bool is_user(const std::string &localDeviceId, const std::vector< lime::CurveId > &algos)
Check if a user is present and active in local storage This function loads the user from DB if not al...
Definition: lime_manager.cpp:164
LimeManager()=delete
std::vector< uint8_t > m_cipherMessage
Definition: lime.hpp:197
CallbackReturn
Definition: lime.hpp:92
EncryptionContext(const std::string &associatedData, const std::vector< uint8_t > &plainMessage, const lime::EncryptionPolicy encryptionPolicy=lime::EncryptionPolicy::optimizeUploadSize)
Definition: lime.hpp:203
RecipientData(const std::string &deviceId)
Definition: lime.hpp:87
static std::size_t hash(const lime::DeviceId &d)
Definition: lime.hpp:184
void dump(std::ostringstream &os, std::string indent=" ") const
Definition: lime_log.cpp:61
void set_peerDeviceStatus(const std::string &peerDeviceId, const lime::CurveId algo, const std::vector< uint8_t > &Ik, lime::PeerDeviceStatus status)
set the peer device status flag in local storage: unsafe, trusted or untrusted.
Definition: lime_manager.cpp:384
void update(const std::string &localDeviceId, const std::vector< lime::CurveId > &algos, limeCallback callback, uint16_t OPkServerLowLimit, uint16_t OPkBatchSize)
Update: shall be called regularly, once a day at least, performs checks, updates and cleaning operati...
Definition: lime_manager.cpp:316
void addRecipient(const std::string &recipientAddress)
Definition: lime.hpp:206
std::function< void(const std::string &url, const std::string &from, std::vector< uint8_t > &&message, const limeX3DHServerResponseProcess &reponseProcess)> limeX3DHServerPostData
Post a message to the X3DH server.
Definition: lime.hpp:123
const std::string getAlgoString() const
Definition: lime.hpp:179
std::function< void(int responseCode, const std::vector< uint8_t > &responseBody)> limeX3DHServerResponseProcess
Get the response from server. The external service providing secure communication to the X3DH server ...
Definition: lime.hpp:113
void create_user(const std::string &localDeviceId, const std::vector< lime::CurveId > &algos, const std::string &x3dhServerUrl, const uint16_t OPkInitialBatchSize, limeCallback callback)
Create a user in local database and publish it on the given X3DH server.
Definition: lime_manager.cpp:92
std::vector< RecipientData > m_recipients
Definition: lime.hpp:195
bool lime_is_PQ_available(void)
Definition: lime_manager.cpp:501
void set_x3dhServerUrl(const std::string &localDeviceId, const std::vector< lime::CurveId > &algos, const std::string &x3dhServerUrl)
Set the X3DH key server URL for this identified user.
Definition: lime_manager.cpp:423
lime::PeerDeviceStatus peerStatus
Definition: lime.hpp:75
std::function< void(const lime::CallbackReturn status, const std::string message)> limeCallback
Callback use to give a status on asynchronous operation.
Definition: lime.hpp:103
PeerDeviceStatus
Definition: lime.hpp:59
lime::PeerDeviceStatus get_peerDeviceStatus(const std::string &peerDeviceId)
get the status of a peer device: unknown, untrusted, trusted, unsafe device's Id matching a local acc...
Definition: lime_manager.cpp:394
EncryptionContext(const std::vector< uint8_t > &associatedData, const std::vector< uint8_t > &plainMessage, const lime::EncryptionPolicy encryptionPolicy=lime::EncryptionPolicy::optimizeUploadSize)
Definition: lime.hpp:201
const lime::CurveId & getAlgo() const
Definition: lime.hpp:178
const lime::EncryptionPolicy m_encryptionPolicy
Definition: lime.hpp:198
std::string CurveId2String(const lime::CurveId algo)
Definition: lime_manager.cpp:461
const std::vector< uint8_t > m_associatedData
Definition: lime.hpp:194
void dump(std::ostringstream &os, std::string indent=" ") const
Definition: lime_log.cpp:49
void stale_sessions(const std::string &localDeviceId, const std::vector< lime::CurveId > &algos, const std::string &peerDeviceId)
Stale all sessions between localDeviceId and peerDevice. If peerDevice keep using this session to enc...
Definition: lime_manager.cpp:412
void get_selfIdentityKey(const std::string &localDeviceId, const std::vector< lime::CurveId > &algos, std::map< lime::CurveId, std::vector< uint8_t >> &Iks)
retrieve self Identity Key, an EdDSA formatted public key
Definition: lime_manager.cpp:376
Definition: lime.hpp:193
void delete_peerDevice(const std::string &peerDeviceId)
delete a peerDevice from local storage
Definition: lime_manager.cpp:402
const std::vector< uint8_t > m_plainMessage
Definition: lime.hpp:196
lime::CurveId string2CurveId(const std::string &algo)
Definition: lime_manager.cpp:452
Definition: lime.hpp:171
bool done
Definition: lime.hpp:82
Definition: lime.cpp:33
const std::string & getUsername() const
Definition: lime.hpp:177
LimeManager operator=(const LimeManager &)=delete
bool operator==(const DeviceId &other) const
Definition: lime.hpp:181
The encrypt function input/output data structure.
Definition: lime.hpp:73
lime::PeerDeviceStatus decrypt(const std::string &localDeviceId, const std::string &recipientUserId, const std::string &senderDeviceId, const std::vector< uint8_t > &DRmessage, const std::vector< uint8_t > &cipherMessage, std::vector< uint8_t > &plainMessage)
Decrypt the given message.
Definition: lime_manager.cpp:302
Database access class.
Definition: lime_localStorage.hpp:34
EncryptionPolicy
Definition: lime.hpp:47
CurveId
Definition: lime.hpp:37
void encrypt(const std::string &localDeviceId, const std::vector< lime::CurveId > &algos, std::shared_ptr< lime::EncryptionContext > encryptionContext, limeCallback callback)
Encrypt a buffer (text or file) for a given list of recipient devices.
Definition: lime_manager.cpp:173
Manage several Lime objects(one is needed for each local user).
Definition: lime.hpp:221
~LimeManager()=default
A pure abstract class defining the API to encrypt/decrypt/manage user and its keys.
Definition: lime_lime.hpp:42
const std::string deviceId
Definition: lime.hpp:74
void delete_user(const DeviceId &localDeviceId, limeCallback callback)
Delete a user from local database and from the X3DH server.
Definition: lime_manager.cpp:146