1 module matrix.outbound_group; 2 3 import std.experimental.allocator : processAllocator; 4 import std.exception : assumeUnique; 5 6 import matrix.olm : olm_error, read_random; 7 import matrix.session : cstr2dstr; 8 9 import std.stdio; // TODO debug only! 10 11 public class OutboundGroupSession { 12 OlmOutboundGroupSession *session; 13 public this() { 14 const len = olm_outbound_group_session_size(); 15 auto mem = processAllocator.allocate(len); 16 this.session = olm_outbound_group_session(mem.ptr); 17 18 auto rnd_len = olm_init_outbound_group_session_random_length(session); 19 auto rnd_mem = read_random(rnd_len); 20 olm_init_outbound_group_session(session, rnd_mem.ptr, rnd_mem.length); 21 } 22 /// serialize session data, locked by key 23 public string pickle(string key) { 24 char[] ret; 25 ret.length = olm_pickle_outbound_group_session_length(this.session); 26 const r = olm_pickle_outbound_group_session(this.session, 27 key.ptr, key.length, ret.ptr, ret.length); 28 error_check(r); 29 return assumeUnique(ret); 30 } 31 /// deserialize session data, unlocked by key 32 static public OutboundGroupSession unpickle(string key, string pickle) { 33 auto a = new OutboundGroupSession(); 34 char[] p = pickle.dup; // p is destroyed! 35 const r = olm_unpickle_outbound_group_session(a.session, 36 key.ptr, key.length, p.ptr, p.length); 37 a.error_check(r); 38 return a; 39 } 40 public string encrypt(string plain) { 41 auto len = olm_group_encrypt_message_length(session, plain.length); 42 error_check(len); 43 char[] ret; 44 ret.length = len; 45 len = olm_group_encrypt(session, plain.ptr, plain.length, ret.ptr, len); 46 error_check(len); 47 return assumeUnique(ret[0..len]); 48 } 49 public string session_id() { 50 char[] ret; 51 ret.length = olm_outbound_group_session_id_length(session); 52 auto r = olm_outbound_group_session_id(session, ret.ptr, ret.length); 53 error_check(r); 54 return assumeUnique(ret); 55 } 56 public @property uint message_index() { 57 return olm_outbound_group_session_message_index(session); 58 } 59 public auto session_key() { 60 char[] ret; 61 ret.length = olm_outbound_group_session_key_length(session); 62 auto r = olm_outbound_group_session_key(session, ret.ptr, ret.length); 63 error_check(r); 64 return assumeUnique(ret); 65 66 } 67 private void error_check(size_t x) { 68 if (x == olm_error()) { 69 auto errmsg = olm_outbound_group_session_last_error(this.session); 70 throw new Exception(cstr2dstr(errmsg)); 71 } 72 } 73 } 74 75 unittest { 76 auto igs = new OutboundGroupSession(); 77 auto p = igs.pickle("foo"); 78 auto dp = OutboundGroupSession.unpickle("foo", p); 79 } 80 81 82 extern (C): 83 // copy&pasted from outbound_group_session.h 84 85 struct OlmOutboundGroupSession; 86 87 /** get the size of an outbound group session, in bytes. */ 88 size_t olm_outbound_group_session_size(); 89 90 /** 91 * Initialise an outbound group session object using the supplied memory 92 * The supplied memory should be at least olm_outbound_group_session_size() 93 * bytes. 94 */ 95 OlmOutboundGroupSession * olm_outbound_group_session( 96 void *memory 97 ); 98 99 /** 100 * A null terminated string describing the most recent error to happen to a 101 * group session */ 102 const(char)* olm_outbound_group_session_last_error( 103 const OlmOutboundGroupSession *session 104 ); 105 106 /** Clears the memory used to back this group session */ 107 size_t olm_clear_outbound_group_session( 108 OlmOutboundGroupSession *session 109 ); 110 111 /** Returns the number of bytes needed to store an outbound group session */ 112 size_t olm_pickle_outbound_group_session_length( 113 const OlmOutboundGroupSession *session 114 ); 115 116 /** 117 * Stores a group session as a base64 string. Encrypts the session using the 118 * supplied key. Returns the length of the session on success. 119 * 120 * Returns olm_error() on failure. If the pickle output buffer 121 * is smaller than olm_pickle_outbound_group_session_length() then 122 * olm_outbound_group_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL" 123 */ 124 size_t olm_pickle_outbound_group_session( 125 OlmOutboundGroupSession *session, 126 const(void)* key, size_t key_length, 127 void * pickled, size_t pickled_length 128 ); 129 130 /** 131 * Loads a group session from a pickled base64 string. Decrypts the session 132 * using the supplied key. 133 * 134 * Returns olm_error() on failure. If the key doesn't match the one used to 135 * encrypt the account then olm_outbound_group_session_last_error() will be 136 * "BAD_ACCOUNT_KEY". If the base64 couldn't be decoded then 137 * olm_outbound_group_session_last_error() will be "INVALID_BASE64". The input 138 * pickled buffer is destroyed 139 */ 140 size_t olm_unpickle_outbound_group_session( 141 OlmOutboundGroupSession *session, 142 const(void)* key, size_t key_length, 143 void * pickled, size_t pickled_length 144 ); 145 146 147 /** The number of random bytes needed to create an outbound group session */ 148 size_t olm_init_outbound_group_session_random_length( 149 const OlmOutboundGroupSession *session 150 ); 151 152 /** 153 * Start a new outbound group session. Returns olm_error() on failure. On 154 * failure last_error will be set with an error code. The last_error will be 155 * NOT_ENOUGH_RANDOM if the number of random bytes was too small. 156 */ 157 size_t olm_init_outbound_group_session( 158 OlmOutboundGroupSession *session, 159 char* random, size_t random_length 160 ); 161 162 /** 163 * The number of bytes that will be created by encrypting a message 164 */ 165 size_t olm_group_encrypt_message_length( 166 OlmOutboundGroupSession *session, 167 size_t plaintext_length 168 ); 169 170 /** 171 * Encrypt some plain-text. Returns the length of the encrypted message or 172 * olm_error() on failure. On failure last_error will be set with an 173 * error code. The last_error will be OUTPUT_BUFFER_TOO_SMALL if the output 174 * buffer is too small. 175 */ 176 size_t olm_group_encrypt( 177 OlmOutboundGroupSession *session, 178 const(char)* plaintext, size_t plaintext_length, 179 char* message, size_t message_length 180 ); 181 182 183 /** 184 * Get the number of bytes returned by olm_outbound_group_session_id() 185 */ 186 size_t olm_outbound_group_session_id_length( 187 const OlmOutboundGroupSession *session 188 ); 189 190 /** 191 * Get a base64-encoded identifier for this session. 192 * 193 * Returns the length of the session id on success or olm_error() on 194 * failure. On failure last_error will be set with an error code. The 195 * last_error will be OUTPUT_BUFFER_TOO_SMALL if the id buffer was too 196 * small. 197 */ 198 size_t olm_outbound_group_session_id( 199 OlmOutboundGroupSession *session, 200 char* id, size_t id_length 201 ); 202 203 /** 204 * Get the current message index for this session. 205 * 206 * Each message is sent with an increasing index; this returns the index for 207 * the next message. 208 */ 209 uint olm_outbound_group_session_message_index( 210 OlmOutboundGroupSession *session 211 ); 212 213 /** 214 * Get the number of bytes returned by olm_outbound_group_session_key() 215 */ 216 size_t olm_outbound_group_session_key_length( 217 const OlmOutboundGroupSession *session 218 ); 219 220 /** 221 * Get the base64-encoded current ratchet key for this session. 222 * 223 * Each message is sent with a different ratchet key. This function returns the 224 * ratchet key that will be used for the next message. 225 * 226 * Returns the length of the ratchet key on success or olm_error() on 227 * failure. On failure last_error will be set with an error code. The 228 * last_error will be OUTPUT_BUFFER_TOO_SMALL if the buffer was too small. 229 */ 230 size_t olm_outbound_group_session_key( 231 OlmOutboundGroupSession *session, 232 char* key, size_t key_length 233 );