lorawan-tools 0.1.1
LoRaWAN crypto and frame tools
Requires Python: >=3.7

# LoRaWAN Python Implementation Documentation

## 1. File Structure and Overview

- `LoRaWanCrypto.py`: Implements core cryptographic algorithms for LoRaWAN, including key management, key derivation, and JoinAccept decryption.
- `LoRaWan.py`: Implements LoRaWAN device join procedure, downlink frame construction, data encryption, MIC calculation, and protocol flow, relying on the cryptographic capabilities provided by `LoRaWanCrypto.py`.

---

## 2. LoRaWanCrypto.py Description

### Main Classes and Methods

#### `KeyIdentifier(Enum)`
Enumeration of key types, including:
- `NWK_KEY`: Network root key
- `APP_KEY`: Application root key
- `NWK_S_ENC_KEY`: Network session encryption key
- `APP_S_KEY`: Application session key
- `F_NWK_S_INT_KEY`/`S_NWK_S_INT_KEY`: Network integrity keys

#### `LoRaWANCrypto`
Core class for LoRaWAN cryptography and key management.

- `set_key(key_id, key)`: Set the specified type of key, which must be 16 bytes.
- `aes_encrypt(data, key_id)`: AES-128-ECB encrypt 16 bytes of data with the specified key.
- `derive_and_store_key(input_data, root_key_id, target_key_id)`: Derive and store a target key by encrypting input_data with the root key.
- `derive_session_key_10x(key_id, join_nonce, net_id, dev_nonce)`: Session key derivation for LoRaWAN 1.0.x.
- `process_join_accept(enc_join_accept, join_req_type=True)`: Decrypt JoinAccept message, return decrypted data and protocol version.
- `verify_join_accept_mic(...)`: Verify JoinAccept MIC (currently a placeholder implementation).

### Usage Example
```python
from LoRaWanCrypto import LoRaWANCrypto, KeyIdentifier
crypto = LoRaWANCrypto()
root_key = bytes.fromhex('4079bf1f6c35cb3b59b2961805ed23b3')
crypto.set_key(KeyIdentifier.NWK_KEY, root_key)
# Derive AppSKey
crypto.derive_session_key_10x(KeyIdentifier.APP_S_KEY, join_nonce, net_id, dev_nonce)
app_skey = crypto.key_store[KeyIdentifier.APP_S_KEY]
```

---

## 3. LoRaWan.py Description

### Main Classes and Methods

#### `LoRaWAN`
Main class for LoRaWAN protocol flow and frame construction.

- `set_join_request_callback(callback)`: Set callback for join request processing.
- `set_join_accept_callback(callback)`: Set callback for join accept processing.
- `set_crypto(crypto)`: Inject a LoRaWANCrypto instance.
- `process_join_request(join_request)`: Parse and process join request.
- `process_join_accept(join_accept, app_key)`: Decrypt and process JoinAccept message.
- `get_app_skey(...)`/`get_nwk_skey(...)`: Get derived session keys.
- `encrypt_payload(payload, app_skey, dev_addr, fcnt, direction)`: Encrypt FRMPayload.
- `calculate_mic(msg, nwk_skey, dev_addr, fcnt)`: Calculate frame MIC.
- `build_downlink_frame(app_skey, nwk_skey, app_data, dev_addr, ...)`: Assemble downlink PHY frame and return base64 encoded string.
- `build_gateway_payload(lorawan_frame, gateway_id, context, ...)`: Generate JSON downlink packet for gateway.

### Usage Example
```python
from LoRaWan import LoRaWAN
from LoRaWanCrypto import LoRaWANCrypto
lorawan = LoRaWAN()
crypto = LoRaWANCrypto()
lorawan.set_crypto(crypto)
# Process JoinAccept
join_accept = bytes.fromhex('20d0bf79b262973f4068d1a0e8f9f7bb8c2b4457fe2635165d3c82ef85b7dc9c3d')
app_key = bytes.fromhex('4079bf1f6c35cb3b59b2961805ed23b3')
lorawan.process_join_accept(join_accept, app_key)
```

---

## 4. Notes
- Key length must be 16 bytes (AES-128).
- MIC verification and JoinAccept decryption must strictly follow the LoRaWAN protocol specification.
- Code examples are for development and debugging purposes only. Please enhance security checks in production environments.