ruby_olm 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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,462 @@
1
+ /* Copyright 2015, 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
+ #include "olm/session.hh"
16
+ #include "olm/cipher.h"
17
+ #include "olm/crypto.h"
18
+ #include "olm/account.hh"
19
+ #include "olm/memory.hh"
20
+ #include "olm/message.hh"
21
+ #include "olm/pickle.hh"
22
+
23
+ #include <cstring>
24
+
25
+ namespace {
26
+
27
+ static const std::uint8_t PROTOCOL_VERSION = 0x3;
28
+
29
+ static const std::uint8_t ROOT_KDF_INFO[] = "OLM_ROOT";
30
+ static const std::uint8_t RATCHET_KDF_INFO[] = "OLM_RATCHET";
31
+ static const std::uint8_t CIPHER_KDF_INFO[] = "OLM_KEYS";
32
+
33
+ static const olm::KdfInfo OLM_KDF_INFO = {
34
+ ROOT_KDF_INFO, sizeof(ROOT_KDF_INFO) - 1,
35
+ RATCHET_KDF_INFO, sizeof(RATCHET_KDF_INFO) - 1
36
+ };
37
+
38
+ static const struct _olm_cipher_aes_sha_256 OLM_CIPHER =
39
+ OLM_CIPHER_INIT_AES_SHA_256(CIPHER_KDF_INFO);
40
+
41
+ } // namespace
42
+
43
+ olm::Session::Session(
44
+ ) : ratchet(OLM_KDF_INFO, OLM_CIPHER_BASE(&OLM_CIPHER)),
45
+ last_error(OlmErrorCode::OLM_SUCCESS),
46
+ received_message(false) {
47
+
48
+ }
49
+
50
+
51
+ std::size_t olm::Session::new_outbound_session_random_length() {
52
+ return CURVE25519_RANDOM_LENGTH * 2;
53
+ }
54
+
55
+
56
+ std::size_t olm::Session::new_outbound_session(
57
+ olm::Account const & local_account,
58
+ _olm_curve25519_public_key const & identity_key,
59
+ _olm_curve25519_public_key const & one_time_key,
60
+ std::uint8_t const * random, std::size_t random_length
61
+ ) {
62
+ if (random_length < new_outbound_session_random_length()) {
63
+ last_error = OlmErrorCode::OLM_NOT_ENOUGH_RANDOM;
64
+ return std::size_t(-1);
65
+ }
66
+
67
+ _olm_curve25519_key_pair base_key;
68
+ _olm_crypto_curve25519_generate_key(random, &base_key);
69
+
70
+ _olm_curve25519_key_pair ratchet_key;
71
+ _olm_crypto_curve25519_generate_key(random + CURVE25519_RANDOM_LENGTH, &ratchet_key);
72
+
73
+ _olm_curve25519_key_pair const & alice_identity_key_pair = (
74
+ local_account.identity_keys.curve25519_key
75
+ );
76
+
77
+ received_message = false;
78
+ alice_identity_key = alice_identity_key_pair.public_key;
79
+ alice_base_key = base_key.public_key;
80
+ bob_one_time_key = one_time_key;
81
+
82
+ // Calculate the shared secret S via triple DH
83
+ std::uint8_t secret[3 * CURVE25519_SHARED_SECRET_LENGTH];
84
+ std::uint8_t * pos = secret;
85
+
86
+ _olm_crypto_curve25519_shared_secret(&alice_identity_key_pair, &one_time_key, pos);
87
+ pos += CURVE25519_SHARED_SECRET_LENGTH;
88
+ _olm_crypto_curve25519_shared_secret(&base_key, &identity_key, pos);
89
+ pos += CURVE25519_SHARED_SECRET_LENGTH;
90
+ _olm_crypto_curve25519_shared_secret(&base_key, &one_time_key, pos);
91
+
92
+ ratchet.initialise_as_alice(secret, sizeof(secret), ratchet_key);
93
+
94
+ olm::unset(base_key);
95
+ olm::unset(ratchet_key);
96
+ olm::unset(secret);
97
+
98
+ return std::size_t(0);
99
+ }
100
+
101
+ namespace {
102
+
103
+ static bool check_message_fields(
104
+ olm::PreKeyMessageReader & reader, bool have_their_identity_key
105
+ ) {
106
+ bool ok = true;
107
+ ok = ok && (have_their_identity_key || reader.identity_key);
108
+ if (reader.identity_key) {
109
+ ok = ok && reader.identity_key_length == CURVE25519_KEY_LENGTH;
110
+ }
111
+ ok = ok && reader.message;
112
+ ok = ok && reader.base_key;
113
+ ok = ok && reader.base_key_length == CURVE25519_KEY_LENGTH;
114
+ ok = ok && reader.one_time_key;
115
+ ok = ok && reader.one_time_key_length == CURVE25519_KEY_LENGTH;
116
+ return ok;
117
+ }
118
+
119
+ } // namespace
120
+
121
+
122
+ std::size_t olm::Session::new_inbound_session(
123
+ olm::Account & local_account,
124
+ _olm_curve25519_public_key const * their_identity_key,
125
+ std::uint8_t const * one_time_key_message, std::size_t message_length
126
+ ) {
127
+ olm::PreKeyMessageReader reader;
128
+ decode_one_time_key_message(reader, one_time_key_message, message_length);
129
+
130
+ if (!check_message_fields(reader, their_identity_key)) {
131
+ last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
132
+ return std::size_t(-1);
133
+ }
134
+
135
+ if (reader.identity_key && their_identity_key) {
136
+ bool same = 0 == std::memcmp(
137
+ their_identity_key->public_key, reader.identity_key, CURVE25519_KEY_LENGTH
138
+ );
139
+ if (!same) {
140
+ last_error = OlmErrorCode::OLM_BAD_MESSAGE_KEY_ID;
141
+ return std::size_t(-1);
142
+ }
143
+ }
144
+
145
+ olm::load_array(alice_identity_key.public_key, reader.identity_key);
146
+ olm::load_array(alice_base_key.public_key, reader.base_key);
147
+ olm::load_array(bob_one_time_key.public_key, reader.one_time_key);
148
+
149
+ olm::MessageReader message_reader;
150
+ decode_message(
151
+ message_reader, reader.message, reader.message_length,
152
+ ratchet.ratchet_cipher->ops->mac_length(ratchet.ratchet_cipher)
153
+ );
154
+
155
+ if (!message_reader.ratchet_key
156
+ || message_reader.ratchet_key_length != CURVE25519_KEY_LENGTH) {
157
+ last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
158
+ return std::size_t(-1);
159
+ }
160
+
161
+ _olm_curve25519_public_key ratchet_key;
162
+ olm::load_array(ratchet_key.public_key, message_reader.ratchet_key);
163
+
164
+ olm::OneTimeKey const * our_one_time_key = local_account.lookup_key(
165
+ bob_one_time_key
166
+ );
167
+
168
+ if (!our_one_time_key) {
169
+ last_error = OlmErrorCode::OLM_BAD_MESSAGE_KEY_ID;
170
+ return std::size_t(-1);
171
+ }
172
+
173
+ _olm_curve25519_key_pair const & bob_identity_key = (
174
+ local_account.identity_keys.curve25519_key
175
+ );
176
+ _olm_curve25519_key_pair const & bob_one_time_key = our_one_time_key->key;
177
+
178
+ // Calculate the shared secret S via triple DH
179
+ std::uint8_t secret[CURVE25519_SHARED_SECRET_LENGTH * 3];
180
+ std::uint8_t * pos = secret;
181
+ _olm_crypto_curve25519_shared_secret(&bob_one_time_key, &alice_identity_key, pos);
182
+ pos += CURVE25519_SHARED_SECRET_LENGTH;
183
+ _olm_crypto_curve25519_shared_secret(&bob_identity_key, &alice_base_key, pos);
184
+ pos += CURVE25519_SHARED_SECRET_LENGTH;
185
+ _olm_crypto_curve25519_shared_secret(&bob_one_time_key, &alice_base_key, pos);
186
+
187
+ ratchet.initialise_as_bob(secret, sizeof(secret), ratchet_key);
188
+
189
+ olm::unset(secret);
190
+
191
+ return std::size_t(0);
192
+ }
193
+
194
+
195
+ std::size_t olm::Session::session_id_length() {
196
+ return SHA256_OUTPUT_LENGTH;
197
+ }
198
+
199
+
200
+ std::size_t olm::Session::session_id(
201
+ std::uint8_t * id, std::size_t id_length
202
+ ) {
203
+ if (id_length < session_id_length()) {
204
+ last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
205
+ return std::size_t(-1);
206
+ }
207
+ std::uint8_t tmp[CURVE25519_KEY_LENGTH * 3];
208
+ std::uint8_t * pos = tmp;
209
+ pos = olm::store_array(pos, alice_identity_key.public_key);
210
+ pos = olm::store_array(pos, alice_base_key.public_key);
211
+ pos = olm::store_array(pos, bob_one_time_key.public_key);
212
+ _olm_crypto_sha256(tmp, sizeof(tmp), id);
213
+ return session_id_length();
214
+ }
215
+
216
+
217
+ bool olm::Session::matches_inbound_session(
218
+ _olm_curve25519_public_key const * their_identity_key,
219
+ std::uint8_t const * one_time_key_message, std::size_t message_length
220
+ ) {
221
+ olm::PreKeyMessageReader reader;
222
+ decode_one_time_key_message(reader, one_time_key_message, message_length);
223
+
224
+ if (!check_message_fields(reader, their_identity_key)) {
225
+ return false;
226
+ }
227
+
228
+ bool same = true;
229
+ if (reader.identity_key) {
230
+ same = same && 0 == std::memcmp(
231
+ reader.identity_key, alice_identity_key.public_key, CURVE25519_KEY_LENGTH
232
+ );
233
+ }
234
+ if (their_identity_key) {
235
+ same = same && 0 == std::memcmp(
236
+ their_identity_key->public_key, alice_identity_key.public_key,
237
+ CURVE25519_KEY_LENGTH
238
+ );
239
+ }
240
+ same = same && 0 == std::memcmp(
241
+ reader.base_key, alice_base_key.public_key, CURVE25519_KEY_LENGTH
242
+ );
243
+ same = same && 0 == std::memcmp(
244
+ reader.one_time_key, bob_one_time_key.public_key, CURVE25519_KEY_LENGTH
245
+ );
246
+ return same;
247
+ }
248
+
249
+
250
+ olm::MessageType olm::Session::encrypt_message_type() {
251
+ if (received_message) {
252
+ return olm::MessageType::MESSAGE;
253
+ } else {
254
+ return olm::MessageType::PRE_KEY;
255
+ }
256
+ }
257
+
258
+
259
+ std::size_t olm::Session::encrypt_message_length(
260
+ std::size_t plaintext_length
261
+ ) {
262
+ std::size_t message_length = ratchet.encrypt_output_length(
263
+ plaintext_length
264
+ );
265
+
266
+ if (received_message) {
267
+ return message_length;
268
+ }
269
+
270
+ return encode_one_time_key_message_length(
271
+ CURVE25519_KEY_LENGTH,
272
+ CURVE25519_KEY_LENGTH,
273
+ CURVE25519_KEY_LENGTH,
274
+ message_length
275
+ );
276
+ }
277
+
278
+
279
+ std::size_t olm::Session::encrypt_random_length() {
280
+ return ratchet.encrypt_random_length();
281
+ }
282
+
283
+
284
+ std::size_t olm::Session::encrypt(
285
+ std::uint8_t const * plaintext, std::size_t plaintext_length,
286
+ std::uint8_t const * random, std::size_t random_length,
287
+ std::uint8_t * message, std::size_t message_length
288
+ ) {
289
+ if (message_length < encrypt_message_length(plaintext_length)) {
290
+ last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
291
+ return std::size_t(-1);
292
+ }
293
+ std::uint8_t * message_body;
294
+ std::size_t message_body_length = ratchet.encrypt_output_length(
295
+ plaintext_length
296
+ );
297
+
298
+ if (received_message) {
299
+ message_body = message;
300
+ } else {
301
+ olm::PreKeyMessageWriter writer;
302
+ encode_one_time_key_message(
303
+ writer,
304
+ PROTOCOL_VERSION,
305
+ CURVE25519_KEY_LENGTH,
306
+ CURVE25519_KEY_LENGTH,
307
+ CURVE25519_KEY_LENGTH,
308
+ message_body_length,
309
+ message
310
+ );
311
+ olm::store_array(writer.one_time_key, bob_one_time_key.public_key);
312
+ olm::store_array(writer.identity_key, alice_identity_key.public_key);
313
+ olm::store_array(writer.base_key, alice_base_key.public_key);
314
+ message_body = writer.message;
315
+ }
316
+
317
+ std::size_t result = ratchet.encrypt(
318
+ plaintext, plaintext_length,
319
+ random, random_length,
320
+ message_body, message_body_length
321
+ );
322
+
323
+ if (result == std::size_t(-1)) {
324
+ last_error = ratchet.last_error;
325
+ ratchet.last_error = OlmErrorCode::OLM_SUCCESS;
326
+ return result;
327
+ }
328
+
329
+ return result;
330
+ }
331
+
332
+
333
+ std::size_t olm::Session::decrypt_max_plaintext_length(
334
+ MessageType message_type,
335
+ std::uint8_t const * message, std::size_t message_length
336
+ ) {
337
+ std::uint8_t const * message_body;
338
+ std::size_t message_body_length;
339
+ if (message_type == olm::MessageType::MESSAGE) {
340
+ message_body = message;
341
+ message_body_length = message_length;
342
+ } else {
343
+ olm::PreKeyMessageReader reader;
344
+ decode_one_time_key_message(reader, message, message_length);
345
+ if (!reader.message) {
346
+ last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
347
+ return std::size_t(-1);
348
+ }
349
+ message_body = reader.message;
350
+ message_body_length = reader.message_length;
351
+ }
352
+
353
+ std::size_t result = ratchet.decrypt_max_plaintext_length(
354
+ message_body, message_body_length
355
+ );
356
+
357
+ if (result == std::size_t(-1)) {
358
+ last_error = ratchet.last_error;
359
+ ratchet.last_error = OlmErrorCode::OLM_SUCCESS;
360
+ }
361
+ return result;
362
+ }
363
+
364
+
365
+ std::size_t olm::Session::decrypt(
366
+ olm::MessageType message_type,
367
+ std::uint8_t const * message, std::size_t message_length,
368
+ std::uint8_t * plaintext, std::size_t max_plaintext_length
369
+ ) {
370
+ std::uint8_t const * message_body;
371
+ std::size_t message_body_length;
372
+ if (message_type == olm::MessageType::MESSAGE) {
373
+ message_body = message;
374
+ message_body_length = message_length;
375
+ } else {
376
+ olm::PreKeyMessageReader reader;
377
+ decode_one_time_key_message(reader, message, message_length);
378
+ if (!reader.message) {
379
+ last_error = OlmErrorCode::OLM_BAD_MESSAGE_FORMAT;
380
+ return std::size_t(-1);
381
+ }
382
+ message_body = reader.message;
383
+ message_body_length = reader.message_length;
384
+ }
385
+
386
+ std::size_t result = ratchet.decrypt(
387
+ message_body, message_body_length, plaintext, max_plaintext_length
388
+ );
389
+
390
+ if (result == std::size_t(-1)) {
391
+ last_error = ratchet.last_error;
392
+ ratchet.last_error = OlmErrorCode::OLM_SUCCESS;
393
+ return result;
394
+ }
395
+
396
+ received_message = true;
397
+ return result;
398
+ }
399
+
400
+ namespace {
401
+ // the master branch writes pickle version 1; the logging_enabled branch writes
402
+ // 0x80000001.
403
+ static const std::uint32_t SESSION_PICKLE_VERSION = 1;
404
+ }
405
+
406
+ std::size_t olm::pickle_length(
407
+ Session const & value
408
+ ) {
409
+ std::size_t length = 0;
410
+ length += olm::pickle_length(SESSION_PICKLE_VERSION);
411
+ length += olm::pickle_length(value.received_message);
412
+ length += olm::pickle_length(value.alice_identity_key);
413
+ length += olm::pickle_length(value.alice_base_key);
414
+ length += olm::pickle_length(value.bob_one_time_key);
415
+ length += olm::pickle_length(value.ratchet);
416
+ return length;
417
+ }
418
+
419
+
420
+ std::uint8_t * olm::pickle(
421
+ std::uint8_t * pos,
422
+ Session const & value
423
+ ) {
424
+ pos = olm::pickle(pos, SESSION_PICKLE_VERSION);
425
+ pos = olm::pickle(pos, value.received_message);
426
+ pos = olm::pickle(pos, value.alice_identity_key);
427
+ pos = olm::pickle(pos, value.alice_base_key);
428
+ pos = olm::pickle(pos, value.bob_one_time_key);
429
+ pos = olm::pickle(pos, value.ratchet);
430
+ return pos;
431
+ }
432
+
433
+
434
+ std::uint8_t const * olm::unpickle(
435
+ std::uint8_t const * pos, std::uint8_t const * end,
436
+ Session & value
437
+ ) {
438
+ uint32_t pickle_version;
439
+ pos = olm::unpickle(pos, end, pickle_version);
440
+
441
+ bool includes_chain_index;
442
+ switch (pickle_version) {
443
+ case 1:
444
+ includes_chain_index = false;
445
+ break;
446
+
447
+ case 0x80000001UL:
448
+ includes_chain_index = true;
449
+ break;
450
+
451
+ default:
452
+ value.last_error = OlmErrorCode::OLM_UNKNOWN_PICKLE_VERSION;
453
+ return end;
454
+ }
455
+
456
+ pos = olm::unpickle(pos, end, value.received_message);
457
+ pos = olm::unpickle(pos, end, value.alice_identity_key);
458
+ pos = olm::unpickle(pos, end, value.alice_base_key);
459
+ pos = olm::unpickle(pos, end, value.bob_one_time_key);
460
+ pos = olm::unpickle(pos, end, value.ratchet, includes_chain_index);
461
+ return pos;
462
+ }
@@ -0,0 +1,57 @@
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
+
16
+ #include "olm/utility.hh"
17
+ #include "olm/crypto.h"
18
+
19
+
20
+ olm::Utility::Utility(
21
+ ) : last_error(OlmErrorCode::OLM_SUCCESS) {
22
+ }
23
+
24
+
25
+ size_t olm::Utility::sha256_length() {
26
+ return SHA256_OUTPUT_LENGTH;
27
+ }
28
+
29
+
30
+ size_t olm::Utility::sha256(
31
+ std::uint8_t const * input, std::size_t input_length,
32
+ std::uint8_t * output, std::size_t output_length
33
+ ) {
34
+ if (output_length < sha256_length()) {
35
+ last_error = OlmErrorCode::OLM_OUTPUT_BUFFER_TOO_SMALL;
36
+ return std::size_t(-1);
37
+ }
38
+ _olm_crypto_sha256(input, input_length, output);
39
+ return SHA256_OUTPUT_LENGTH;
40
+ }
41
+
42
+
43
+ size_t olm::Utility::ed25519_verify(
44
+ _olm_ed25519_public_key const & key,
45
+ std::uint8_t const * message, std::size_t message_length,
46
+ std::uint8_t const * signature, std::size_t signature_length
47
+ ) {
48
+ if (signature_length < ED25519_SIGNATURE_LENGTH) {
49
+ last_error = OlmErrorCode::OLM_BAD_MESSAGE_MAC;
50
+ return std::size_t(-1);
51
+ }
52
+ if (!_olm_crypto_ed25519_verify(&key, message, message_length, signature)) {
53
+ last_error = OlmErrorCode::OLM_BAD_MESSAGE_MAC;
54
+ return std::size_t(-1);
55
+ }
56
+ return std::size_t(0);
57
+ }
@@ -0,0 +1,107 @@
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 <cstring>
16
+ #include <iostream>
17
+ #include <iomanip>
18
+ #include <cstdlib>
19
+
20
+
21
+ std::ostream & print_hex(
22
+ std::ostream & os,
23
+ std::uint8_t const * data,
24
+ std::size_t length
25
+ ) {
26
+ for (std::size_t i = 0; i < length; i++) {
27
+ os << std::setw(2) << std::setfill('0') << std::right
28
+ << std::hex << (int) data[i];
29
+ }
30
+ return os;
31
+ }
32
+
33
+
34
+ char const * TEST_CASE;
35
+
36
+
37
+ template<typename T>
38
+ void assert_equals(
39
+ const char *file,
40
+ unsigned line,
41
+ const char *expected_expr,
42
+ const char *actual_expr,
43
+ T const & expected,
44
+ T const & actual
45
+ ) {
46
+ if (expected != actual) {
47
+ std::cout << "FAILED: " << TEST_CASE << std::endl;
48
+ std::cout << file << ":" << line << std::endl;
49
+ std::cout << expected_expr << " == " << actual_expr << std::endl;
50
+ std::cout << "Expected: " << expected << std::endl;
51
+ std::cout << "Actual: " << actual << std::endl;
52
+ std::exit(1);
53
+ }
54
+ }
55
+
56
+ template<typename T>
57
+ void assert_not_equals(
58
+ const char *file,
59
+ unsigned line,
60
+ const char *expected_expr,
61
+ const char *actual_expr,
62
+ T const & expected,
63
+ T const & actual
64
+ ) {
65
+ if (expected == actual) {
66
+ std::cout << "FAILED: " << TEST_CASE << std::endl;
67
+ std::cout << file << ":" << line << std::endl;
68
+ std::cout << expected_expr << " == " << actual_expr << std::endl;
69
+ std::cout << "Unexpected: " << expected << std::endl;
70
+ std::cout << "Actual: " << actual << std::endl;
71
+ std::exit(1);
72
+ }
73
+ }
74
+
75
+
76
+ void assert_equals(
77
+ const char *file,
78
+ unsigned line,
79
+ const char *expected_expr,
80
+ const char *actual_expr,
81
+ std::uint8_t const * expected,
82
+ std::uint8_t const * actual,
83
+ std::size_t length
84
+ ) {
85
+ if (std::memcmp(expected, actual, length)) {
86
+ std::cout << "FAILED: " << TEST_CASE << std::endl;
87
+ std::cout << file << ":" << line << std::endl;
88
+ std::cout << expected_expr << " == " << actual_expr << std::endl;
89
+ print_hex(std::cout << "Expected: ", expected, length) << std::endl;
90
+ print_hex(std::cout << "Actual: ", actual, length) << std::endl;
91
+ std::exit(1);
92
+ }
93
+ }
94
+
95
+ #define assert_equals(expected, actual, ...) assert_equals( \
96
+ __FILE__, __LINE__, #expected, #actual, expected, actual, ##__VA_ARGS__ \
97
+ )
98
+
99
+ #define assert_not_equals(expected, actual, ...) assert_not_equals( \
100
+ __FILE__, __LINE__, #expected, #actual, expected, actual, ##__VA_ARGS__ \
101
+ )
102
+
103
+ class TestCase {
104
+ public:
105
+ TestCase(const char *name) { TEST_CASE = name; }
106
+ ~TestCase() { std::cout << "PASSED: " << TEST_CASE << std::endl; }
107
+ };
@@ -0,0 +1,70 @@
1
+ #include "olm/base64.hh"
2
+ #include "olm/base64.h"
3
+ #include "unittest.hh"
4
+
5
+ int main() {
6
+
7
+ { /* Base64 encode test */
8
+ TestCase test_case("Base64 C++ binding encode test");
9
+
10
+ std::uint8_t input[] = "Hello World";
11
+ std::uint8_t expected_output[] = "SGVsbG8gV29ybGQ";
12
+ std::size_t input_length = sizeof(input) - 1;
13
+
14
+ std::size_t output_length = olm::encode_base64_length(input_length);
15
+ assert_equals(std::size_t(15), output_length);
16
+
17
+ std::uint8_t output[output_length];
18
+ olm::encode_base64(input, input_length, output);
19
+ assert_equals(expected_output, output, output_length);
20
+ }
21
+
22
+ {
23
+ TestCase test_case("Base64 C binding encode test");
24
+
25
+ std::uint8_t input[] = "Hello World";
26
+ std::uint8_t expected_output[] = "SGVsbG8gV29ybGQ";
27
+ std::size_t input_length = sizeof(input) - 1;
28
+
29
+ std::size_t output_length = ::_olm_encode_base64_length(input_length);
30
+ assert_equals(std::size_t(15), output_length);
31
+
32
+ std::uint8_t output[output_length];
33
+ output_length = ::_olm_encode_base64(input, input_length, output);
34
+ assert_equals(std::size_t(15), output_length);
35
+ assert_equals(expected_output, output, output_length);
36
+ }
37
+
38
+ { /* Base64 decode test */
39
+ TestCase test_case("Base64 C++ binding decode test");
40
+
41
+ std::uint8_t input[] = "SGVsbG8gV29ybGQ";
42
+ std::uint8_t expected_output[] = "Hello World";
43
+ std::size_t input_length = sizeof(input) - 1;
44
+
45
+ std::size_t output_length = olm::decode_base64_length(input_length);
46
+ assert_equals(std::size_t(11), output_length);
47
+
48
+ std::uint8_t output[output_length];
49
+ olm::decode_base64(input, input_length, output);
50
+ assert_equals(expected_output, output, output_length);
51
+ }
52
+
53
+ {
54
+ TestCase test_case("Base64 C binding decode test");
55
+
56
+ std::uint8_t input[] = "SGVsbG8gV29ybGQ";
57
+ std::uint8_t expected_output[] = "Hello World";
58
+ std::size_t input_length = sizeof(input) - 1;
59
+
60
+ std::size_t output_length = ::_olm_decode_base64_length(input_length);
61
+ assert_equals(std::size_t(11), output_length);
62
+
63
+ std::uint8_t output[output_length];
64
+ output_length = ::_olm_decode_base64(input, input_length, output);
65
+ assert_equals(std::size_t(11), output_length);
66
+ assert_equals(expected_output, output, output_length);
67
+ }
68
+
69
+
70
+ }