olm_rs/utility.rs
1// Copyright 2020 Johannes Hayeß
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//! This module wraps around all functions following the pattern `olm_utility_*`.
16
17use crate::errors::{self, OlmUtilityError};
18use crate::ByteBuf;
19use std::ffi::CStr;
20
21pub struct OlmUtility {
22 olm_utility_ptr: *mut olm_sys::OlmUtility,
23 _olm_utility_buf: ByteBuf,
24}
25
26/// Allows you to make use of crytographic hashing via SHA-2 and
27/// verifying ed25519 signatures.
28impl OlmUtility {
29 /// Creates a new instance of OlmUtility.
30 ///
31 /// # C-API equivalent
32 /// `olm_utility`
33 ///
34 pub fn new() -> Self {
35 // allocate the buffer for OlmUtility to be written into
36 let mut olm_utility_buf = ByteBuf::new(unsafe { olm_sys::olm_utility_size() });
37 let olm_utility_ptr = unsafe { olm_sys::olm_utility(olm_utility_buf.as_mut_void_ptr()) };
38
39 Self {
40 olm_utility_ptr,
41 _olm_utility_buf: olm_utility_buf,
42 }
43 }
44
45 /// Returns the last error that occurred for an OlmUtility
46 /// Since error codes are encoded as CStrings by libolm,
47 /// OlmUtilityError::Unknown is returned on an unknown error code.
48 fn last_error(olm_utility_ptr: *mut olm_sys::OlmUtility) -> OlmUtilityError {
49 let error_raw = unsafe { olm_sys::olm_utility_last_error(olm_utility_ptr) };
50 let error = unsafe { CStr::from_ptr(error_raw).to_str().unwrap() };
51
52 match error {
53 "BAD_MESSAGE_MAC" => OlmUtilityError::BadMessageMac,
54 "OUTPUT_BUFFER_TOO_SMALL" => OlmUtilityError::OutputBufferTooSmall,
55 "INVALID_BASE64" => OlmUtilityError::InvalidBase64,
56 _ => OlmUtilityError::Unknown,
57 }
58 }
59
60 /// Returns a sha256 of the supplied byte slice.
61 ///
62 /// # C-API equivalent
63 /// `olm_sha256`
64 ///
65 /// # Panics
66 /// * `OUTPUT_BUFFER_TOO_SMALL` for supplied output buffer
67 /// * on malformed UTF-8 coding of the hash provided by libolm
68 ///
69 pub fn sha256_bytes(&self, input_buf: &[u8]) -> String {
70 let output_len = unsafe { olm_sys::olm_sha256_length(self.olm_utility_ptr) };
71 let mut output_buf = vec![0; output_len];
72
73 let sha256_error = unsafe {
74 olm_sys::olm_sha256(
75 self.olm_utility_ptr,
76 input_buf.as_ptr() as *const _,
77 input_buf.len(),
78 output_buf.as_mut_ptr() as *mut _,
79 output_len,
80 )
81 };
82
83 // We assume a correct implementation of the SHA256 function here,
84 // that always returns a valid UTF-8 string.
85 let sha256_result = String::from_utf8(output_buf).unwrap();
86
87 // Errors from sha256 are fatal
88 if sha256_error == errors::olm_error() {
89 errors::handle_fatal_error(Self::last_error(self.olm_utility_ptr));
90 }
91
92 sha256_result
93 }
94
95 /// Convenience function that converts the UTF-8 message
96 /// to bytes and then calls [`sha256_bytes()`](Self::sha256_bytes()), returning its output.
97 pub fn sha256_utf8_msg(&self, msg: &str) -> String {
98 self.sha256_bytes(msg.as_bytes())
99 }
100
101 /// Verify a ed25519 signature.
102 ///
103 /// # Arugments
104 /// * `key` - The public part of the ed25519 key that signed the message.
105 /// * `message` - The message that was signed.
106 /// * `signature` - The signature of the message.
107 ///
108 /// # C-API equivalent
109 /// `olm_ed25519_verify`
110 ///
111 pub fn ed25519_verify(
112 &self,
113 key: &str,
114 message: &str,
115 signature: String,
116 ) -> Result<bool, OlmUtilityError> {
117 let ed25519_verify_error = unsafe {
118 olm_sys::olm_ed25519_verify(
119 self.olm_utility_ptr,
120 key.as_ptr() as *const _,
121 key.len(),
122 message.as_ptr() as *const _,
123 message.len(),
124 signature.as_ptr() as *mut _,
125 signature.len(),
126 )
127 };
128
129 // Since the two values are the same it is safe to copy
130 let ed25519_verify_result: usize = ed25519_verify_error;
131
132 if ed25519_verify_error == errors::olm_error() {
133 Err(Self::last_error(self.olm_utility_ptr))
134 } else {
135 Ok(ed25519_verify_result == 0)
136 }
137 }
138}
139
140impl Default for OlmUtility {
141 fn default() -> Self {
142 Self::new()
143 }
144}
145
146impl Drop for OlmUtility {
147 fn drop(&mut self) {
148 unsafe {
149 olm_sys::olm_clear_utility(self.olm_utility_ptr);
150 }
151 }
152}