]> gitweb.ps.run Git - matrix_esp_thesis/blob - ext/olm/src/megolm.c
remove newline
[matrix_esp_thesis] / ext / olm / src / megolm.c
1 /* Copyright 2016 OpenMarket Ltd
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16
17 #include "olm/megolm.h"
18
19 #include <string.h>
20
21 #include "olm/cipher.h"
22 #include "olm/crypto.h"
23 #include "olm/pickle.h"
24
25 static const struct _olm_cipher_aes_sha_256 MEGOLM_CIPHER =
26     OLM_CIPHER_INIT_AES_SHA_256("MEGOLM_KEYS");
27 const struct _olm_cipher *megolm_cipher = OLM_CIPHER_BASE(&MEGOLM_CIPHER);
28
29 /* the seeds used in the HMAC-SHA-256 functions for each part of the ratchet.
30  */
31 #define HASH_KEY_SEED_LENGTH 1
32 static uint8_t HASH_KEY_SEEDS[MEGOLM_RATCHET_PARTS][HASH_KEY_SEED_LENGTH] = {
33     {0x00},
34     {0x01},
35     {0x02},
36     {0x03}
37 };
38
39 static void rehash_part(
40     uint8_t data[MEGOLM_RATCHET_PARTS][MEGOLM_RATCHET_PART_LENGTH],
41     int rehash_from_part, int rehash_to_part
42 ) {
43     _olm_crypto_hmac_sha256(
44         data[rehash_from_part],
45         MEGOLM_RATCHET_PART_LENGTH,
46         HASH_KEY_SEEDS[rehash_to_part], HASH_KEY_SEED_LENGTH,
47         data[rehash_to_part]
48     );
49 }
50
51
52
53 void megolm_init(Megolm *megolm, uint8_t const *random_data, uint32_t counter) {
54     megolm->counter = counter;
55     memcpy(megolm->data, random_data, MEGOLM_RATCHET_LENGTH);
56 }
57
58 size_t megolm_pickle_length(const Megolm *megolm) {
59     size_t length = 0;
60     length += _olm_pickle_bytes_length(megolm_get_data(megolm), MEGOLM_RATCHET_LENGTH);
61     length += _olm_pickle_uint32_length(megolm->counter);
62     return length;
63
64 }
65
66 uint8_t * megolm_pickle(const Megolm *megolm,  uint8_t *pos) {
67     pos = _olm_pickle_bytes(pos, megolm_get_data(megolm), MEGOLM_RATCHET_LENGTH);
68     pos = _olm_pickle_uint32(pos, megolm->counter);
69     return pos;
70 }
71
72 const uint8_t * megolm_unpickle(Megolm *megolm, const uint8_t *pos,
73                                 const uint8_t *end) {
74     pos = _olm_unpickle_bytes(pos, end, (uint8_t *)(megolm->data),
75                              MEGOLM_RATCHET_LENGTH);
76     UNPICKLE_OK(pos);
77
78     pos = _olm_unpickle_uint32(pos, end, &megolm->counter);
79     UNPICKLE_OK(pos);
80
81     return pos;
82 }
83
84 /* simplistic implementation for a single step */
85 void megolm_advance(Megolm *megolm) {
86     uint32_t mask = 0x00FFFFFF;
87     int h = 0;
88     int i;
89
90     megolm->counter++;
91
92     /* figure out how much we need to rekey */
93     while (h < (int)MEGOLM_RATCHET_PARTS) {
94         if (!(megolm->counter & mask))
95             break;
96         h++;
97         mask >>= 8;
98     }
99
100     /* now update R(h)...R(3) based on R(h) */
101     for (i = MEGOLM_RATCHET_PARTS-1; i >= h; i--) {
102         rehash_part(megolm->data, h, i);
103     }
104 }
105
106 void megolm_advance_to(Megolm *megolm, uint32_t advance_to) {
107     int j;
108
109     /* starting with R0, see if we need to update each part of the hash */
110     for (j = 0; j < (int)MEGOLM_RATCHET_PARTS; j++) {
111         int shift = (MEGOLM_RATCHET_PARTS-j-1) * 8;
112         uint32_t mask = (~(uint32_t)0) << shift;
113         int k;
114
115         /* how many times do we need to rehash this part?
116          *
117          * '& 0xff' ensures we handle integer wraparound correctly
118          */
119         unsigned int steps =
120             ((advance_to >> shift) - (megolm->counter >> shift)) & 0xff;
121
122         if (steps == 0) {
123             /* deal with the edge case where megolm->counter is slightly larger
124              * than advance_to. This should only happen for R(0), and implies
125              * that advance_to has wrapped around and we need to advance R(0)
126              * 256 times.
127              */
128             if (advance_to < megolm->counter) {
129                 steps = 0x100;
130             } else {
131                 continue;
132             }
133         }
134
135         /* for all but the last step, we can just bump R(j) without regard
136          * to R(j+1)...R(3).
137          */
138         while (steps > 1) {
139             rehash_part(megolm->data, j, j);
140             steps --;
141         }
142
143         /* on the last step we also need to bump R(j+1)...R(3).
144          *
145          * (Theoretically, we could skip bumping R(j+2) if we're going to bump
146          * R(j+1) again, but the code to figure that out is a bit baroque and
147          * doesn't save us much).
148          */
149         for (k = 3; k >= j; k--) {
150             rehash_part(megolm->data, j, k);
151         }
152         megolm->counter = advance_to & mask;
153     }
154 }