Metadata-Version: 2.4
Name: licensespring_hardware_id_generator
Version: 1.6.0
Summary: LicenseSpring hardware ID generator
License: LicenseSpring Hardware ID Generator License Agreement (LHIGLA)
Classifier: License :: Other/Proprietary License
Classifier: Programming Language :: Python :: 3
Classifier: Operating System :: OS Independent
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: license
Dynamic: license-file
Dynamic: summary

# LicenseSpring Hardware ID Generator

The LicenseSpring Hardware ID Generator offers stable cross-platform hardware ID generation.

This Python wrapper, and the library provided with it are licensed under the LicenseSpring Hardware ID Generator License Agreement (LHIGLA).

## Installation

Install the `licensespring_hardware_id_generator` library:

```
pip install licensespring_hardware_id_generator
```

## Requirements

`python>=3.8`

## Examples

The library exposes one Enum and six functions:

### Enum
- `HardwareIdAlgorithm`: Defines the available hardware ID generation algorithms.
### Functions
- `get_hardware_id`: Computes and returns the hardware identifier using the specified algorithm.
- `get_logs`: Returns a list of log strings and clears the log buffer.
- `get_version`: Retrieves the version of the hardware ID generator library.
- `is_key_store_available`: Reports whether the device's TPM / Secure Enclave can be used by this process.
- `create_key_pair`: Returns the public key of the device's P-256 signing key pair, creating it if needed.
- `sign`: Signs a message with the device's P-256 signing key.

```python
from licensespring_hardware_id_generator import HardwareIdAlgorithm, get_hardware_id, get_logs, get_version

version = get_version()
hardware_id = get_hardware_id(HardwareIdAlgorithm.Default)
logs = get_logs()

print("Version:", version)
print("Hardware ID:", hardware_id)
print("Logs:")
for log_line in logs:
    print(log_line)
```

### Device signing key

For binding a license to specific hardware more strongly than a hardware ID
alone, the library can create a P-256 key pair inside the device's TPM (Windows,
Linux) or Secure Enclave (macOS, iOS) and sign with it. The private key is
generated in, and never leaves, that hardware.

Always check `is_key_store_available()` first: it returns `False` when there is
no TPM or Secure Enclave, when the TPM is present but unusable, or when the host
process is not entitled to use the key store. On macOS it is expected to be
`False` for a plain Python interpreter, since persisting a Secure Enclave key
requires the *host process* to be code-signed with a `keychain-access-groups`
entitlement backed by an embedded provisioning profile.

```python
import base64

from licensespring_hardware_id_generator import (create_key_pair, get_logs,
                                                is_key_store_available, sign)

if not is_key_store_available():
    print("No device key store available:")
    for log_line in get_logs():
        print(" ", log_line)
else:
    # Base64 DER SubjectPublicKeyInfo. Register this with your backend once.
    public_key = create_key_pair()
    print("Public key:", public_key)

    # Accepts bytes, or a str which is encoded as UTF-8. The payload is
    # length-delimited, so it may contain NUL bytes anywhere.
    signature = sign(b"nonce-from-your-backend")
    print("Signature:", signature)
    assert len(base64.b64decode(signature)) == 64  # raw r || s, not DER
```

`create_key_pair()` returns the same public key on every call for as long as the
key material lives. It changes if the TPM is cleared, the keychain entry is
removed, or the disk is moved to different hardware. `sign()` returns the raw
`r || s` signature, base64-encoded, each half 32 bytes big-endian and
zero-padded, over `SHA-256(message)`.

Both raise `RuntimeError` on failure; call `get_logs()` for the reason. `sign()`
raises `ValueError` for an empty message rather than signing an empty payload.
