Skip to main content

opaque_borink/
lib.rs

1pub mod client;
2pub mod encoded;
3pub mod server;
4
5use base64::DecodeError;
6use opaque_ke::ciphersuite::CipherSuite;
7pub use opaque_ke::errors::ProtocolError;
8use std::fmt::{Debug, Display, Formatter};
9
10pub struct Cipher;
11impl CipherSuite for Cipher {
12    type OprfCs = opaque_ke::Ristretto255;
13    type KeGroup = opaque_ke::Ristretto255;
14    type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
15    type Ksf = argon2::Argon2<'static>;
16}
17
18#[derive(Debug)]
19pub enum Error {
20    ProtocolError(ProtocolError),
21    DecodeError(DecodeError),
22}
23
24impl Display for Error {
25    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
26        write!(f, "{:?}", &self)
27    }
28}
29
30impl std::error::Error for Error {}
31
32impl From<ProtocolError> for Error {
33    fn from(e: ProtocolError) -> Self {
34        Error::ProtocolError(e)
35    }
36}
37
38impl From<DecodeError> for Error {
39    fn from(e: DecodeError) -> Self {
40        Error::DecodeError(e)
41    }
42}
43
44pub(crate) mod opaque_impl {
45    use opaque_ke::{
46        ClientLogin, ClientLoginFinishParameters, ClientRegistration,
47        ClientRegistrationFinishParameters, CredentialFinalization, CredentialRequest,
48        CredentialResponse, RegistrationRequest, RegistrationResponse, RegistrationUpload,
49        ServerLogin, ServerLoginStartParameters, ServerRegistration,
50    };
51    use rand::{
52        rngs::{OsRng, ThreadRng},
53        thread_rng,
54    };
55
56    use super::{Cipher, Error, IntoArray};
57
58    #[repr(transparent)]
59    pub struct PasswordFile(ServerRegistration<Cipher>);
60
61    impl PasswordFile {
62        pub fn serialize(&self) -> [u8; PASSWORD_FILE_SERIALIZED_LEN] {
63            self.0.serialize().into_array()
64        }
65
66        pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
67            let registration = opaque_ke::ServerRegistration::<Cipher>::deserialize(bytes)?;
68
69            Ok(Self(registration))
70        }
71    }
72
73    pub struct ServerSetup(opaque_ke::ServerSetup<Cipher>);
74
75    impl ServerSetup {
76        pub fn create() -> Self {
77            let mut rng = OsRng;
78            let server_setup = opaque_ke::ServerSetup::<Cipher>::new(&mut rng);
79
80            Self(server_setup)
81        }
82
83        pub fn view(&self) -> ServerSetupView {
84            ServerSetupView {
85                setup: &self.0,
86                rng: thread_rng(),
87            }
88        }
89
90        pub fn serialize(&self) -> [u8; SERVER_SETUP_LEN] {
91            self.0.serialize().into_array()
92        }
93
94        pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
95            let setup = opaque_ke::ServerSetup::<Cipher>::deserialize(bytes)?;
96
97            Ok(Self(setup))
98        }
99    }
100
101    #[derive(Clone)]
102    pub struct ServerSetupView<'a> {
103        setup: &'a opaque_ke::ServerSetup<Cipher>,
104        rng: rand::rngs::ThreadRng,
105    }
106
107    pub fn server_login_start(
108        setup: &mut ServerSetupView,
109        password_file: &PasswordFile,
110        login_start_request: &[u8],
111        user_id: &str,
112    ) -> Result<ServerLoginStartResult, Error> {
113        let login_start_request = CredentialRequest::<Cipher>::deserialize(login_start_request)?;
114
115        let result = ServerLogin::<Cipher>::start(
116            &mut setup.rng,
117            setup.setup,
118            Some(password_file.0.clone()),
119            login_start_request,
120            user_id.as_bytes(),
121            ServerLoginStartParameters::default(),
122        )?;
123
124        Ok(ServerLoginStartResult {
125            response: result.message.serialize().into_array(),
126            state: result.state.serialize().into_array(),
127        })
128    }
129
130    pub struct ClientStateLogin {
131        rng: rand::rngs::ThreadRng,
132        state: Option<ClientLogin<Cipher>>,
133    }
134
135    pub fn client_login_start(
136        client_state: &mut ClientStateLogin,
137        password: &[u8],
138    ) -> Result<ClientLoginStartResult, Error> {
139        let result = ClientLogin::<Cipher>::start(&mut client_state.rng, password)?;
140
141        client_state.state = Some(result.state);
142
143        Ok(ClientLoginStartResult {
144            response: result.message.serialize().into_array(),
145        })
146    }
147
148    pub fn client_login_finish(
149        client_state: &mut ClientStateLogin,
150        password: &[u8],
151        server_message: &[u8],
152    ) -> Result<ClientLoginFinishResult, Error> {
153        if client_state.state.is_none() {
154            panic!("Client state not initialized! Run `client_login_start` first!")
155        }
156        let client_state = client_state.state.take().unwrap();
157        let server_message = CredentialResponse::<Cipher>::deserialize(server_message)?;
158        let result = client_state.finish(
159            password,
160            server_message,
161            ClientLoginFinishParameters::default(),
162        )?;
163
164        Ok(ClientLoginFinishResult {
165            response: result.message.serialize().into_array(),
166            shared_secret: result.session_key.into_array(),
167        })
168    }
169
170    pub fn server_login_finish(
171        login_finish_request: &[u8],
172        server_state: &[u8],
173    ) -> Result<ServerLoginFinishResult, Error> {
174        let state = ServerLogin::<Cipher>::deserialize(server_state)?;
175        let login_finish_request =
176            CredentialFinalization::<Cipher>::deserialize(login_finish_request)?;
177        let result = state.finish(login_finish_request)?;
178        Ok(ServerLoginFinishResult {
179            shared_secret: result.session_key.into_array(),
180        })
181    }
182
183    pub struct ClientStateRegistration {
184        rng: ThreadRng,
185        state: Option<ClientRegistration<Cipher>>,
186    }
187
188    impl ClientStateRegistration {
189        pub fn setup() -> Self {
190            Self {
191                rng: thread_rng(),
192                state: None,
193            }
194        }
195
196        pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
197            let login = ClientRegistration::<Cipher>::deserialize(bytes)?;
198
199            Ok(Self {
200                rng: thread_rng(),
201                state: Some(login),
202            })
203        }
204
205        pub fn serialize(&self) -> [u8; REGISTER_CLIENT_STATE_LEN] {
206            self.state
207                .as_ref()
208                .expect("Can only serialize after first step is completed!")
209                .serialize()
210                .into_array()
211        }
212    }
213
214    impl ClientStateLogin {
215        pub fn setup() -> Self {
216            Self {
217                rng: thread_rng(),
218                state: None,
219            }
220        }
221
222        pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
223            let login = ClientLogin::<Cipher>::deserialize(bytes)?;
224
225            Ok(Self {
226                rng: thread_rng(),
227                state: Some(login),
228            })
229        }
230
231        pub fn serialize(&self) -> [u8; LOGIN_CLIENT_STATE_LEN] {
232            self.state
233                .as_ref()
234                .expect("Can only serialize after first step is completed!")
235                .serialize()
236                .into_array()
237        }
238    }
239
240    pub fn client_register_start(
241        client_state: &mut ClientStateRegistration,
242        password: &[u8],
243    ) -> Result<ClientRegistrationStartResult, Error> {
244        let result = ClientRegistration::start(&mut client_state.rng, password)?;
245
246        client_state.state = Some(result.state);
247
248        Ok(ClientRegistrationStartResult {
249            response: result.message.serialize().into_array(),
250        })
251    }
252
253    pub fn server_register_start(
254        server_setup: &mut ServerSetupView,
255        register_start_request: &[u8],
256        user_id: &[u8],
257    ) -> Result<ServerRegistrationStartResult, Error> {
258        let register_start_request =
259            RegistrationRequest::<Cipher>::deserialize(register_start_request)?;
260
261        let result = ServerRegistration::<Cipher>::start(
262            server_setup.setup,
263            register_start_request,
264            user_id,
265        )?;
266
267        Ok(ServerRegistrationStartResult {
268            response: result.message.serialize().into_array(),
269        })
270    }
271
272    pub fn client_register_finish(
273        client_state: &mut ClientStateRegistration,
274        password: &[u8],
275        server_message: &[u8],
276    ) -> Result<ClientRegistrationFinishResult, Error> {
277        if client_state.state.is_none() {
278            panic!("Client state not initialized! Run `server_register_start` first!")
279        }
280        let state = client_state.state.take().unwrap();
281        let server_message = RegistrationResponse::deserialize(server_message)?;
282
283        let result = state.finish(
284            &mut client_state.rng,
285            password,
286            server_message,
287            ClientRegistrationFinishParameters::default(),
288        )?;
289
290        Ok(ClientRegistrationFinishResult {
291            response: result.message.serialize().into_array(),
292        })
293    }
294
295    pub fn server_register_finish(register_finish_request: &[u8]) -> Result<PasswordFile, Error> {
296        let register_finish_request =
297            RegistrationUpload::<Cipher>::deserialize(register_finish_request)?;
298
299        let result = ServerRegistration::finish(register_finish_request);
300
301        Ok(PasswordFile(result))
302    }
303
304    pub const SERVER_SETUP_LEN: usize = 128;
305
306    pub const LOGIN_SERVER_MESSAGE_LEN: usize = 320;
307    pub const LOGIN_SERVER_STATE_LEN: usize = 192;
308    pub const LOGIN_CLIENT_STATE_LEN: usize = 192;
309    pub const LOGIN_CLIENT_MESSAGE_LEN: usize = 96;
310    pub const LOGIN_FINISH_MESSAGE_LEN: usize = 64;
311
312    pub const REGISTER_SERVER_MESSAGE_LEN: usize = 64;
313    pub const REGISTER_CLIENT_STATE_LEN: usize = 64;
314    pub const REGISTER_CLIENT_MESSAGE_LEN: usize = 32;
315    pub const REGISTER_FINISH_MESSAGE_LEN: usize = 192;
316
317    pub const SHARED_SECRET_LEN: usize = 64;
318
319    pub const PASSWORD_FILE_LEN: usize = 328;
320    pub const PASSWORD_FILE_SERIALIZED_LEN: usize = 192;
321
322    pub struct ServerLoginStartResult {
323        pub response: [u8; LOGIN_SERVER_MESSAGE_LEN],
324        pub state: [u8; LOGIN_SERVER_STATE_LEN],
325    }
326
327    pub struct ClientLoginStartResult {
328        pub response: [u8; LOGIN_CLIENT_MESSAGE_LEN],
329    }
330
331    pub struct ClientLoginFinishResult {
332        pub response: [u8; LOGIN_FINISH_MESSAGE_LEN],
333        pub shared_secret: [u8; SHARED_SECRET_LEN],
334    }
335
336    pub struct ServerLoginFinishResult {
337        pub shared_secret: [u8; SHARED_SECRET_LEN],
338    }
339
340    pub struct ClientRegistrationStartResult {
341        pub response: [u8; REGISTER_CLIENT_MESSAGE_LEN],
342    }
343
344    pub struct ClientRegistrationFinishResult {
345        pub response: [u8; REGISTER_FINISH_MESSAGE_LEN],
346    }
347
348    pub struct ServerRegistrationStartResult {
349        pub response: [u8; REGISTER_SERVER_MESSAGE_LEN],
350    }
351
352    #[cfg(test)]
353    mod test {
354        use opaque_ke::{ClientLogin, ClientRegistration};
355
356        use super::*;
357
358        #[test]
359        fn check_lengths() {
360            let mut rng = OsRng;
361            let server_setup = opaque_ke::ServerSetup::<Cipher>::new(&mut rng);
362
363            assert_eq!(SERVER_SETUP_LEN, server_setup.serialize().len());
364
365            let a = ClientRegistration::start(&mut rng, "my_pass".as_bytes()).unwrap();
366
367            assert_eq!(REGISTER_CLIENT_MESSAGE_LEN, a.message.serialize().len());
368            assert_eq!(
369                a.message.serialize().as_slice(),
370                a.message
371                    .serialize()
372                    .into_array::<REGISTER_CLIENT_MESSAGE_LEN>()
373                    .as_slice()
374            );
375            assert_eq!(REGISTER_CLIENT_STATE_LEN, a.state.serialize().len());
376
377            let b =
378                ServerRegistration::start(&server_setup, a.message, "my_user".as_bytes()).unwrap();
379
380            assert_eq!(REGISTER_SERVER_MESSAGE_LEN, b.message.serialize().len());
381            assert_eq!(
382                b.message.serialize().as_slice(),
383                b.message
384                    .serialize()
385                    .into_array::<REGISTER_SERVER_MESSAGE_LEN>()
386                    .as_slice()
387            );
388
389            let c = a
390                .state
391                .finish(
392                    &mut rng,
393                    "my_pass".as_bytes(),
394                    b.message,
395                    opaque_ke::ClientRegistrationFinishParameters::default(),
396                )
397                .unwrap();
398
399            assert_eq!(REGISTER_FINISH_MESSAGE_LEN, c.message.serialize().len());
400            assert_eq!(
401                c.message.serialize().as_slice(),
402                c.message
403                    .serialize()
404                    .into_array::<REGISTER_FINISH_MESSAGE_LEN>()
405                    .as_slice()
406            );
407
408            let pw_file = ServerRegistration::finish(c.message);
409
410            assert_eq!(
411                size_of_val(&PasswordFile(pw_file.clone())),
412                PASSWORD_FILE_LEN
413            );
414            assert_eq!(size_of::<PasswordFile>(), PASSWORD_FILE_LEN);
415
416            let d = ClientLogin::<Cipher>::start(&mut rng, "my_pass".as_bytes()).unwrap();
417
418            assert_eq!(LOGIN_CLIENT_MESSAGE_LEN, d.message.serialize().len());
419            assert_eq!(
420                d.message.serialize().as_slice(),
421                d.message
422                    .serialize()
423                    .into_array::<LOGIN_CLIENT_MESSAGE_LEN>()
424                    .as_slice()
425            );
426            assert_eq!(LOGIN_CLIENT_STATE_LEN, d.state.serialize().len());
427
428            let e = ServerLogin::<Cipher>::start(
429                &mut rng,
430                &server_setup,
431                Some(pw_file.clone()),
432                d.message,
433                "my_user".as_bytes(),
434                opaque_ke::ServerLoginStartParameters::default(),
435            )
436            .unwrap();
437
438            let f: [u8; LOGIN_SERVER_MESSAGE_LEN] = e.message.serialize().into_array();
439            let g: [u8; LOGIN_SERVER_MESSAGE_LEN] =
440                unsafe { core::mem::transmute(e.message.serialize()) };
441
442            assert_eq!(&f, e.message.serialize().as_slice());
443            assert_eq!(&g, &f);
444            assert_eq!(LOGIN_SERVER_MESSAGE_LEN, e.message.serialize().len());
445            assert_eq!(LOGIN_SERVER_STATE_LEN, e.state.serialize().len());
446
447            let h = d
448                .state
449                .finish(
450                    "my_pass".as_bytes(),
451                    e.message,
452                    ClientLoginFinishParameters::default(),
453                )
454                .unwrap();
455
456            assert_eq!(LOGIN_FINISH_MESSAGE_LEN, h.message.serialize().len());
457            assert_eq!(
458                h.message.serialize().as_slice(),
459                h.message
460                    .serialize()
461                    .into_array::<LOGIN_FINISH_MESSAGE_LEN>()
462            );
463            assert_eq!(64, h.session_key.len());
464        }
465    }
466}
467
468#[cfg(test)]
469pub mod test_util {
470    use super::opaque_impl::*;
471
472    pub fn gen_password_file_with_setup_and_pw(setup: &mut ServerSetupView, user_id: &[u8], password: &[u8]) -> PasswordFile {
473        let mut client_state = ClientStateRegistration::setup();
474
475        let client_start = client_register_start(&mut client_state, password).unwrap();
476        
477        let server_start = server_register_start(setup, &client_start.response, user_id).unwrap();
478
479        let client_finish = client_register_finish(&mut client_state, password, &server_start.response).unwrap();
480
481        let server_finish = server_register_finish(&client_finish.response).unwrap();
482
483        server_finish
484    }
485}
486
487// The following code is taken from version 1.1.1 of https://github.com/fizyk20/generic-array under the MIT License
488// It's a backport of some functions that allow conversion to normal arrays to the version of generic array used in opaque_ke (0.14.7)
489mod generic_array_backport {
490    use generic_array::{ArrayLength, GenericArray};
491    use typenum::{Const, ToUInt};
492
493    const unsafe fn const_transmute<A, B>(a: A) -> B {
494        if std::mem::size_of::<A>() != std::mem::size_of::<B>() {
495            panic!("Size mismatch for generic_array::const_transmute");
496        }
497
498        #[repr(C)]
499        union Union<A, B> {
500            a: std::mem::ManuallyDrop<A>,
501            b: std::mem::ManuallyDrop<B>,
502        }
503
504        let a = std::mem::ManuallyDrop::new(a);
505        std::mem::ManuallyDrop::into_inner(Union { a }.b)
506    }
507
508    pub trait IntoArray<N: ArrayLength<u8>> {
509        fn into_array<const U: usize>(self) -> [u8; U]
510        where
511            Const<U>: IntoArrayLength<ArrayLength = N>,
512            Self: Sized;
513    }
514
515    impl<N: ArrayLength<u8>> IntoArray<N> for GenericArray<u8, N> {
516        fn into_array<const U: usize>(self) -> [u8; U]
517        where
518            Const<U>: IntoArrayLength<ArrayLength = N>,
519            Self: Sized,
520        {
521            unsafe { const_transmute(self) }
522        }
523    }
524
525    pub trait IntoArrayLength {
526        /// The associated `ArrayLength`
527        type ArrayLength: ArrayLength<u8>;
528    }
529
530    impl<const N: usize> IntoArrayLength for Const<N>
531    where
532        Const<N>: ToUInt,
533        typenum::U<N>: ArrayLength<u8>,
534    {
535        type ArrayLength = typenum::U<N>;
536    }
537}
538
539pub(crate) use generic_array_backport::IntoArray;