Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3234,6 +3234,109 @@ def infer_tls_terminator(process_name, local_port, protocol, tls_listener_names)
return "unknown"
return "upstream-or-external-lb"

def parse_proc_crypto_entries():
"""Parse /proc/crypto into a list of dict entries."""
entries = []
try:
with open("/proc/crypto", "r", encoding="utf-8", errors="ignore") as f:
raw = f.read()
except Exception:
return entries

blocks = [block.strip() for block in raw.split("\n\n") if block.strip()]
for block in blocks:
item = {}
for line in block.splitlines():
if ":" not in line:
continue
key, value = line.split(":", 1)
item[key.strip().lower()] = value.strip()
if item:
entries.append(item)
return entries

def collect_algorithm_competition(requested_algorithm="aes"):
"""
Build algorithm implementation competition using kernel crypto registry.
The winner is the implementation with highest priority.
"""
entries = parse_proc_crypto_entries()
requested = (requested_algorithm or "aes").lower()
req_type_allow = {
"aes": {"skcipher", "aead", "cipher"},
"sha": {"shash", "ahash", "hash"},
"chacha20": {"skcipher", "aead", "cipher"}
}
req_tokens = {
"aes": ["aes"],
"sha": ["sha"],
"chacha20": ["chacha20", "xchacha20", "chacha"]
}
allowed_types = req_type_allow.get(requested, {"skcipher", "aead", "cipher", "shash", "ahash", "hash"})
tokens = req_tokens.get(requested, [requested])
candidates = []

for entry in entries:
name = str(entry.get("name", "")).lower()
driver = str(entry.get("driver", "")).lower()
alg_type = str(entry.get("type", "")).lower()

if not any(token in name or token in driver for token in tokens):
continue
if alg_type and alg_type not in allowed_types:
continue

try:
priority = int(entry.get("priority", "0") or 0)
except ValueError:
priority = 0

impl_name = driver or name or "unknown-impl"
candidates.append({
"name": impl_name,
"priority": priority,
"type": alg_type or "unknown",
"source": "kernel"
})

# Deduplicate by implementation name, keep the highest priority variant.
dedup = {}
for item in candidates:
existing = dedup.get(item["name"])
if existing is None or item["priority"] > existing["priority"]:
dedup[item["name"]] = item
candidates = list(dedup.values())
candidates.sort(key=lambda x: x["priority"], reverse=True)

if not candidates:
# Fallback keeps the UX informative on hosts without readable /proc/crypto.
fallback_map = {
"aes": [
{"name": "aesni-intel", "priority": 300, "type": "skcipher", "source": "mock"},
{"name": "aes-avx", "priority": 200, "type": "skcipher", "source": "mock"},
{"name": "aes-generic", "priority": 100, "type": "skcipher", "source": "mock"}
],
"sha": [
{"name": "sha256-avx2", "priority": 240, "type": "shash", "source": "mock"},
{"name": "sha256-ssse3", "priority": 180, "type": "shash", "source": "mock"},
{"name": "sha256-generic", "priority": 100, "type": "shash", "source": "mock"}
],
"chacha20": [
{"name": "chacha20-neon", "priority": 260, "type": "skcipher", "source": "mock"},
{"name": "chacha20-simd", "priority": 220, "type": "skcipher", "source": "mock"},
{"name": "chacha20-generic", "priority": 100, "type": "skcipher", "source": "mock"}
]
}
candidates = fallback_map.get(requested, fallback_map["aes"])

selected = candidates[0] if candidates else None
return {
"request": requested.upper(),
"implementations": candidates[:8],
"selected": selected,
"selection_policy": "max-priority"
}

def collect_crypto_realtime():
"""
Build a near-realtime list of processes likely interacting with kernel crypto.
Expand Down Expand Up @@ -3390,6 +3493,12 @@ def collect_crypto_realtime():
if p not in unique_processes:
unique_processes.append(p)

algorithm_competitions = {
"aes": collect_algorithm_competition("aes"),
"sha": collect_algorithm_competition("sha"),
"chacha20": collect_algorithm_competition("chacha20")
}

return {
"items": items[:24],
"processes": unique_processes[:16],
Expand All @@ -3399,6 +3508,8 @@ def collect_crypto_realtime():
"active_flows": active_flows,
"unknown_pid_flows": int(unknown_pid_flows),
"tls_terminators": sorted(list(tls_listener_names))[:8],
"algorithm_competition": algorithm_competitions["aes"],
"algorithm_competitions": algorithm_competitions,
"source": "live-heuristic-v2",
"timestamp": datetime.utcnow().isoformat() + "Z"
}
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ <h2>Linux Kernel Ring 0 Visualization</h2>
<script src="/static/js/kernel-dna.js?v=23"></script>
<script src="/static/js/network-stack.js?v=6"></script>
<script src="/static/js/devices-belt.js?v=14"></script>
<script src="/static/js/crypto-belt.js?v=7"></script>
<script src="/static/js/crypto-belt.js?v=9"></script>
<script src="/static/js/filesystem-map.js?v=3"></script>
<script src="/static/js/kernel-context-menu.js?v=25"></script>
<!-- 3D visualization script - DISABLED -->
Expand Down
208 changes: 206 additions & 2 deletions static/js/crypto-belt.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
this.prevLaneKeys = new Set();
this.laneHistory = new Map();
this.recentlyGone = [];
this.selectedCompetitionAlgorithm = 'AES';
this.algorithmModes = ['AES', 'SHA', 'CHACHA20'];
}

init(containerId = 'crypto-belt-container') {
Expand Down Expand Up @@ -535,6 +537,162 @@
});
}

getCompetitionPayload(meta) {
const selected = String(this.selectedCompetitionAlgorithm || 'AES').toLowerCase();
const groups = meta?.algorithm_competitions || null;
if (groups && groups[selected]) return groups[selected];

Check warning on line 543 in static/js/crypto-belt.js

View workflow job for this annotation

GitHub Actions / security

Generic Object Injection Sink

Check warning on line 543 in static/js/crypto-belt.js

View workflow job for this annotation

GitHub Actions / security

Generic Object Injection Sink
return meta?.algorithm_competition || {
request: this.selectedCompetitionAlgorithm,
implementations: [],
selected: null,
selection_policy: 'max-priority'
};
}

drawAlgorithmCompetition(layer, meta, width) {
const comp = this.getCompetitionPayload(meta);
const request = String(comp.request || this.selectedCompetitionAlgorithm || 'AES').toUpperCase();
const impls = Array.isArray(comp.implementations) ? comp.implementations.slice(0, 5) : [];
const selectedName = String(comp?.selected?.name || '').toLowerCase();

const panelX = Math.floor(width * 0.73);
const panelY = 130;
const panelW = Math.max(260, Math.floor(width * 0.24));
const panelH = Math.max(220, 170 + impls.length * 30);

const panel = layer.append('g').attr('class', 'crypto-algo-competition');
panel.append('rect')
.attr('x', panelX)
.attr('y', panelY)
.attr('width', panelW)
.attr('height', panelH)
.attr('rx', 8)
.style('fill', 'rgba(8, 11, 16, 0.88)')
.style('stroke', 'rgba(165, 178, 200, 0.35)')
.style('stroke-width', 1);

panel.append('text')
.attr('x', panelX + 14)
.attr('y', panelY + 22)
.style('font-family', 'Share Tech Mono, monospace')
.style('font-size', '11px')
.style('fill', '#d7ddea')
.text('ALGORITHM COMPETITION');

const toggleY = panelY + 38;
this.algorithmModes.forEach((mode, idx) => {
const isActive = mode === request;
const btnX = panelX + 14 + idx * 86;
const btn = panel.append('g')
.attr('class', 'algo-toggle-btn')
.style('cursor', 'pointer')
.on('click', () => {
this.selectedCompetitionAlgorithm = mode;
this.renderFlowMap(this.lastPayload || this.normalizeTelemetry(this.getFallbackTelemetry()));
});

btn.append('rect')
.attr('x', btnX)
.attr('y', toggleY)
.attr('width', 78)
.attr('height', 18)
.attr('rx', 4)
.style('fill', isActive ? 'rgba(32, 52, 81, 0.92)' : 'rgba(12, 16, 22, 0.85)')
.style('stroke', isActive ? 'rgba(124, 178, 255, 0.9)' : 'rgba(150, 162, 182, 0.35)')
.style('stroke-width', isActive ? 1.1 : 0.8);

btn.append('text')
.attr('x', btnX + 39)
.attr('y', toggleY + 12)
.attr('text-anchor', 'middle')
.style('font-family', 'Share Tech Mono, monospace')
.style('font-size', '9px')
.style('letter-spacing', '0.3px')
.style('fill', isActive ? '#cfe2ff' : '#a7b3c5')
.text(mode);
});

panel.append('text')
.attr('x', panelX + 14)
.attr('y', panelY + 67)
.style('font-family', 'Share Tech Mono, monospace')
.style('font-size', '10px')
.style('fill', '#99a8bd')
.text(`request ${request} -> lookup -> pick max priority`);

const stepsY = panelY + 92;
panel.append('text')
.attr('x', panelX + 14)
.attr('y', stepsY)
.style('font-family', 'Share Tech Mono, monospace')
.style('font-size', '10px')
.style('fill', '#b3bece')
.text(`${request} REQUEST`);

panel.append('line')
.attr('x1', panelX + 20)
.attr('y1', stepsY + 8)
.attr('x2', panelX + 20)
.attr('y2', stepsY + 28)
.style('stroke', '#7c8ca2')
.style('stroke-width', 1);

panel.append('text')
.attr('x', panelX + 14)
.attr('y', stepsY + 42)
.style('font-family', 'Share Tech Mono, monospace')
.style('font-size', '10px')
.style('fill', '#b3bece')
.text('CRYPTO LOOKUP');

const baseY = stepsY + 64;
if (!impls.length) {
panel.append('text')
.attr('x', panelX + 14)
.attr('y', baseY)
.style('font-family', 'Share Tech Mono, monospace')
.style('font-size', '10px')
.style('fill', '#97a5ba')
.text('No implementations detected');
return;
}

impls.forEach((impl, idx) => {
const y = baseY + idx * 30;
const name = String(impl.name || 'unknown');
const prio = Number(impl.priority || 0);
const isSelected = name.toLowerCase() === selectedName;

panel.append('rect')
.attr('x', panelX + 12)
.attr('y', y - 12)
.attr('width', panelW - 24)
.attr('height', 22)
.attr('rx', 5)
.style('fill', isSelected ? 'rgba(20, 39, 29, 0.9)' : 'rgba(14, 18, 24, 0.85)')
.style('stroke', isSelected ? 'rgba(114, 242, 173, 0.8)' : 'rgba(150, 162, 182, 0.28)')
.style('stroke-width', isSelected ? 1.2 : 0.8);

panel.append('text')
.attr('x', panelX + 20)
.attr('y', y + 2)
.style('font-family', 'Share Tech Mono, monospace')
.style('font-size', '10px')
.style('fill', isSelected ? '#9effca' : '#c5cedb')
.text(`${name} priority ${prio}`);

if (isSelected) {
panel.append('text')
.attr('x', panelX + panelW - 70)
.attr('y', y + 2)
.style('font-family', 'Share Tech Mono, monospace')
.style('font-size', '9px')
.style('fill', '#9effca')
.text('SELECTED');
}
});
}

drawNode(group, x, y, label, level, intensity, palette, emphasis) {
const width = Math.min(Math.max(150, String(label).length * 8 + 28), 250);
const height = 34;
Expand Down Expand Up @@ -575,7 +733,7 @@
const path = d3.path();
path.moveTo(points[0].x, points[0].y);
for (let i = 1; i < points.length; i += 1) {
path.lineTo(points[i].x, points[i].y);

Check warning on line 736 in static/js/crypto-belt.js

View workflow job for this annotation

GitHub Actions / security

Generic Object Injection Sink

Check warning on line 736 in static/js/crypto-belt.js

View workflow job for this annotation

GitHub Actions / security

Generic Object Injection Sink
}

group.append('path')
Expand Down Expand Up @@ -608,8 +766,8 @@
let chain = dot.transition().duration(0);
for (let i = 1; i < points.length; i += 1) {
chain = chain.duration(segmentDuration)
.attr('cx', points[i].x)

Check warning on line 769 in static/js/crypto-belt.js

View workflow job for this annotation

GitHub Actions / security

Generic Object Injection Sink
.attr('cy', points[i].y);

Check warning on line 770 in static/js/crypto-belt.js

View workflow job for this annotation

GitHub Actions / security

Generic Object Injection Sink
}

chain.on('end', () => {
Expand All @@ -635,6 +793,7 @@
const layer = this.svg.append('g').attr('class', 'crypto-flow-layer');
this.drawGrid(layer, width, height);
this.drawProtocolLegend(layer);
this.drawAlgorithmCompetition(layer, payload?.meta || {}, width);

const lanes = Array.isArray(payload.items) ? payload.items : [];
const topY = 150;
Expand All @@ -644,7 +803,7 @@
const endpointY = 520;

const startX = width * 0.16;
const usableWidth = width * 0.70;
const usableWidth = width * 0.52;
const laneCount = Math.max(lanes.length, 1);
const laneStep = laneCount > 1 ? usableWidth / (laneCount - 1) : 0;

Expand Down Expand Up @@ -758,6 +917,48 @@
ops_per_sec: 960,
tls_sessions: 2,
active_flows: 3,
algorithm_competition: {
request: 'AES',
implementations: [
{ name: 'aesni-intel', priority: 300, type: 'skcipher' },
{ name: 'aes-avx', priority: 200, type: 'skcipher' },
{ name: 'aes-generic', priority: 100, type: 'skcipher' }
],
selected: { name: 'aesni-intel', priority: 300, type: 'skcipher' },
selection_policy: 'max-priority'
},
algorithm_competitions: {
aes: {
request: 'AES',
implementations: [
{ name: 'aesni-intel', priority: 300, type: 'skcipher' },
{ name: 'aes-avx', priority: 200, type: 'skcipher' },
{ name: 'aes-generic', priority: 100, type: 'skcipher' }
],
selected: { name: 'aesni-intel', priority: 300, type: 'skcipher' },
selection_policy: 'max-priority'
},
sha: {
request: 'SHA',
implementations: [
{ name: 'sha256-avx2', priority: 240, type: 'shash' },
{ name: 'sha256-ssse3', priority: 180, type: 'shash' },
{ name: 'sha256-generic', priority: 100, type: 'shash' }
],
selected: { name: 'sha256-avx2', priority: 240, type: 'shash' },
selection_policy: 'max-priority'
},
chacha20: {
request: 'CHACHA20',
implementations: [
{ name: 'chacha20-neon', priority: 260, type: 'skcipher' },
{ name: 'chacha20-simd', priority: 220, type: 'skcipher' },
{ name: 'chacha20-generic', priority: 100, type: 'skcipher' }
],
selected: { name: 'chacha20-neon', priority: 260, type: 'skcipher' },
selection_policy: 'max-priority'
}
},
source: 'mock'
}
};
Expand Down Expand Up @@ -786,7 +987,10 @@
const source = String(data?.meta?.source || 'api');
const unknownPid = Number(data?.meta?.unknown_pid_flows || 0);
const terms = Array.isArray(data?.meta?.tls_terminators) ? data.meta.tls_terminators.join(',') : '-';
this.telemetryNode.textContent = `ops/s: ${ops} | tls: ${tls} | active: ${flows} | unknown-pid: ${unknownPid} | terminator: ${terms || '-'} | source: ${source}`;
const selectedComp = this.getCompetitionPayload(data?.meta || {});
const selectedImpl = String(selectedComp?.selected?.name || '-');
const reqLabel = String(selectedComp?.request || this.selectedCompetitionAlgorithm || 'AES').toUpperCase();
this.telemetryNode.textContent = `ops/s: ${ops} | tls: ${tls} | active: ${flows} | unknown-pid: ${unknownPid} | terminator: ${terms || '-'} | ${reqLabel}: ${selectedImpl} | source: ${source}`;
}
})
.catch(() => {
Expand Down
Loading