Encode, decode, and check network device secrets: Juniper $9$, Juniper $8$, and Nokia SR OS custom-hash
Project description
network-secret
Encode, decode, and check network device secrets for Juniper JunOS and Nokia SR OS, from the command line or Python. network-secret is a unified successor to juniper8-crypt and juniper9-crypt: it covers all three formats in a single package with a single CLI.
Prefer a browser? Encode and decode all three formats at network-secret.pages.dev. It runs the same algorithms fully client-side - nothing you type is ever sent to a server.
Repository layout
This repo holds both the Python package and the website that share these algorithms.
| Path | What |
|---|---|
network_secret/ |
The Python package published to PyPI as network-secret |
tests/ |
Python test suite |
web/ |
The Svelte site deployed to Cloudflare Pages, with its own README and tests |
The two implementations share known-answer vectors, so keeping them in one repo means a cipher fix and its test data land in a single commit.
Supported formats
| Format | CLI subcommand | Python module | Description |
|---|---|---|---|
$9$ |
juniper9 |
network_secret.juniper9 |
Juniper reversible obfuscation - keyless |
$8$ |
juniper8 |
network_secret.juniper8 |
Juniper AES-256-GCM - keyed by master password |
| Nokia custom-hash | nokia-sros-custom-hash |
network_secret.nokia_sros_custom_hash |
Nokia SR OS AES-ECB shared-key cipher |
Install
pip install network-secret
Or with uv:
uv add network-secret
Python API
from network_secret import juniper8, juniper9, nokia_sros_custom_hash
# Juniper $9$ (keyless)
cipher9 = juniper9.encrypt("BGPsecret1")
plain9 = juniper9.decrypt(cipher9)
# 'BGPsecret1'
# Juniper $8$ (master-password keyed)
master = "MyMasterPassword"
cipher8 = juniper8.encrypt("BGPsecret1", master)
plain8 = juniper8.decrypt(cipher8, master)
# 'BGPsecret1'
plain_a, plain_b, match = juniper8.check(cipher8, "BGPsecret1", master)
# match is True
# Nokia SR OS custom-hash (16/24/32-character shared key)
key = "a3f8d9e112c04b7af1c3e8b92d057a4e"
cipher_nokia = nokia_sros_custom_hash.encrypt("BGPsecret1", key)
plain_nokia = nokia_sros_custom_hash.decrypt(cipher_nokia, key)
# 'BGPsecret1'
plain_a, plain_b, match = nokia_sros_custom_hash.check(cipher_nokia, "BGPsecret1", key)
# match is True
All three check() functions return a tuple[str, str, bool]: the two decrypted plaintexts and whether they match.
Command-line usage
# List all supported ciphers
network-secret --list
# Show the version
network-secret --version
Juniper $9$ (keyless)
network-secret juniper9 --encrypt 'BGPsecret1'
network-secret juniper9 --decrypt '$9$abc...'
network-secret juniper9 --check '$9$abc...' 'BGPsecret1'
Juniper $8$ (master-password keyed)
The master password is resolved in this order: -m/--master flag, then the JUNOS_MASTER_PASSWORD environment variable, then an interactive no-echo prompt.
# Master on the command line
network-secret juniper8 -m 'MyMaster' --encrypt 'BGPsecret1'
network-secret juniper8 -m 'MyMaster' --decrypt '$8$aes256-gcm$...'
network-secret juniper8 -m 'MyMaster' --check '$8$aes256-gcm$...' 'BGPsecret1'
# Master from the environment (keeps it out of shell history and the process list)
export JUNOS_MASTER_PASSWORD='MyMaster'
network-secret juniper8 --decrypt '$8$aes256-gcm$...'
# Master from an interactive prompt
network-secret juniper8 --decrypt '$8$aes256-gcm$...'
# Master password: <typed without echo>
Always quote
$8$and$9$strings with single quotes - the shell expands$8and$9as positional parameters otherwise.
Nokia SR OS custom-hash (shared-key)
The shared key is resolved in this order: -k/--key flag, then the SROS_CUSTOM_HASH_KEY environment variable, then an interactive no-echo prompt. Keys must be exactly 16, 24, or 32 characters.
# Key on the command line
network-secret nokia-sros-custom-hash -k 'a3f8d9e112c04b7af1c3e8b92d057a4e' --encrypt 'BGPsecret1'
network-secret nokia-sros-custom-hash -k 'a3f8d9e112c04b7af1c3e8b92d057a4e' --decrypt 'ABC123...'
network-secret nokia-sros-custom-hash -k 'a3f8d9e112c04b7af1c3e8b92d057a4e' --check 'ABC123...' 'BGPsecret1'
# Key from the environment
export SROS_CUSTOM_HASH_KEY='a3f8d9e112c04b7af1c3e8b92d057a4e'
network-secret nokia-sros-custom-hash --decrypt 'ABC123...'
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success (or --check matched) |
| 1 | --check mismatched |
| 2 | Invalid input (malformed value, wrong key, etc.) |
Supersedes
network-secret supersedes the older single-format packages juniper8-crypt and juniper9-crypt. It exposes the same algorithms under the same function signatures (encrypt, decrypt, check); migrating is a matter of updating the import path.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file network_secret-0.1.1.tar.gz.
File metadata
- Download URL: network_secret-0.1.1.tar.gz
- Upload date:
- Size: 13.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3fe2c5e5e2e50c4435b34908037ba55778b84d6949456842e465aba2c1c67787
|
|
| MD5 |
6b1e6ea835c4046d10b2bcf2bc0616a9
|
|
| BLAKE2b-256 |
ce2bf7623e0056af8cd7c7b645f6ff1a3f6693573438a43da404c1fd073c17a8
|
Provenance
The following attestation bundles were made for network_secret-0.1.1.tar.gz:
Publisher:
publish.yml on antoinekh/network-secret
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
network_secret-0.1.1.tar.gz -
Subject digest:
3fe2c5e5e2e50c4435b34908037ba55778b84d6949456842e465aba2c1c67787 - Sigstore transparency entry: 2225306341
- Sigstore integration time:
-
Permalink:
antoinekh/network-secret@7f5308b94cfb8f3d625cffbf9e0985d59f4b32a1 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/antoinekh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7f5308b94cfb8f3d625cffbf9e0985d59f4b32a1 -
Trigger Event:
release
-
Statement type:
File details
Details for the file network_secret-0.1.1-py3-none-any.whl.
File metadata
- Download URL: network_secret-0.1.1-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86453a6433510e2675351a5081e2204177429a3b01a99ace1081ced101e33bdc
|
|
| MD5 |
1b806c91c941a976221c5a0c9f282a68
|
|
| BLAKE2b-256 |
4bbbf12b551ce9756b87575818f20ef7c7ac16c6eb364bd018b38ad5d6511684
|
Provenance
The following attestation bundles were made for network_secret-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on antoinekh/network-secret
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
network_secret-0.1.1-py3-none-any.whl -
Subject digest:
86453a6433510e2675351a5081e2204177429a3b01a99ace1081ced101e33bdc - Sigstore transparency entry: 2225306749
- Sigstore integration time:
-
Permalink:
antoinekh/network-secret@7f5308b94cfb8f3d625cffbf9e0985d59f4b32a1 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/antoinekh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7f5308b94cfb8f3d625cffbf9e0985d59f4b32a1 -
Trigger Event:
release
-
Statement type: