ruby_olm 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. checksums.yaml +7 -0
  2. data/ext/ruby_olm/ext_lib_olm/ext_account.c +274 -0
  3. data/ext/ruby_olm/ext_lib_olm/ext_lib_olm.c +51 -0
  4. data/ext/ruby_olm/ext_lib_olm/ext_lib_olm.h +13 -0
  5. data/ext/ruby_olm/ext_lib_olm/ext_session.c +363 -0
  6. data/ext/ruby_olm/ext_lib_olm/ext_utility.c +69 -0
  7. data/ext/ruby_olm/ext_lib_olm/extconf.rb +69 -0
  8. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_account.cpp +695 -0
  9. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_account.h +56 -0
  10. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_inbound_group_session.cpp +654 -0
  11. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_inbound_group_session.h +51 -0
  12. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_jni.h +81 -0
  13. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_jni_helper.cpp +224 -0
  14. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_jni_helper.h +30 -0
  15. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_manager.cpp +35 -0
  16. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_manager.h +36 -0
  17. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_outbound_group_session.cpp +563 -0
  18. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_outbound_group_session.h +49 -0
  19. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_pk.cpp +716 -0
  20. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_pk.h +48 -0
  21. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_session.cpp +977 -0
  22. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_session.h +59 -0
  23. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_utility.cpp +236 -0
  24. data/ext/ruby_olm/ext_lib_olm/olm/android/olm-sdk/src/main/jni/olm_utility.h +40 -0
  25. data/ext/ruby_olm/ext_lib_olm/olm/fuzzers/fuzz_decode_message.cpp +14 -0
  26. data/ext/ruby_olm/ext_lib_olm/olm/fuzzers/fuzz_decrypt.cpp +65 -0
  27. data/ext/ruby_olm/ext_lib_olm/olm/fuzzers/fuzz_group_decrypt.cpp +73 -0
  28. data/ext/ruby_olm/ext_lib_olm/olm/fuzzers/fuzz_unpickle_account.cpp +14 -0
  29. data/ext/ruby_olm/ext_lib_olm/olm/fuzzers/fuzz_unpickle_session.cpp +14 -0
  30. data/ext/ruby_olm/ext_lib_olm/olm/fuzzers/include/fuzzing.hh +82 -0
  31. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/account.hh +160 -0
  32. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/base64.h +77 -0
  33. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/base64.hh +63 -0
  34. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/cipher.h +138 -0
  35. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/crypto.h +202 -0
  36. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/error.h +72 -0
  37. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/inbound_group_session.h +235 -0
  38. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/list.hh +119 -0
  39. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/megolm.h +95 -0
  40. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/memory.h +41 -0
  41. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/memory.hh +90 -0
  42. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/message.h +93 -0
  43. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/message.hh +138 -0
  44. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/olm.h +451 -0
  45. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/olm.hh +4 -0
  46. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/outbound_group_session.h +181 -0
  47. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/pickle.h +90 -0
  48. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/pickle.hh +149 -0
  49. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/pickle_encoding.h +76 -0
  50. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/pk.h +214 -0
  51. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/ratchet.hh +184 -0
  52. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/session.hh +156 -0
  53. data/ext/ruby_olm/ext_lib_olm/olm/include/olm/utility.hh +61 -0
  54. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/aes.c +1073 -0
  55. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/aes.h +123 -0
  56. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/aes_test.c +276 -0
  57. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/arcfour.c +45 -0
  58. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/arcfour.h +30 -0
  59. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/arcfour_test.c +47 -0
  60. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/base64.c +135 -0
  61. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/base64.h +27 -0
  62. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/base64_test.c +54 -0
  63. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/blowfish.c +269 -0
  64. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/blowfish.h +32 -0
  65. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/blowfish_test.c +68 -0
  66. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/des.c +269 -0
  67. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/des.h +37 -0
  68. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/des_test.c +83 -0
  69. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/md2.c +104 -0
  70. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/md2.h +33 -0
  71. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/md2_test.c +58 -0
  72. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/md5.c +189 -0
  73. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/md5.h +34 -0
  74. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/md5_test.c +60 -0
  75. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/rot-13.c +35 -0
  76. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/rot-13.h +20 -0
  77. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/rot-13_test.c +44 -0
  78. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/sha1.c +149 -0
  79. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/sha1.h +35 -0
  80. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/sha1_test.c +58 -0
  81. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/sha256.c +159 -0
  82. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/sha256.h +34 -0
  83. data/ext/ruby_olm/ext_lib_olm/olm/lib/crypto-algorithms/sha256_test.c +61 -0
  84. data/ext/ruby_olm/ext_lib_olm/olm/lib/curve25519-donna/contrib/Curve25519Donna.c +118 -0
  85. data/ext/ruby_olm/ext_lib_olm/olm/lib/curve25519-donna/contrib/Curve25519Donna.h +53 -0
  86. data/ext/ruby_olm/ext_lib_olm/olm/lib/curve25519-donna/curve25519-donna-c64.c +449 -0
  87. data/ext/ruby_olm/ext_lib_olm/olm/lib/curve25519-donna/curve25519-donna.c +860 -0
  88. data/ext/ruby_olm/ext_lib_olm/olm/lib/curve25519-donna/python-src/curve25519/curve25519module.c +105 -0
  89. data/ext/ruby_olm/ext_lib_olm/olm/lib/curve25519-donna/speed-curve25519.c +50 -0
  90. data/ext/ruby_olm/ext_lib_olm/olm/lib/curve25519-donna/test-curve25519.c +54 -0
  91. data/ext/ruby_olm/ext_lib_olm/olm/lib/curve25519-donna/test-noncanon.c +39 -0
  92. data/ext/ruby_olm/ext_lib_olm/olm/lib/curve25519-donna/test-sc-curve25519.c +72 -0
  93. data/ext/ruby_olm/ext_lib_olm/olm/lib/curve25519-donna.h +18 -0
  94. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/add_scalar.c +56 -0
  95. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/ed25519.h +38 -0
  96. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/fe.c +1493 -0
  97. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/fe.h +41 -0
  98. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/fixedint.h +72 -0
  99. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/ge.c +467 -0
  100. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/ge.h +74 -0
  101. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/key_exchange.c +79 -0
  102. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/keypair.c +16 -0
  103. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/precomp_data.h +1391 -0
  104. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/sc.c +814 -0
  105. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/sc.h +12 -0
  106. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/seed.c +40 -0
  107. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/sha512.c +275 -0
  108. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/sha512.h +21 -0
  109. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/sign.c +31 -0
  110. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/src/verify.c +77 -0
  111. data/ext/ruby_olm/ext_lib_olm/olm/lib/ed25519/test.c +150 -0
  112. data/ext/ruby_olm/ext_lib_olm/olm/python/dummy/stddef.h +0 -0
  113. data/ext/ruby_olm/ext_lib_olm/olm/python/dummy/stdint.h +0 -0
  114. data/ext/ruby_olm/ext_lib_olm/olm/src/account.cpp +380 -0
  115. data/ext/ruby_olm/ext_lib_olm/olm/src/base64.cpp +167 -0
  116. data/ext/ruby_olm/ext_lib_olm/olm/src/cipher.cpp +152 -0
  117. data/ext/ruby_olm/ext_lib_olm/olm/src/crypto.cpp +299 -0
  118. data/ext/ruby_olm/ext_lib_olm/olm/src/ed25519.c +22 -0
  119. data/ext/ruby_olm/ext_lib_olm/olm/src/error.c +44 -0
  120. data/ext/ruby_olm/ext_lib_olm/olm/src/inbound_group_session.c +524 -0
  121. data/ext/ruby_olm/ext_lib_olm/olm/src/megolm.c +150 -0
  122. data/ext/ruby_olm/ext_lib_olm/olm/src/memory.cpp +45 -0
  123. data/ext/ruby_olm/ext_lib_olm/olm/src/message.cpp +401 -0
  124. data/ext/ruby_olm/ext_lib_olm/olm/src/olm.cpp +738 -0
  125. data/ext/ruby_olm/ext_lib_olm/olm/src/outbound_group_session.c +363 -0
  126. data/ext/ruby_olm/ext_lib_olm/olm/src/pickle.cpp +242 -0
  127. data/ext/ruby_olm/ext_lib_olm/olm/src/pickle_encoding.c +92 -0
  128. data/ext/ruby_olm/ext_lib_olm/olm/src/pk.cpp +412 -0
  129. data/ext/ruby_olm/ext_lib_olm/olm/src/ratchet.cpp +625 -0
  130. data/ext/ruby_olm/ext_lib_olm/olm/src/session.cpp +462 -0
  131. data/ext/ruby_olm/ext_lib_olm/olm/src/utility.cpp +57 -0
  132. data/ext/ruby_olm/ext_lib_olm/olm/tests/include/unittest.hh +107 -0
  133. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_base64.cpp +70 -0
  134. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_crypto.cpp +246 -0
  135. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_group_session.cpp +329 -0
  136. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_list.cpp +92 -0
  137. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_megolm.cpp +134 -0
  138. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_message.cpp +112 -0
  139. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_olm.cpp +405 -0
  140. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_olm_decrypt.cpp +90 -0
  141. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_olm_sha256.cpp +20 -0
  142. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_olm_signature.cpp +81 -0
  143. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_olm_using_malloc.cpp +210 -0
  144. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_pk.cpp +166 -0
  145. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_ratchet.cpp +221 -0
  146. data/ext/ruby_olm/ext_lib_olm/olm/tests/test_session.cpp +144 -0
  147. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMAccount.h +51 -0
  148. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMAccount_Private.h +25 -0
  149. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMInboundGroupSession.h +38 -0
  150. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMKit.h +37 -0
  151. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMMessage.h +38 -0
  152. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMOutboundGroupSession.h +32 -0
  153. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMPkDecryption.h +71 -0
  154. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMPkEncryption.h +42 -0
  155. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMPkMessage.h +31 -0
  156. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMSerializable.h +29 -0
  157. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMSession.h +44 -0
  158. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMSession_Private.h +26 -0
  159. data/ext/ruby_olm/ext_lib_olm/olm/xcode/OLMKit/OLMUtility.h +49 -0
  160. data/ext/ruby_olm/ext_lib_olm/staging/account.cpp +380 -0
  161. data/ext/ruby_olm/ext_lib_olm/staging/aes.c +1073 -0
  162. data/ext/ruby_olm/ext_lib_olm/staging/base64.cpp +167 -0
  163. data/ext/ruby_olm/ext_lib_olm/staging/cipher.cpp +152 -0
  164. data/ext/ruby_olm/ext_lib_olm/staging/crypto.cpp +299 -0
  165. data/ext/ruby_olm/ext_lib_olm/staging/curve25519-donna.c +860 -0
  166. data/ext/ruby_olm/ext_lib_olm/staging/ed25519.c +22 -0
  167. data/ext/ruby_olm/ext_lib_olm/staging/error.c +44 -0
  168. data/ext/ruby_olm/ext_lib_olm/staging/inbound_group_session.c +524 -0
  169. data/ext/ruby_olm/ext_lib_olm/staging/megolm.c +150 -0
  170. data/ext/ruby_olm/ext_lib_olm/staging/memory.cpp +45 -0
  171. data/ext/ruby_olm/ext_lib_olm/staging/message.cpp +401 -0
  172. data/ext/ruby_olm/ext_lib_olm/staging/olm.cpp +738 -0
  173. data/ext/ruby_olm/ext_lib_olm/staging/outbound_group_session.c +363 -0
  174. data/ext/ruby_olm/ext_lib_olm/staging/pickle.cpp +242 -0
  175. data/ext/ruby_olm/ext_lib_olm/staging/pickle_encoding.c +92 -0
  176. data/ext/ruby_olm/ext_lib_olm/staging/pk.cpp +412 -0
  177. data/ext/ruby_olm/ext_lib_olm/staging/ratchet.cpp +625 -0
  178. data/ext/ruby_olm/ext_lib_olm/staging/session.cpp +461 -0
  179. data/ext/ruby_olm/ext_lib_olm/staging/sha256.c +159 -0
  180. data/ext/ruby_olm/ext_lib_olm/staging/utility.cpp +57 -0
  181. data/lib/ruby_olm/account.rb +42 -0
  182. data/lib/ruby_olm/message.rb +6 -0
  183. data/lib/ruby_olm/olm_error.rb +70 -0
  184. data/lib/ruby_olm/olm_message.rb +25 -0
  185. data/lib/ruby_olm/pre_key_message.rb +6 -0
  186. data/lib/ruby_olm/session.rb +16 -0
  187. data/lib/ruby_olm/version.rb +5 -0
  188. data/lib/ruby_olm.rb +10 -0
  189. data/rakefile +18 -0
  190. data/test/examples/test_bob_no_answer.rb +62 -0
  191. data/test/examples/test_exchange.rb +60 -0
  192. data/test/spec/test_account.rb +152 -0
  193. data/test/unit/test_account_methods.rb +85 -0
  194. metadata +282 -0
@@ -0,0 +1,221 @@
1
+ /* Copyright 2015 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
+ #include "olm/ratchet.hh"
16
+ #include "olm/cipher.h"
17
+ #include "unittest.hh"
18
+
19
+
20
+ int main() {
21
+
22
+ std::uint8_t root_info[] = "Olm";
23
+ std::uint8_t ratchet_info[] = "OlmRatchet";
24
+ std::uint8_t message_info[] = "OlmMessageKeys";
25
+
26
+ olm::KdfInfo kdf_info = {
27
+ root_info, sizeof(root_info) - 1,
28
+ ratchet_info, sizeof(ratchet_info) - 1
29
+ };
30
+
31
+ _olm_cipher_aes_sha_256 cipher0 = OLM_CIPHER_INIT_AES_SHA_256(message_info);
32
+ _olm_cipher *cipher = OLM_CIPHER_BASE(&cipher0);
33
+
34
+ std::uint8_t random_bytes[] = "0123456789ABDEF0123456789ABCDEF";
35
+ _olm_curve25519_key_pair alice_key;
36
+ _olm_crypto_curve25519_generate_key(random_bytes, &alice_key);
37
+
38
+ std::uint8_t shared_secret[] = "A secret";
39
+
40
+ { /* Send/Receive test case */
41
+ TestCase test_case("Olm Send/Receive");
42
+
43
+ olm::Ratchet alice(kdf_info, cipher);
44
+ olm::Ratchet bob(kdf_info, cipher);
45
+
46
+ alice.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, alice_key);
47
+ bob.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, alice_key.public_key);
48
+
49
+ std::uint8_t plaintext[] = "Message";
50
+ std::size_t plaintext_length = sizeof(plaintext) - 1;
51
+
52
+ std::size_t message_length, random_length, output_length;
53
+ std::size_t encrypt_length, decrypt_length;
54
+ {
55
+ /* Alice sends Bob a message */
56
+ message_length = alice.encrypt_output_length(plaintext_length);
57
+ random_length = alice.encrypt_random_length();
58
+ assert_equals(std::size_t(0), random_length);
59
+
60
+ std::uint8_t message[message_length];
61
+
62
+ encrypt_length = alice.encrypt(
63
+ plaintext, plaintext_length,
64
+ NULL, 0,
65
+ message, message_length
66
+ );
67
+ assert_equals(message_length, encrypt_length);
68
+
69
+ output_length = bob.decrypt_max_plaintext_length(message, message_length);
70
+ std::uint8_t output[output_length];
71
+ decrypt_length = bob.decrypt(
72
+ message, message_length,
73
+ output, output_length
74
+ );
75
+ assert_equals(plaintext_length, decrypt_length);
76
+ assert_equals(plaintext, output, decrypt_length);
77
+ }
78
+
79
+
80
+ {
81
+ /* Bob sends Alice a message */
82
+ message_length = bob.encrypt_output_length(plaintext_length);
83
+ random_length = bob.encrypt_random_length();
84
+ assert_equals(std::size_t(32), random_length);
85
+
86
+ std::uint8_t message[message_length];
87
+ std::uint8_t random[] = "This is a random 32 byte string.";
88
+
89
+ encrypt_length = bob.encrypt(
90
+ plaintext, plaintext_length,
91
+ random, 32,
92
+ message, message_length
93
+ );
94
+ assert_equals(message_length, encrypt_length);
95
+
96
+ output_length = alice.decrypt_max_plaintext_length(message, message_length);
97
+ std::uint8_t output[output_length];
98
+ decrypt_length = alice.decrypt(
99
+ message, message_length,
100
+ output, output_length
101
+ );
102
+ assert_equals(plaintext_length, decrypt_length);
103
+ assert_equals(plaintext, output, decrypt_length);
104
+ }
105
+
106
+ } /* Send/receive message test case */
107
+
108
+ { /* Out of order test case */
109
+
110
+ TestCase test_case("Olm Out of Order");
111
+
112
+ olm::Ratchet alice(kdf_info, cipher);
113
+ olm::Ratchet bob(kdf_info, cipher);
114
+
115
+ alice.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, alice_key);
116
+ bob.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, alice_key.public_key);
117
+
118
+ std::uint8_t plaintext_1[] = "First Message";
119
+ std::size_t plaintext_1_length = sizeof(plaintext_1) - 1;
120
+
121
+ std::uint8_t plaintext_2[] = "Second Messsage. A bit longer than the first.";
122
+ std::size_t plaintext_2_length = sizeof(plaintext_2) - 1;
123
+
124
+ std::size_t message_1_length, message_2_length, random_length, output_length;
125
+ std::size_t encrypt_length, decrypt_length;
126
+
127
+ {
128
+ /* Alice sends Bob two messages and they arrive out of order */
129
+ message_1_length = alice.encrypt_output_length(plaintext_1_length);
130
+ random_length = alice.encrypt_random_length();
131
+ assert_equals(std::size_t(0), random_length);
132
+
133
+ std::uint8_t message_1[message_1_length];
134
+ std::uint8_t random[] = "This is a random 32 byte string.";
135
+ encrypt_length = alice.encrypt(
136
+ plaintext_1, plaintext_1_length,
137
+ random, 32,
138
+ message_1, message_1_length
139
+ );
140
+ assert_equals(message_1_length, encrypt_length);
141
+
142
+ message_2_length = alice.encrypt_output_length(plaintext_2_length);
143
+ random_length = alice.encrypt_random_length();
144
+ assert_equals(std::size_t(0), random_length);
145
+
146
+ std::uint8_t message_2[message_2_length];
147
+ encrypt_length = alice.encrypt(
148
+ plaintext_2, plaintext_2_length,
149
+ NULL, 0,
150
+ message_2, message_2_length
151
+ );
152
+ assert_equals(message_2_length, encrypt_length);
153
+
154
+ output_length = bob.decrypt_max_plaintext_length(
155
+ message_2, message_2_length
156
+ );
157
+ std::uint8_t output_1[output_length];
158
+ decrypt_length = bob.decrypt(
159
+ message_2, message_2_length,
160
+ output_1, output_length
161
+ );
162
+ assert_equals(plaintext_2_length, decrypt_length);
163
+ assert_equals(plaintext_2, output_1, decrypt_length);
164
+
165
+ output_length = bob.decrypt_max_plaintext_length(
166
+ message_1, message_1_length
167
+ );
168
+ std::uint8_t output_2[output_length];
169
+ decrypt_length = bob.decrypt(
170
+ message_1, message_1_length,
171
+ output_2, output_length
172
+ );
173
+
174
+ assert_equals(plaintext_1_length, decrypt_length);
175
+ assert_equals(plaintext_1, output_2, decrypt_length);
176
+ }
177
+
178
+ } /* Out of order test case */
179
+
180
+ { /* More messages */
181
+
182
+ TestCase test_case("Olm More Messages");
183
+
184
+ olm::Ratchet alice(kdf_info, cipher);
185
+ olm::Ratchet bob(kdf_info, cipher);
186
+
187
+ alice.initialise_as_alice(shared_secret, sizeof(shared_secret) - 1, alice_key);
188
+ bob.initialise_as_bob(shared_secret, sizeof(shared_secret) - 1, alice_key.public_key);
189
+
190
+ std::uint8_t plaintext[] = "These 15 bytes";
191
+ assert_equals(std::size_t(15), sizeof(plaintext));
192
+ std::uint8_t random[] = "This is a random 32 byte string";
193
+
194
+ for (unsigned i = 0; i < 8; ++i) {
195
+ {
196
+ std::uint8_t msg[alice.encrypt_output_length(sizeof(plaintext))];
197
+ alice.encrypt(
198
+ plaintext, 15, random, 32, msg, sizeof(msg)
199
+ );
200
+ std::uint8_t output[bob.decrypt_max_plaintext_length(msg, sizeof(msg))];
201
+ assert_equals(
202
+ std::size_t(15), bob.decrypt(msg, sizeof(msg), output, sizeof(output))
203
+ );
204
+ }
205
+ random[31]++;
206
+ {
207
+ std::uint8_t msg[bob.encrypt_output_length(sizeof(plaintext))];
208
+ bob.encrypt(
209
+ plaintext, 15, random, 32, msg, sizeof(msg)
210
+ );
211
+ std::uint8_t output[alice.decrypt_max_plaintext_length(msg, sizeof(msg))];
212
+ assert_equals(
213
+ std::size_t(15), alice.decrypt(msg, sizeof(msg), output, sizeof(output))
214
+ );
215
+ }
216
+ random[31]++;
217
+ }
218
+
219
+ }
220
+
221
+ }
@@ -0,0 +1,144 @@
1
+ #include "olm/session.hh"
2
+ #include "olm/pickle_encoding.h"
3
+
4
+ #include "unittest.hh"
5
+
6
+ /* decode into a buffer, which is returned */
7
+ std::uint8_t *decode_hex(
8
+ const char * input
9
+ ) {
10
+ static std::uint8_t buf[256];
11
+ std::uint8_t *p = buf;
12
+ while (*input != '\0') {
13
+ char high = *(input++);
14
+ char low = *(input++);
15
+ if (high >= 'a') high -= 'a' - ('9' + 1);
16
+ if (low >= 'a') low -= 'a' - ('9' + 1);
17
+ uint8_t value = ((high - '0') << 4) | (low - '0');
18
+ *p++ = value;
19
+ }
20
+ return buf;
21
+ }
22
+
23
+ void check_session(const olm::Session &session) {
24
+ assert_equals(
25
+ decode_hex("49d640dc96b80176694af69fc4b8ca9fac49aecbd697d01fd8bee1ed2693b6c9"),
26
+ session.ratchet.root_key, 32
27
+ );
28
+
29
+ assert_equals(
30
+ std::size_t(1),
31
+ session.ratchet.sender_chain.size()
32
+ );
33
+
34
+ assert_equals(
35
+ decode_hex("f77a03eaa9b301fa7d2a5aa6b50286906de12cc96044f526dbbcb12839ad7003"),
36
+ session.ratchet.sender_chain[0].ratchet_key.public_key.public_key, 32
37
+ );
38
+
39
+ assert_equals(
40
+ decode_hex("d945c6ed4c7c277117adf11fb133a7936d287afe97c0b3ac989644b4490d4f31"),
41
+ session.ratchet.sender_chain[0].ratchet_key.private_key.private_key, 32
42
+ );
43
+
44
+ assert_equals(
45
+ std::uint32_t(0),
46
+ session.ratchet.sender_chain[0].chain_key.index
47
+ );
48
+
49
+ assert_equals(
50
+ std::size_t(0),
51
+ session.ratchet.receiver_chains.size()
52
+ );
53
+
54
+ assert_equals(
55
+ std::size_t(0),
56
+ session.ratchet.skipped_message_keys.size()
57
+ );
58
+
59
+ assert_equals(OLM_SUCCESS, session.last_error);
60
+ assert_equals(false, session.received_message);
61
+
62
+ assert_equals(
63
+ decode_hex("7326b58623a3f7bd8da11a1bab51f432c02a7430241b326e9fc8916a21eb257e"),
64
+ session.alice_identity_key.public_key, 32
65
+ );
66
+
67
+ assert_equals(
68
+ decode_hex("0ab4b30bde20bd374ceccc72861660f0fd046f7516900796c3e5de41c598316c"),
69
+ session.alice_base_key.public_key, 32
70
+ );
71
+
72
+ assert_equals(
73
+ decode_hex("585dba930b10d90d81702c715f4085d07c42b0cd2d676010bb6086c86c4cc618"),
74
+ session.bob_one_time_key.public_key, 32
75
+ );
76
+ }
77
+
78
+ int main() {
79
+
80
+ {
81
+ TestCase test_case("V1 session pickle");
82
+
83
+ const uint8_t *PICKLE_KEY=(uint8_t *)"secret_key";
84
+ uint8_t pickled[] =
85
+ "wkEpwMgiAqD7B1/Lw2cKYYDcUZVOd9QHes7ZroWxr/Rp/nWEAySgRsIu/a54YhO67rwitr"
86
+ "Lpos7tFxxK9IZ7pKB1qrR1coVWIt78V9lp9WgmBAvxHBSY+tu1lkL/JjLi963/yFdPancZ"
87
+ "+WHMVfaKlV3gWGpo7EfNK6qAOxI1Ea/eCsE2sYrsHEDvLLGlKAA9E56rmmoe2w6TKzsQjs"
88
+ "ZM2/XT2eJ82EgMO9pL02iLElXWmGNv72Ut7DouR0pQIT50HIEEKcFxYcoTb3WCfJD76Coe"
89
+ "sE4kx+TA6d45Xu1bwQNNkTGF+nCCu/GmKY+sECXbz9U6WhxG0YdF9Z4T8YkWYAgpKNS0FW"
90
+ "RV";
91
+ size_t pickle_len = _olm_enc_input(
92
+ PICKLE_KEY, strlen((char *)PICKLE_KEY),
93
+ pickled, strlen((char *)pickled), NULL
94
+ );
95
+
96
+ olm::Session session;
97
+ const uint8_t *unpickle_res = olm::unpickle(pickled, pickled+sizeof(pickled), session);
98
+ assert_equals(
99
+ pickle_len, (size_t)(unpickle_res - pickled)
100
+ );
101
+
102
+ check_session(session);
103
+
104
+ #if 0
105
+ size_t rawlen = olm::pickle_length(session);
106
+ uint8_t *r1 = _olm_enc_output_pos(pickled, rawlen);
107
+ olm::pickle(r1, session);
108
+ _olm_enc_output(
109
+ PICKLE_KEY, strlen((char *)PICKLE_KEY),
110
+ pickled, rawlen);
111
+ printf("%s\n", pickled);
112
+ #endif
113
+ }
114
+
115
+ {
116
+ TestCase test_case("V2 session pickle");
117
+
118
+ const uint8_t *PICKLE_KEY=(uint8_t *)"secret_key";
119
+ uint8_t pickled[] =
120
+ "m+DS/q34MXpw2xp50ZD0B7val1mlMpQXo0mx+VPje0weFYRRuuZQBdJgcFPEpi2MVSpA4c"
121
+ "qgqHyj2/bU7/lz+BXkEBrCFVx0BJidxXfOLDW4TNtRhLS1YHJNGP8GvTg1+dCytBTLsCdm"
122
+ "5f945Eq1U/pY3Cg96YTUufFP6EYrfRoDbAsRHc+h+wKKftQv+W44yUmRhcCemGHtpxk3UQ"
123
+ "AMCI7EBv9BvveyZMy3p9qZ3xvFK34Hef+R7gjtFycz7Nk/4UF46sT3cTmUlXz9iFW4uz2F"
124
+ "rTI1Wjym+l0DadsbSpHSUjmp9zt4qRP2UjwfZ5QNLv+cdObIfqFsiThGu/PlKigdF4SLHr"
125
+ "nG";
126
+
127
+ size_t pickle_len = _olm_enc_input(
128
+ PICKLE_KEY, strlen((char *)PICKLE_KEY),
129
+ pickled, strlen((char *)pickled), NULL
130
+ );
131
+
132
+ olm::Session session;
133
+ const uint8_t *unpickle_res = olm::unpickle(pickled, pickled+sizeof(pickled), session);
134
+ assert_equals(
135
+ pickle_len, (size_t)(unpickle_res - pickled)
136
+ );
137
+
138
+ check_session(session);
139
+ }
140
+
141
+
142
+
143
+ return 0;
144
+ }
@@ -0,0 +1,51 @@
1
+ /*
2
+ Copyright 2016 Chris Ballinger
3
+ Copyright 2016 OpenMarket Ltd
4
+ Copyright 2016 Vector Creations Ltd
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+ #import <Foundation/Foundation.h>
20
+ #import "OLMSerializable.h"
21
+
22
+ @class OLMSession;
23
+
24
+ @interface OLMAccount : NSObject <OLMSerializable, NSSecureCoding>
25
+
26
+ /** Creates new account */
27
+ - (instancetype) initNewAccount;
28
+
29
+ /** public identity keys. base64 encoded in "curve25519" and "ed25519" keys */
30
+ - (NSDictionary*) identityKeys;
31
+
32
+ /** signs message with ed25519 key for account */
33
+ - (NSString*) signMessage:(NSData*)messageData;
34
+
35
+ /** Public parts of the unpublished one time keys for the account */
36
+ - (NSDictionary*) oneTimeKeys;
37
+
38
+ - (BOOL) removeOneTimeKeysForSession:(OLMSession*)session;
39
+
40
+ /** Marks the current set of one time keys as being published. */
41
+ - (void) markOneTimeKeysAsPublished;
42
+
43
+ /** The largest number of one time keys this account can store. */
44
+ - (NSUInteger) maxOneTimeKeys;
45
+
46
+ /** Generates a number of new one time keys. If the total number of keys stored
47
+ * by this account exceeds -maxOneTimeKeys then the old keys are
48
+ * discarded. */
49
+ - (void) generateOneTimeKeys:(NSUInteger)numberOfKeys;
50
+
51
+ @end
@@ -0,0 +1,25 @@
1
+ /*
2
+ Copyright 2016 Chris Ballinger
3
+ Copyright 2016 OpenMarket Ltd
4
+ Copyright 2016 Vector Creations Ltd
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+ #include "olm/olm.h"
20
+
21
+ @interface OLMAccount()
22
+
23
+ @property (nonatomic) OlmAccount *account;
24
+
25
+ @end
@@ -0,0 +1,38 @@
1
+ /*
2
+ Copyright 2016 OpenMarket Ltd
3
+ Copyright 2016 Vector Creations Ltd
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+
18
+ #import <Foundation/Foundation.h>
19
+ #import "OLMSerializable.h"
20
+
21
+ @interface OLMInboundGroupSession : NSObject <OLMSerializable, NSSecureCoding>
22
+
23
+ - (instancetype)initInboundGroupSessionWithSessionKey:(NSString*)sessionKey error:(NSError**)error;
24
+
25
+ - (instancetype)initInboundGroupSessionWithImportedSession:(NSString*)sessionKey error:(NSError**)error;
26
+
27
+ - (NSString*)sessionIdentifier;
28
+
29
+ /** base64 ciphertext -> UTF-8 plaintext */
30
+ - (NSString*)decryptMessage:(NSString*)message messageIndex:(NSUInteger*)messageIndex error:(NSError**)error;
31
+
32
+ - (NSUInteger)firstKnownIndex;
33
+
34
+ - (BOOL)isVerified;
35
+
36
+ - (NSString*)exportSessionAtMessageIndex:(NSUInteger)messageIndex error:(NSError**)error;
37
+
38
+ @end
@@ -0,0 +1,37 @@
1
+ /*
2
+ Copyright 2016 Chris Ballinger
3
+ Copyright 2016 OpenMarket Ltd
4
+ Copyright 2016 Vector Creations Ltd
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+ #import <Foundation/Foundation.h>
20
+
21
+ // In this header, you should import all the public headers of your framework using statements like #import <OLMKit/PublicHeader.h>
22
+
23
+ #import <OLMKit/OLMAccount.h>
24
+ #import <OLMKit/OLMSession.h>
25
+ #import <OLMKit/OLMMessage.h>
26
+ #import <OLMKit/OLMUtility.h>
27
+ #import <OLMKit/OLMInboundGroupSession.h>
28
+ #import <OLMKit/OLMOutboundGroupSession.h>
29
+ #import <OLMKit/OLMPkEncryption.h>
30
+ #import <OLMKit/OLMPkDecryption.h>
31
+
32
+ @interface OLMKit : NSObject
33
+
34
+ //! Project version string for OLMKit, the same as libolm.
35
+ + (NSString*)versionString;
36
+
37
+ @end
@@ -0,0 +1,38 @@
1
+ /*
2
+ Copyright 2016 Chris Ballinger
3
+ Copyright 2016 OpenMarket Ltd
4
+ Copyright 2016 Vector Creations Ltd
5
+
6
+ Licensed under the Apache License, Version 2.0 (the "License");
7
+ you may not use this file except in compliance with the License.
8
+ You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing, software
13
+ distributed under the License is distributed on an "AS IS" BASIS,
14
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ See the License for the specific language governing permissions and
16
+ limitations under the License.
17
+ */
18
+
19
+ #import <Foundation/Foundation.h>
20
+
21
+ /*
22
+ from olm.hh
23
+ static const size_t OLM_MESSAGE_TYPE_PRE_KEY = 0;
24
+ static const size_t OLM_MESSAGE_TYPE_MESSAGE = 1;
25
+ */
26
+ typedef NS_ENUM(NSInteger, OLMMessageType) {
27
+ OLMMessageTypePreKey = 0,
28
+ OLMMessageTypeMessage = 1
29
+ };
30
+
31
+ @interface OLMMessage : NSObject
32
+
33
+ @property (nonatomic, copy, readonly, nonnull) NSString *ciphertext;
34
+ @property (readonly) OLMMessageType type;
35
+
36
+ - (nullable instancetype) initWithCiphertext:(nonnull NSString*)ciphertext type:(OLMMessageType)type;
37
+
38
+ @end
@@ -0,0 +1,32 @@
1
+ /*
2
+ Copyright 2016 OpenMarket Ltd
3
+ Copyright 2016 Vector Creations Ltd
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ */
17
+
18
+ #import <Foundation/Foundation.h>
19
+ #import "OLMSerializable.h"
20
+
21
+ @interface OLMOutboundGroupSession : NSObject <OLMSerializable, NSSecureCoding>
22
+
23
+ - (instancetype) initOutboundGroupSession;
24
+
25
+ - (NSString*)sessionIdentifier;
26
+ - (NSUInteger)messageIndex;
27
+ - (NSString*)sessionKey;
28
+
29
+ /** UTF-8 plaintext -> base64 ciphertext */
30
+ - (NSString*)encryptMessage:(NSString*)message error:(NSError**)error;
31
+
32
+ @end
@@ -0,0 +1,71 @@
1
+ /*
2
+ Copyright 2018 New Vector Ltd
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ #import <Foundation/Foundation.h>
18
+
19
+ #import "OLMSerializable.h"
20
+ #import "OLMPkMessage.h"
21
+
22
+ NS_ASSUME_NONNULL_BEGIN
23
+
24
+ @interface OLMPkDecryption : NSObject <OLMSerializable, NSSecureCoding>
25
+
26
+ /**
27
+ Initialise the key from the private part of a key as returned by `privateKey`.
28
+
29
+ Note that the pubkey is a base64 encoded string, but the private key is
30
+ an unencoded byte array.
31
+
32
+ @param privateKey the private key part.
33
+ @param error the error if any.
34
+ @return the associated public key.
35
+ */
36
+ - (NSString *)setPrivateKey:(NSData*)privateKey error:(NSError* _Nullable *)error;
37
+
38
+ /**
39
+ Generate a new key to use for decrypting messages.
40
+
41
+ @param error the error if any.
42
+ @return the public part of the generated key.
43
+ */
44
+ - (NSString *)generateKey:(NSError* _Nullable *)error;
45
+
46
+ /**
47
+ Get the private key.
48
+
49
+ @return the private key;
50
+ */
51
+ - (NSData *)privateKey;
52
+
53
+ /**
54
+ Decrypt a ciphertext.
55
+
56
+ @param message the cipher message to decrypt.
57
+ @param error the error if any.
58
+ @return the decrypted message.
59
+ */
60
+ - (NSString *)decryptMessage:(OLMPkMessage*)message error:(NSError* _Nullable *)error;
61
+
62
+ /**
63
+ Private key length.
64
+
65
+ @return the length in bytes.
66
+ */
67
+ + (NSUInteger)privateKeyLength;
68
+
69
+ @end
70
+
71
+ NS_ASSUME_NONNULL_END