Skip to content

Commit 9aef21d

Browse files
committed
pyxcrypt: Wipe confident memory in a secure way.
* meson.build: Probe for system functions that securely wipe memory. * src/pyxcrypt/pyxcrypt-config.h.in: New file. * src/pyxcrypt/pyxcrypt-memerase.c: New file. * src/pyxcrypt/pyxcrypt.c: Wipe memory securely where applicable.
1 parent e319e55 commit 9aef21d

File tree

4 files changed

+119
-6
lines changed

4 files changed

+119
-6
lines changed

meson.build

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,37 @@
11
project('pyxcrypt', 'c', meson_version: '>= 1.3.0')
2+
3+
compiler = meson.get_compiler('c')
4+
conf_data = configuration_data()
25
lxcrypt = dependency('libxcrypt')
36

7+
if compiler.has_function('SecureZeroMemory', prefix : '#include <Windows.h>')
8+
conf_data.set('PYXCRYPT_HAVE_SECUREZEROMEMORY', true)
9+
else
10+
if compiler.has_function('memset_explicit', prefix : '#include <string.h>')
11+
conf_data.set('PYXCRYPT_HAVE_MEMSET_EXPLICIT', true)
12+
else
13+
if compiler.has_function('explicit_bzero', prefix : '#include <string.h>')
14+
conf_data.set('PYXCRYPT_HAVE_EXPLICIT_BZERO', true)
15+
else
16+
conf_data.set('PYXCRYPT_USE_MEMERASE_IMPL', true)
17+
endif
18+
endif
19+
endif
20+
21+
pyxcrypt_src = [
22+
'src/pyxcrypt/pyxcrypt.c',
23+
'src/pyxcrypt/pyxcrypt-memerase.c'
24+
]
25+
426
py = import('python').find_installation('python3', pure: false)
527

6-
py.extension_module('pyxcrypt',
7-
'src/pyxcrypt/pyxcrypt.c',
8-
dependencies: lxcrypt,
9-
install: true,
10-
subdir: 'pyxcrypt',
11-
limited_api: '3.2'
28+
py.extension_module(
29+
'pyxcrypt',
30+
pyxcrypt_src,
31+
dependencies: lxcrypt,
32+
install: true,
33+
subdir: 'pyxcrypt',
34+
limited_api: '3.2'
1235
)
1336

1437
py.install_sources(
@@ -31,3 +54,9 @@ test('unit-tests',
3154
run_tests,
3255
args: ['../tests'],
3356
)
57+
58+
configure_file(
59+
input : 'src/pyxcrypt/pyxcrypt-config.h.in',
60+
output : 'pyxcrypt-config.h',
61+
configuration : conf_data
62+
)

src/pyxcrypt/pyxcrypt-config.h.in

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* This file is part of pyxcrypt.
3+
*
4+
* pyxcrypt is free software: you can redistribute it and/or modify it
5+
* under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, either version 3 of
7+
* the License, or (at your option) any later version.
8+
*
9+
* pyxcrypt is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY;
11+
* without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE.
13+
* See the GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with pyxcrypt.
17+
* If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
#if !defined _PYXCRYPT_CONFIG_H_
21+
#define _PYXCRYPT_CONFIG_H_
22+
23+
#include <stddef.h>
24+
25+
#mesondefine PYXCRYPT_HAVE_SECUREZEROMEMORY
26+
#mesondefine PYXCRYPT_HAVE_MEMSET_EXPLICIT
27+
#mesondefine PYXCRYPT_HAVE_EXPLICIT_BZERO
28+
#mesondefine PYXCRYPT_USE_MEMERASE_IMPL
29+
30+
#if defined PYXCRYPT_HAVE_SECUREZEROMEMORY
31+
#include <Windows.h>
32+
#define pyxcrypt_memerase(p, l) SecureZeroMemory(p, l)
33+
#elif defined PYXCRYPT_HAVE_MEMSET_EXPLICIT
34+
#define pyxcrypt_memerase(p, l) memset_explicit(p, 0, l)
35+
#elif defined PYXCRYPT_HAVE_EXPLICIT_BZERO
36+
#define pyxcrypt_memerase(p, l) explicit_bzero(p, l)
37+
#elif defined PYXCRYPT_USE_MEMERASE_IMPL
38+
39+
#if defined __GNUC__ && __GNUC__ >= 3
40+
#define NO_INLINE __attribute__ ((__noinline__))
41+
#else
42+
#error "Don't know how to prevent function inlining"
43+
#endif
44+
45+
NO_INLINE extern void pyxcrypt_memerase(void *p, size_t l);
46+
#endif /* PYXCRYPT_USE_MEMERASE_IMPL */
47+
#endif /* _PYXCRYPT_CONFIG_H_ */

src/pyxcrypt/pyxcrypt-memerase.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* This file is part of pyxcrypt.
3+
*
4+
* pyxcrypt is free software: you can redistribute it and/or modify it
5+
* under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, either version 3 of
7+
* the License, or (at your option) any later version.
8+
*
9+
* pyxcrypt is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY;
11+
* without even the implied warranty of MERCHANTABILITY or
12+
* FITNESS FOR A PARTICULAR PURPOSE.
13+
* See the GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with pyxcrypt.
17+
* If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include <pyxcrypt-config.h>
21+
22+
#if defined PYXCRYPT_USE_MEMERASE_IMPL
23+
24+
#include <string.h>
25+
26+
/* Keep this in a seperate translation-unit,
27+
so the compiler will not start to optimize this away. */
28+
NO_INLINE void pyxcrypt_memerase(void *p, size_t l)
29+
{
30+
p = memset (p, 0, l);
31+
asm volatile ("" : : "g" (p) : "memory");
32+
}
33+
#endif /* PYXCRYPT_USE_MEMERASE_IMPL */

src/pyxcrypt/pyxcrypt.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* If not, see <https://www.gnu.org/licenses/>.
1818
*/
1919

20+
#include <pyxcrypt-config.h>
2021

2122
#if !defined(Py_LIMITED_API) || Py_LIMITED_API > 0x030a0000
2223
#include <stdio.h>
@@ -64,6 +65,7 @@ static PyObject * _crypt_gensalt(PyObject *self, PyObject *args)
6465
return NULL;
6566
}
6667
output = Py_BuildValue("z", setting);
68+
pyxcrypt_memerase(setting, CRYPT_GENSALT_OUTPUT_SIZE);
6769
free(setting);
6870

6971
return output;
@@ -99,10 +101,12 @@ static PyObject * _crypt(PyObject *self, PyObject *args)
99101
if (hash == NULL)
100102
{
101103
PyErr_SetString(PyExc_RuntimeError, strerror(errno));
104+
pyxcrypt_memerase(data, size);
102105
free(data);
103106
return NULL;
104107
}
105108
output = Py_BuildValue("z", hash);
109+
pyxcrypt_memerase(data->output, sizeof(data->output));
106110
free(data);
107111

108112
return output;

0 commit comments

Comments
 (0)