1
+ use std:: mem;
2
+ use std:: sync:: Once ;
3
+
4
+ use libc:: { self , size_t} ;
5
+ use libsodium_sys:: {
6
+ sodium_init
7
+ , sodium_mlock
8
+ , sodium_munlock,
9
+ } ;
1
10
use numpy:: { PyArray1 , PyArrayMethods } ;
2
- use pyo3:: buffer:: PyBuffer ;
3
11
use pyo3:: prelude:: * ;
4
- use pyo3:: types:: { PyByteArray , PyMemoryView } ;
12
+ use pyo3:: types:: { PyByteArray , PyCFunction } ;
5
13
use zeroize_rs:: Zeroize ;
6
14
15
+ /// The global [`sync::Once`] that ensures we only perform
16
+ /// library initialization one time.
17
+ static INIT : Once = Once :: new ( ) ;
18
+
19
+ /// A flag that returns whether this library has been safely
20
+ /// initialized.
21
+ static mut INITIALIZED : bool = false ;
22
+
7
23
/// A Python module implemented in Rust.
8
24
#[ pymodule]
9
- fn zeroize ( _py : Python , m : & PyModule ) -> PyResult < ( ) > {
25
+ fn zeroize < ' py > ( py : Python , m : & Bound < ' py , PyModule > ) -> PyResult < ( ) > {
10
26
m. add_function ( wrap_pyfunction ! ( zeroize1, m) ?) ?;
11
27
m. add_function ( wrap_pyfunction ! ( zeroize_np, m) ?) ?;
12
28
// m.add_function(wrap_pyfunction!(zeroize_mv, m)?)?;
29
+ m. add_function ( wrap_pyfunction ! ( mlock, m) ?) ?;
30
+ m. add_function ( wrap_pyfunction ! ( munlock, m) ?) ?;
31
+ m. add_function ( wrap_pyfunction ! ( mlock_np, m) ?) ?;
32
+ m. add_function ( wrap_pyfunction ! ( munlock_np, m) ?) ?;
13
33
Ok ( ( ) )
14
34
}
15
35
@@ -26,6 +46,58 @@ fn zeroize_np<'py>(arr: &Bound<'py, PyArray1<u8>>) -> PyResult<()> {
26
46
Ok ( ( ) )
27
47
}
28
48
49
+ #[ pyfunction]
50
+ fn mlock < ' py > ( arr : & Bound < ' py , PyByteArray > ) -> PyResult < ( ) > {
51
+ unsafe {
52
+ if !init ( ) {
53
+ panic ! ( "libsodium failed to initialize" )
54
+ }
55
+ if !_mlock ( arr. as_bytes_mut ( ) . as_mut_ptr ( ) ) {
56
+ panic ! ( "mlock failed" )
57
+ }
58
+ }
59
+ Ok ( ( ) )
60
+ }
61
+
62
+ #[ pyfunction]
63
+ fn mlock_np < ' py > ( arr : & Bound < ' py , PyArray1 < u8 > > ) -> PyResult < ( ) > {
64
+ unsafe {
65
+ if !init ( ) {
66
+ panic ! ( "libsodium failed to initialize" )
67
+ }
68
+ if !_mlock ( arr. as_slice_mut ( ) . unwrap ( ) . as_mut_ptr ( ) ) {
69
+ panic ! ( "mlock failed" )
70
+ }
71
+ }
72
+ Ok ( ( ) )
73
+ }
74
+
75
+ #[ pyfunction]
76
+ fn munlock < ' py > ( arr : & Bound < ' py , PyByteArray > ) -> PyResult < ( ) > {
77
+ unsafe {
78
+ if !init ( ) {
79
+ panic ! ( "libsodium failed to initialize" )
80
+ }
81
+ if !_munlock ( arr. as_bytes_mut ( ) . as_mut_ptr ( ) ) {
82
+ panic ! ( "mlock failed" )
83
+ }
84
+ }
85
+ Ok ( ( ) )
86
+ }
87
+
88
+ #[ pyfunction]
89
+ fn munlock_np < ' py > ( arr : & Bound < ' py , PyArray1 < u8 > > ) -> PyResult < ( ) > {
90
+ unsafe {
91
+ if !init ( ) {
92
+ panic ! ( "libsodium failed to initialize" )
93
+ }
94
+ if !_munlock ( arr. as_slice_mut ( ) . unwrap ( ) . as_mut_ptr ( ) ) {
95
+ panic ! ( "mlock failed" )
96
+ }
97
+ }
98
+ Ok ( ( ) )
99
+ }
100
+
29
101
// #[pyfunction]
30
102
// fn zeroize_mv<'py>(arr: &PyMemoryView, len: usize) -> PyResult<()> {
31
103
// // Get the buffer information
@@ -41,3 +113,61 @@ fn zeroize_np<'py>(arr: &Bound<'py, PyArray1<u8>>) -> PyResult<()> {
41
113
//
42
114
// Ok(())
43
115
// }
116
+
117
+ /// Initialized libsodium. This function *must* be called at least once
118
+ /// prior to using any of the other functions in this library, and
119
+ /// callers *must* verify that it returns `true`. If it returns `false`,
120
+ /// libsodium was unable to be properly set up and this library *must
121
+ /// not* be used.
122
+ ///
123
+ /// Calling it multiple times is a no-op.
124
+ pub ( crate ) fn init ( ) -> bool {
125
+ unsafe {
126
+ INIT . call_once ( || {
127
+ // NOTE: Calls to transmute fail to compile if the source
128
+ // and destination type have a different size. We (ab)use
129
+ // this fact to statically assert the size of types at
130
+ // compile-time.
131
+ //
132
+ // We assume that we can freely cast between rust array
133
+ // sizes and [`libc::size_t`]. If that's not true, DO NOT
134
+ // COMPILE.
135
+ #[ allow( clippy:: useless_transmute) ]
136
+ let _ = std:: mem:: transmute :: < usize , size_t > ( 0 ) ;
137
+
138
+ let mut failure = false ;
139
+
140
+ // sodium_init returns 0 on success, -1 on failure, and 1 if
141
+ // the library is already initialized; someone else might
142
+ // have already initialized it before us, so we only care
143
+ // about failure
144
+ failure |= sodium_init ( ) == -1 ;
145
+
146
+ INITIALIZED = !failure;
147
+ } ) ;
148
+
149
+ INITIALIZED
150
+ }
151
+ }
152
+
153
+ /// Calls the platform's underlying `mlock(2)` implementation.
154
+ unsafe fn _mlock < T > ( ptr : * mut T ) -> bool {
155
+ sodium_mlock ( ptr. cast ( ) , mem:: size_of :: < T > ( ) ) == 0
156
+ }
157
+
158
+ /// Calls the platform's underlying `munlock(2)` implementation.
159
+ unsafe fn _munlock < T > ( ptr : * mut T ) -> bool {
160
+ sodium_munlock ( ptr. cast ( ) , mem:: size_of :: < T > ( ) ) == 0
161
+ }
162
+
163
+ #[ cfg( test) ]
164
+ mod test {
165
+ use zeroize_rs:: Zeroize ;
166
+
167
+ #[ test]
168
+ fn test_zeroize ( ) {
169
+ let mut arr = [ 1 , 2 , 3 , 4 , 5 ] ;
170
+ arr. zeroize ( ) ;
171
+ assert_eq ! ( arr, [ 0 , 0 , 0 , 0 , 0 ] ) ;
172
+ }
173
+ }
0 commit comments