Skip to main content

Securely clear secrets from memory. Built on stable Rust primitives which guarantee memory is zeroed using an operation will not be 'optimized away' by the compiler. Uses a portable pure Rust implementation that works everywhere.

Project description

Zeroize

PyPI version PyPI tests

Clear secrets from memory. Built on stable Rust primitives which guarantee memory is zeroed using an operation will not be 'optimized away' by the compiler. Uses a portable pure Rust implementation that works everywhere.

It uses zeroize crate under the hood.
It can work with bytearray and numpy array.

[!WARNING] In the case of Copy-on-write fork you need to zeroize the memory before forking the child process, see example below.
Also by itself it doesn't work if memory is moved or moved to swap. You can use crypes with libc.mlock() to lock the memory, see example below.

Examples

Lock and zeroize memory

from zeroize import zeroize1, zeroize_np
import numpy as np
import ctypes


# Load the C standard library
LIBC = ctypes.CDLL("libc.so.6")
MLOCK = LIBC.mlock
MUNLOCK = LIBC.munlock

# Define mlock and munlock argument types
MLOCK.argtypes = [ctypes.c_void_p, ctypes.c_size_t]
MUNLOCK.argtypes = [ctypes.c_void_p, ctypes.c_size_t]


def lock_memory(buffer):
    """Locks the memory of the given buffer."""
    address = ctypes.addressof(ctypes.c_char.from_buffer(buffer))
    size = len(buffer)
    if MLOCK(address, size) != 0:
        raise RuntimeError("Failed to lock memory")


def unlock_memory(buffer):
    """Unlocks the memory of the given buffer."""
    address = ctypes.addressof(ctypes.c_char.from_buffer(buffer))
    size = len(buffer)
    if MUNLOCK(address, size) != 0:
        raise RuntimeError("Failed to unlock memory")


try:
    print("allocate memory")

    # regular array
    arr = bytearray(b"1234567890")

    # numpy array
    arr_np = np.array([0] * 10, dtype=np.uint8)
    arr_np[:] = arr
    assert arr_np.tobytes() == b"1234567890"

    print("locking memory")

    lock_memory(arr)
    lock_memory(arr_np)

    print("zeroize'ing...: ")
    zeroize1(arr)
    zeroize_np(arr_np)

    print("checking if is zeroized")
    assert arr == bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
    assert all(arr_np == 0)

    print("all good, bye!")
finally:
    # Unlock the memory
    print("unlocking memory")
    unlock_memory(arr)
    unlock_memory(arr_np)

Zeroing memory before starting child process

This mitigates the problems that appears on Copy-on-write fork. You need to zeroize the data before forking the child process.

import os
from zeroize import zeroize1, zeroize_np
import numpy as np
import ctypes


# Load the C standard library
LIBC = ctypes.CDLL("libc.so.6")
MLOCK = LIBC.mlock
MUNLOCK = LIBC.munlock

# Define mlock and munlock argument types
MLOCK.argtypes = [ctypes.c_void_p, ctypes.c_size_t]
MUNLOCK.argtypes = [ctypes.c_void_p, ctypes.c_size_t]


def lock_memory(buffer):
    """Locks the memory of the given buffer."""
    address = ctypes.addressof(ctypes.c_char.from_buffer(buffer))
    size = len(buffer)
    if MLOCK(address, size) != 0:
        raise RuntimeError("Failed to lock memory")


def unlock_memory(buffer):
    """Unlocks the memory of the given buffer."""
    address = ctypes.addressof(ctypes.c_char.from_buffer(buffer))
    size = len(buffer)
    if MUNLOCK(address, size) != 0:
        raise RuntimeError("Failed to unlock memory")


try:
    sensitive_data = bytearray(b"Sensitive Information")
    lock_memory(sensitive_data)

    print("Before zeroization:", sensitive_data)

    zeroize1(sensitive_data)
    print("After zeroization:", sensitive_data)

    # Forking after zeroization to ensure no sensitive data is copied
    pid = os.fork()
    if pid == 0:
        # This is the child process
        print("Child process memory after fork:", sensitive_data)
    else:
        # This is the parent process
        os.wait()  # Wait for the child process to exit
finally:
    # Unlock the memory
    print("unlocking memory")
    unlock_memory(sensitive_data)

Building from source

Browser

Open in Gitpod

Open in Codespaces

Geting sources from GitHub

Skip this if you're starting it in browser.

git clone https://github.com/radumarias/zeroize-python && cd zeroize-python

Compile and run

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

To configure your current shell, you need to source the corresponding env file under $HOME/.cargo. This is usually done by running one of the following (note the leading DOT):

. "$HOME/.cargo/env"
python -m venv .env
source .env/bin/activate
pip install -r requirements.txt
maturin develop
python examples/lock_and_zeroize.py
python examples/zeroize_before_fork.py

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zeroize-0.1.8.tar.gz (12.6 kB view hashes)

Uploaded Source

Built Distributions

zeroize-0.1.8-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (988.5 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

zeroize-0.1.8-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ s390x

zeroize-0.1.8-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.0 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ppc64le

zeroize-0.1.8-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (999.1 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARMv7l

zeroize-0.1.8-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (984.8 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARM64

zeroize-0.1.8-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl (1.0 MB view hashes)

Uploaded PyPy manylinux: glibc 2.5+ i686

zeroize-0.1.8-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (988.3 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

zeroize-0.1.8-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ s390x

zeroize-0.1.8-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.0 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ppc64le

zeroize-0.1.8-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (999.0 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARMv7l

zeroize-0.1.8-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (984.5 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARM64

zeroize-0.1.8-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl (1.0 MB view hashes)

Uploaded PyPy manylinux: glibc 2.5+ i686

zeroize-0.1.8-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (988.4 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

zeroize-0.1.8-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ s390x

zeroize-0.1.8-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.0 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ppc64le

zeroize-0.1.8-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (999.0 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARMv7l

zeroize-0.1.8-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (984.8 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARM64

zeroize-0.1.8-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl (1.0 MB view hashes)

Uploaded PyPy manylinux: glibc 2.5+ i686

zeroize-0.1.8-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (991.9 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

zeroize-0.1.8-pp37-pypy37_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ s390x

zeroize-0.1.8-pp37-pypy37_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.0 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ppc64le

zeroize-0.1.8-pp37-pypy37_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (1.0 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARMv7l

zeroize-0.1.8-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (987.2 kB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ ARM64

zeroize-0.1.8-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl (1.0 MB view hashes)

Uploaded PyPy manylinux: glibc 2.5+ i686

zeroize-0.1.8-cp312-none-win_amd64.whl (112.6 kB view hashes)

Uploaded CPython 3.12 Windows x86-64

zeroize-0.1.8-cp312-none-win32.whl (111.2 kB view hashes)

Uploaded CPython 3.12 Windows x86

zeroize-0.1.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (986.8 kB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

zeroize-0.1.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.1 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ s390x

zeroize-0.1.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.0 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ppc64le

zeroize-0.1.8-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (998.0 kB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ARMv7l

zeroize-0.1.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (983.6 kB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ARM64

zeroize-0.1.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl (1.0 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.5+ i686

zeroize-0.1.8-cp312-cp312-macosx_11_0_arm64.whl (214.0 kB view hashes)

Uploaded CPython 3.12 macOS 11.0+ ARM64

zeroize-0.1.8-cp312-cp312-macosx_10_12_x86_64.whl (216.8 kB view hashes)

Uploaded CPython 3.12 macOS 10.12+ x86-64

zeroize-0.1.8-cp311-none-win_amd64.whl (112.5 kB view hashes)

Uploaded CPython 3.11 Windows x86-64

zeroize-0.1.8-cp311-none-win32.whl (111.2 kB view hashes)

Uploaded CPython 3.11 Windows x86

zeroize-0.1.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (987.3 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

zeroize-0.1.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.1 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ s390x

zeroize-0.1.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.0 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ppc64le

zeroize-0.1.8-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (998.3 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARMv7l

zeroize-0.1.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (984.0 kB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARM64

zeroize-0.1.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl (1.0 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.5+ i686

zeroize-0.1.8-cp311-cp311-macosx_11_0_arm64.whl (214.5 kB view hashes)

Uploaded CPython 3.11 macOS 11.0+ ARM64

zeroize-0.1.8-cp311-cp311-macosx_10_12_x86_64.whl (217.5 kB view hashes)

Uploaded CPython 3.11 macOS 10.12+ x86-64

zeroize-0.1.8-cp310-none-win_amd64.whl (112.5 kB view hashes)

Uploaded CPython 3.10 Windows x86-64

zeroize-0.1.8-cp310-none-win32.whl (111.3 kB view hashes)

Uploaded CPython 3.10 Windows x86

zeroize-0.1.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (987.4 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

zeroize-0.1.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.1 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ s390x

zeroize-0.1.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.0 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ppc64le

zeroize-0.1.8-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (998.4 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARMv7l

zeroize-0.1.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (984.0 kB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARM64

zeroize-0.1.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl (1.0 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.5+ i686

zeroize-0.1.8-cp310-cp310-macosx_11_0_arm64.whl (214.6 kB view hashes)

Uploaded CPython 3.10 macOS 11.0+ ARM64

zeroize-0.1.8-cp310-cp310-macosx_10_12_x86_64.whl (217.6 kB view hashes)

Uploaded CPython 3.10 macOS 10.12+ x86-64

zeroize-0.1.8-cp39-none-win_amd64.whl (112.6 kB view hashes)

Uploaded CPython 3.9 Windows x86-64

zeroize-0.1.8-cp39-none-win32.whl (111.3 kB view hashes)

Uploaded CPython 3.9 Windows x86

zeroize-0.1.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (987.3 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

zeroize-0.1.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.1 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ s390x

zeroize-0.1.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.0 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ppc64le

zeroize-0.1.8-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (998.3 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARMv7l

zeroize-0.1.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (984.2 kB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARM64

zeroize-0.1.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl (1.0 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.5+ i686

zeroize-0.1.8-cp39-cp39-macosx_11_0_arm64.whl (214.5 kB view hashes)

Uploaded CPython 3.9 macOS 11.0+ ARM64

zeroize-0.1.8-cp39-cp39-macosx_10_12_x86_64.whl (217.6 kB view hashes)

Uploaded CPython 3.9 macOS 10.12+ x86-64

zeroize-0.1.8-cp38-none-win_amd64.whl (112.5 kB view hashes)

Uploaded CPython 3.8 Windows x86-64

zeroize-0.1.8-cp38-none-win32.whl (111.0 kB view hashes)

Uploaded CPython 3.8 Windows x86

zeroize-0.1.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (987.4 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

zeroize-0.1.8-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.1 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ s390x

zeroize-0.1.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.0 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ppc64le

zeroize-0.1.8-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (998.1 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARMv7l

zeroize-0.1.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (984.0 kB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARM64

zeroize-0.1.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl (1.0 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.5+ i686

zeroize-0.1.8-cp37-none-win_amd64.whl (112.5 kB view hashes)

Uploaded CPython 3.7 Windows x86-64

zeroize-0.1.8-cp37-none-win32.whl (111.0 kB view hashes)

Uploaded CPython 3.7 Windows x86

zeroize-0.1.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (987.5 kB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ x86-64

zeroize-0.1.8-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl (1.1 MB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ s390x

zeroize-0.1.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (1.0 MB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ ppc64le

zeroize-0.1.8-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (998.5 kB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ ARMv7l

zeroize-0.1.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (984.0 kB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ ARM64

zeroize-0.1.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl (1.0 MB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.5+ i686

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page