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}