oscura 0.5.1__py3-none-any.whl → 0.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (497) hide show
  1. oscura/__init__.py +169 -167
  2. oscura/analyzers/__init__.py +3 -0
  3. oscura/analyzers/classification.py +659 -0
  4. oscura/analyzers/digital/edges.py +325 -65
  5. oscura/analyzers/digital/quality.py +293 -166
  6. oscura/analyzers/digital/timing.py +260 -115
  7. oscura/analyzers/digital/timing_numba.py +334 -0
  8. oscura/analyzers/entropy.py +605 -0
  9. oscura/analyzers/eye/diagram.py +176 -109
  10. oscura/analyzers/eye/metrics.py +5 -5
  11. oscura/analyzers/jitter/__init__.py +6 -4
  12. oscura/analyzers/jitter/ber.py +52 -52
  13. oscura/analyzers/jitter/classification.py +156 -0
  14. oscura/analyzers/jitter/decomposition.py +163 -113
  15. oscura/analyzers/jitter/spectrum.py +80 -64
  16. oscura/analyzers/ml/__init__.py +39 -0
  17. oscura/analyzers/ml/features.py +600 -0
  18. oscura/analyzers/ml/signal_classifier.py +604 -0
  19. oscura/analyzers/packet/daq.py +246 -158
  20. oscura/analyzers/packet/parser.py +12 -1
  21. oscura/analyzers/packet/payload.py +50 -2110
  22. oscura/analyzers/packet/payload_analysis.py +361 -181
  23. oscura/analyzers/packet/payload_patterns.py +133 -70
  24. oscura/analyzers/packet/stream.py +84 -23
  25. oscura/analyzers/patterns/__init__.py +26 -5
  26. oscura/analyzers/patterns/anomaly_detection.py +908 -0
  27. oscura/analyzers/patterns/clustering.py +169 -108
  28. oscura/analyzers/patterns/clustering_optimized.py +227 -0
  29. oscura/analyzers/patterns/discovery.py +1 -1
  30. oscura/analyzers/patterns/matching.py +581 -197
  31. oscura/analyzers/patterns/pattern_mining.py +778 -0
  32. oscura/analyzers/patterns/periodic.py +121 -38
  33. oscura/analyzers/patterns/sequences.py +175 -78
  34. oscura/analyzers/power/conduction.py +1 -1
  35. oscura/analyzers/power/soa.py +6 -6
  36. oscura/analyzers/power/switching.py +250 -110
  37. oscura/analyzers/protocol/__init__.py +17 -1
  38. oscura/analyzers/protocols/base.py +6 -6
  39. oscura/analyzers/protocols/ble/__init__.py +38 -0
  40. oscura/analyzers/protocols/ble/analyzer.py +809 -0
  41. oscura/analyzers/protocols/ble/uuids.py +288 -0
  42. oscura/analyzers/protocols/can.py +257 -127
  43. oscura/analyzers/protocols/can_fd.py +107 -80
  44. oscura/analyzers/protocols/flexray.py +139 -80
  45. oscura/analyzers/protocols/hdlc.py +93 -58
  46. oscura/analyzers/protocols/i2c.py +247 -106
  47. oscura/analyzers/protocols/i2s.py +138 -86
  48. oscura/analyzers/protocols/industrial/__init__.py +40 -0
  49. oscura/analyzers/protocols/industrial/bacnet/__init__.py +33 -0
  50. oscura/analyzers/protocols/industrial/bacnet/analyzer.py +708 -0
  51. oscura/analyzers/protocols/industrial/bacnet/encoding.py +412 -0
  52. oscura/analyzers/protocols/industrial/bacnet/services.py +622 -0
  53. oscura/analyzers/protocols/industrial/ethercat/__init__.py +30 -0
  54. oscura/analyzers/protocols/industrial/ethercat/analyzer.py +474 -0
  55. oscura/analyzers/protocols/industrial/ethercat/mailbox.py +339 -0
  56. oscura/analyzers/protocols/industrial/ethercat/topology.py +166 -0
  57. oscura/analyzers/protocols/industrial/modbus/__init__.py +31 -0
  58. oscura/analyzers/protocols/industrial/modbus/analyzer.py +525 -0
  59. oscura/analyzers/protocols/industrial/modbus/crc.py +79 -0
  60. oscura/analyzers/protocols/industrial/modbus/functions.py +436 -0
  61. oscura/analyzers/protocols/industrial/opcua/__init__.py +21 -0
  62. oscura/analyzers/protocols/industrial/opcua/analyzer.py +552 -0
  63. oscura/analyzers/protocols/industrial/opcua/datatypes.py +446 -0
  64. oscura/analyzers/protocols/industrial/opcua/services.py +264 -0
  65. oscura/analyzers/protocols/industrial/profinet/__init__.py +23 -0
  66. oscura/analyzers/protocols/industrial/profinet/analyzer.py +441 -0
  67. oscura/analyzers/protocols/industrial/profinet/dcp.py +263 -0
  68. oscura/analyzers/protocols/industrial/profinet/ptcp.py +200 -0
  69. oscura/analyzers/protocols/jtag.py +180 -98
  70. oscura/analyzers/protocols/lin.py +219 -114
  71. oscura/analyzers/protocols/manchester.py +4 -4
  72. oscura/analyzers/protocols/onewire.py +253 -149
  73. oscura/analyzers/protocols/parallel_bus/__init__.py +20 -0
  74. oscura/analyzers/protocols/parallel_bus/centronics.py +92 -0
  75. oscura/analyzers/protocols/parallel_bus/gpib.py +137 -0
  76. oscura/analyzers/protocols/spi.py +192 -95
  77. oscura/analyzers/protocols/swd.py +321 -167
  78. oscura/analyzers/protocols/uart.py +267 -125
  79. oscura/analyzers/protocols/usb.py +235 -131
  80. oscura/analyzers/side_channel/power.py +17 -12
  81. oscura/analyzers/signal/__init__.py +15 -0
  82. oscura/analyzers/signal/timing_analysis.py +1086 -0
  83. oscura/analyzers/signal_integrity/__init__.py +4 -1
  84. oscura/analyzers/signal_integrity/sparams.py +2 -19
  85. oscura/analyzers/spectral/chunked.py +129 -60
  86. oscura/analyzers/spectral/chunked_fft.py +300 -94
  87. oscura/analyzers/spectral/chunked_wavelet.py +100 -80
  88. oscura/analyzers/statistical/checksum.py +376 -217
  89. oscura/analyzers/statistical/classification.py +229 -107
  90. oscura/analyzers/statistical/entropy.py +78 -53
  91. oscura/analyzers/statistics/correlation.py +407 -211
  92. oscura/analyzers/statistics/outliers.py +2 -2
  93. oscura/analyzers/statistics/streaming.py +30 -5
  94. oscura/analyzers/validation.py +216 -101
  95. oscura/analyzers/waveform/measurements.py +9 -0
  96. oscura/analyzers/waveform/measurements_with_uncertainty.py +31 -15
  97. oscura/analyzers/waveform/spectral.py +500 -228
  98. oscura/api/__init__.py +31 -5
  99. oscura/api/dsl/__init__.py +582 -0
  100. oscura/{dsl → api/dsl}/commands.py +43 -76
  101. oscura/{dsl → api/dsl}/interpreter.py +26 -51
  102. oscura/{dsl → api/dsl}/parser.py +107 -77
  103. oscura/{dsl → api/dsl}/repl.py +2 -2
  104. oscura/api/dsl.py +1 -1
  105. oscura/{integrations → api/integrations}/__init__.py +1 -1
  106. oscura/{integrations → api/integrations}/llm.py +201 -102
  107. oscura/api/operators.py +3 -3
  108. oscura/api/optimization.py +144 -30
  109. oscura/api/rest_server.py +921 -0
  110. oscura/api/server/__init__.py +17 -0
  111. oscura/api/server/dashboard.py +850 -0
  112. oscura/api/server/static/README.md +34 -0
  113. oscura/api/server/templates/base.html +181 -0
  114. oscura/api/server/templates/export.html +120 -0
  115. oscura/api/server/templates/home.html +284 -0
  116. oscura/api/server/templates/protocols.html +58 -0
  117. oscura/api/server/templates/reports.html +43 -0
  118. oscura/api/server/templates/session_detail.html +89 -0
  119. oscura/api/server/templates/sessions.html +83 -0
  120. oscura/api/server/templates/waveforms.html +73 -0
  121. oscura/automotive/__init__.py +8 -1
  122. oscura/automotive/can/__init__.py +10 -0
  123. oscura/automotive/can/checksum.py +3 -1
  124. oscura/automotive/can/dbc_generator.py +590 -0
  125. oscura/automotive/can/message_wrapper.py +121 -74
  126. oscura/automotive/can/patterns.py +98 -21
  127. oscura/automotive/can/session.py +292 -56
  128. oscura/automotive/can/state_machine.py +6 -3
  129. oscura/automotive/can/stimulus_response.py +97 -75
  130. oscura/automotive/dbc/__init__.py +10 -2
  131. oscura/automotive/dbc/generator.py +84 -56
  132. oscura/automotive/dbc/parser.py +6 -6
  133. oscura/automotive/dtc/data.json +17 -102
  134. oscura/automotive/dtc/database.py +2 -2
  135. oscura/automotive/flexray/__init__.py +31 -0
  136. oscura/automotive/flexray/analyzer.py +504 -0
  137. oscura/automotive/flexray/crc.py +185 -0
  138. oscura/automotive/flexray/fibex.py +449 -0
  139. oscura/automotive/j1939/__init__.py +45 -8
  140. oscura/automotive/j1939/analyzer.py +605 -0
  141. oscura/automotive/j1939/spns.py +326 -0
  142. oscura/automotive/j1939/transport.py +306 -0
  143. oscura/automotive/lin/__init__.py +47 -0
  144. oscura/automotive/lin/analyzer.py +612 -0
  145. oscura/automotive/loaders/blf.py +13 -2
  146. oscura/automotive/loaders/csv_can.py +143 -72
  147. oscura/automotive/loaders/dispatcher.py +50 -2
  148. oscura/automotive/loaders/mdf.py +86 -45
  149. oscura/automotive/loaders/pcap.py +111 -61
  150. oscura/automotive/uds/__init__.py +4 -0
  151. oscura/automotive/uds/analyzer.py +725 -0
  152. oscura/automotive/uds/decoder.py +140 -58
  153. oscura/automotive/uds/models.py +7 -1
  154. oscura/automotive/visualization.py +1 -1
  155. oscura/cli/analyze.py +348 -0
  156. oscura/cli/batch.py +142 -122
  157. oscura/cli/benchmark.py +275 -0
  158. oscura/cli/characterize.py +137 -82
  159. oscura/cli/compare.py +224 -131
  160. oscura/cli/completion.py +250 -0
  161. oscura/cli/config_cmd.py +361 -0
  162. oscura/cli/decode.py +164 -87
  163. oscura/cli/export.py +286 -0
  164. oscura/cli/main.py +115 -31
  165. oscura/{onboarding → cli/onboarding}/__init__.py +3 -3
  166. oscura/{onboarding → cli/onboarding}/help.py +80 -58
  167. oscura/{onboarding → cli/onboarding}/tutorials.py +97 -72
  168. oscura/{onboarding → cli/onboarding}/wizard.py +55 -36
  169. oscura/cli/progress.py +147 -0
  170. oscura/cli/shell.py +157 -135
  171. oscura/cli/validate_cmd.py +204 -0
  172. oscura/cli/visualize.py +158 -0
  173. oscura/convenience.py +125 -79
  174. oscura/core/__init__.py +4 -2
  175. oscura/core/backend_selector.py +3 -3
  176. oscura/core/cache.py +126 -15
  177. oscura/core/cancellation.py +1 -1
  178. oscura/{config → core/config}/__init__.py +20 -11
  179. oscura/{config → core/config}/defaults.py +1 -1
  180. oscura/{config → core/config}/loader.py +7 -5
  181. oscura/{config → core/config}/memory.py +5 -5
  182. oscura/{config → core/config}/migration.py +1 -1
  183. oscura/{config → core/config}/pipeline.py +99 -23
  184. oscura/{config → core/config}/preferences.py +1 -1
  185. oscura/{config → core/config}/protocol.py +3 -3
  186. oscura/{config → core/config}/schema.py +426 -272
  187. oscura/{config → core/config}/settings.py +1 -1
  188. oscura/{config → core/config}/thresholds.py +195 -153
  189. oscura/core/correlation.py +5 -6
  190. oscura/core/cross_domain.py +0 -2
  191. oscura/core/debug.py +9 -5
  192. oscura/{extensibility → core/extensibility}/docs.py +158 -70
  193. oscura/{extensibility → core/extensibility}/extensions.py +160 -76
  194. oscura/{extensibility → core/extensibility}/logging.py +1 -1
  195. oscura/{extensibility → core/extensibility}/measurements.py +1 -1
  196. oscura/{extensibility → core/extensibility}/plugins.py +1 -1
  197. oscura/{extensibility → core/extensibility}/templates.py +73 -3
  198. oscura/{extensibility → core/extensibility}/validation.py +1 -1
  199. oscura/core/gpu_backend.py +11 -7
  200. oscura/core/log_query.py +101 -11
  201. oscura/core/logging.py +126 -54
  202. oscura/core/logging_advanced.py +5 -5
  203. oscura/core/memory_limits.py +108 -70
  204. oscura/core/memory_monitor.py +2 -2
  205. oscura/core/memory_progress.py +7 -7
  206. oscura/core/memory_warnings.py +1 -1
  207. oscura/core/numba_backend.py +13 -13
  208. oscura/{plugins → core/plugins}/__init__.py +9 -9
  209. oscura/{plugins → core/plugins}/base.py +7 -7
  210. oscura/{plugins → core/plugins}/cli.py +3 -3
  211. oscura/{plugins → core/plugins}/discovery.py +186 -106
  212. oscura/{plugins → core/plugins}/lifecycle.py +1 -1
  213. oscura/{plugins → core/plugins}/manager.py +7 -7
  214. oscura/{plugins → core/plugins}/registry.py +3 -3
  215. oscura/{plugins → core/plugins}/versioning.py +1 -1
  216. oscura/core/progress.py +16 -1
  217. oscura/core/provenance.py +8 -2
  218. oscura/{schemas → core/schemas}/__init__.py +2 -2
  219. oscura/{schemas → core/schemas}/device_mapping.json +2 -8
  220. oscura/{schemas → core/schemas}/packet_format.json +4 -24
  221. oscura/{schemas → core/schemas}/protocol_definition.json +2 -12
  222. oscura/core/types.py +4 -0
  223. oscura/core/uncertainty.py +3 -3
  224. oscura/correlation/__init__.py +52 -0
  225. oscura/correlation/multi_protocol.py +811 -0
  226. oscura/discovery/auto_decoder.py +117 -35
  227. oscura/discovery/comparison.py +191 -86
  228. oscura/discovery/quality_validator.py +155 -68
  229. oscura/discovery/signal_detector.py +196 -79
  230. oscura/export/__init__.py +18 -8
  231. oscura/export/kaitai_struct.py +513 -0
  232. oscura/export/scapy_layer.py +801 -0
  233. oscura/export/wireshark/generator.py +1 -1
  234. oscura/export/wireshark/templates/dissector.lua.j2 +2 -2
  235. oscura/export/wireshark_dissector.py +746 -0
  236. oscura/guidance/wizard.py +207 -111
  237. oscura/hardware/__init__.py +19 -0
  238. oscura/{acquisition → hardware/acquisition}/__init__.py +4 -4
  239. oscura/{acquisition → hardware/acquisition}/file.py +2 -2
  240. oscura/{acquisition → hardware/acquisition}/hardware.py +7 -7
  241. oscura/{acquisition → hardware/acquisition}/saleae.py +15 -12
  242. oscura/{acquisition → hardware/acquisition}/socketcan.py +1 -1
  243. oscura/{acquisition → hardware/acquisition}/streaming.py +2 -2
  244. oscura/{acquisition → hardware/acquisition}/synthetic.py +3 -3
  245. oscura/{acquisition → hardware/acquisition}/visa.py +33 -11
  246. oscura/hardware/firmware/__init__.py +29 -0
  247. oscura/hardware/firmware/pattern_recognition.py +874 -0
  248. oscura/hardware/hal_detector.py +736 -0
  249. oscura/hardware/security/__init__.py +37 -0
  250. oscura/hardware/security/side_channel_detector.py +1126 -0
  251. oscura/inference/__init__.py +4 -0
  252. oscura/inference/active_learning/observation_table.py +4 -1
  253. oscura/inference/alignment.py +216 -123
  254. oscura/inference/bayesian.py +113 -33
  255. oscura/inference/crc_reverse.py +101 -55
  256. oscura/inference/logic.py +6 -2
  257. oscura/inference/message_format.py +342 -183
  258. oscura/inference/protocol.py +95 -44
  259. oscura/inference/protocol_dsl.py +180 -82
  260. oscura/inference/signal_intelligence.py +1439 -706
  261. oscura/inference/spectral.py +99 -57
  262. oscura/inference/state_machine.py +810 -158
  263. oscura/inference/stream.py +270 -110
  264. oscura/iot/__init__.py +34 -0
  265. oscura/iot/coap/__init__.py +32 -0
  266. oscura/iot/coap/analyzer.py +668 -0
  267. oscura/iot/coap/options.py +212 -0
  268. oscura/iot/lorawan/__init__.py +21 -0
  269. oscura/iot/lorawan/crypto.py +206 -0
  270. oscura/iot/lorawan/decoder.py +801 -0
  271. oscura/iot/lorawan/mac_commands.py +341 -0
  272. oscura/iot/mqtt/__init__.py +27 -0
  273. oscura/iot/mqtt/analyzer.py +999 -0
  274. oscura/iot/mqtt/properties.py +315 -0
  275. oscura/iot/zigbee/__init__.py +31 -0
  276. oscura/iot/zigbee/analyzer.py +615 -0
  277. oscura/iot/zigbee/security.py +153 -0
  278. oscura/iot/zigbee/zcl.py +349 -0
  279. oscura/jupyter/display.py +125 -45
  280. oscura/{exploratory → jupyter/exploratory}/__init__.py +8 -8
  281. oscura/{exploratory → jupyter/exploratory}/error_recovery.py +298 -141
  282. oscura/jupyter/exploratory/fuzzy.py +746 -0
  283. oscura/{exploratory → jupyter/exploratory}/fuzzy_advanced.py +258 -100
  284. oscura/{exploratory → jupyter/exploratory}/legacy.py +464 -242
  285. oscura/{exploratory → jupyter/exploratory}/parse.py +167 -145
  286. oscura/{exploratory → jupyter/exploratory}/recovery.py +119 -87
  287. oscura/jupyter/exploratory/sync.py +612 -0
  288. oscura/{exploratory → jupyter/exploratory}/unknown.py +299 -176
  289. oscura/jupyter/magic.py +4 -4
  290. oscura/{ui → jupyter/ui}/__init__.py +2 -2
  291. oscura/{ui → jupyter/ui}/formatters.py +3 -3
  292. oscura/{ui → jupyter/ui}/progressive_display.py +153 -82
  293. oscura/loaders/__init__.py +183 -67
  294. oscura/loaders/binary.py +88 -1
  295. oscura/loaders/chipwhisperer.py +153 -137
  296. oscura/loaders/configurable.py +208 -86
  297. oscura/loaders/csv_loader.py +458 -215
  298. oscura/loaders/hdf5_loader.py +278 -119
  299. oscura/loaders/lazy.py +87 -54
  300. oscura/loaders/mmap_loader.py +1 -1
  301. oscura/loaders/numpy_loader.py +253 -116
  302. oscura/loaders/pcap.py +226 -151
  303. oscura/loaders/rigol.py +110 -49
  304. oscura/loaders/sigrok.py +201 -78
  305. oscura/loaders/tdms.py +81 -58
  306. oscura/loaders/tektronix.py +291 -174
  307. oscura/loaders/touchstone.py +182 -87
  308. oscura/loaders/tss.py +456 -0
  309. oscura/loaders/vcd.py +215 -117
  310. oscura/loaders/wav.py +155 -68
  311. oscura/reporting/__init__.py +9 -0
  312. oscura/reporting/analyze.py +352 -146
  313. oscura/reporting/argument_preparer.py +69 -14
  314. oscura/reporting/auto_report.py +97 -61
  315. oscura/reporting/batch.py +131 -58
  316. oscura/reporting/chart_selection.py +57 -45
  317. oscura/reporting/comparison.py +63 -17
  318. oscura/reporting/content/executive.py +76 -24
  319. oscura/reporting/core_formats/multi_format.py +11 -8
  320. oscura/reporting/engine.py +312 -158
  321. oscura/reporting/enhanced_reports.py +949 -0
  322. oscura/reporting/export.py +86 -43
  323. oscura/reporting/formatting/numbers.py +69 -42
  324. oscura/reporting/html.py +139 -58
  325. oscura/reporting/index.py +137 -65
  326. oscura/reporting/output.py +158 -67
  327. oscura/reporting/pdf.py +67 -102
  328. oscura/reporting/plots.py +191 -112
  329. oscura/reporting/sections.py +88 -47
  330. oscura/reporting/standards.py +104 -61
  331. oscura/reporting/summary_generator.py +75 -55
  332. oscura/reporting/tables.py +138 -54
  333. oscura/reporting/templates/enhanced/protocol_re.html +525 -0
  334. oscura/sessions/__init__.py +14 -23
  335. oscura/sessions/base.py +3 -3
  336. oscura/sessions/blackbox.py +106 -10
  337. oscura/sessions/generic.py +2 -2
  338. oscura/sessions/legacy.py +783 -0
  339. oscura/side_channel/__init__.py +63 -0
  340. oscura/side_channel/dpa.py +1025 -0
  341. oscura/utils/__init__.py +15 -1
  342. oscura/utils/bitwise.py +118 -0
  343. oscura/{builders → utils/builders}/__init__.py +1 -1
  344. oscura/{comparison → utils/comparison}/__init__.py +6 -6
  345. oscura/{comparison → utils/comparison}/compare.py +202 -101
  346. oscura/{comparison → utils/comparison}/golden.py +83 -63
  347. oscura/{comparison → utils/comparison}/limits.py +313 -89
  348. oscura/{comparison → utils/comparison}/mask.py +151 -45
  349. oscura/{comparison → utils/comparison}/trace_diff.py +1 -1
  350. oscura/{comparison → utils/comparison}/visualization.py +147 -89
  351. oscura/{component → utils/component}/__init__.py +3 -3
  352. oscura/{component → utils/component}/impedance.py +122 -58
  353. oscura/{component → utils/component}/reactive.py +165 -168
  354. oscura/{component → utils/component}/transmission_line.py +3 -3
  355. oscura/{filtering → utils/filtering}/__init__.py +6 -6
  356. oscura/{filtering → utils/filtering}/base.py +1 -1
  357. oscura/{filtering → utils/filtering}/convenience.py +2 -2
  358. oscura/{filtering → utils/filtering}/design.py +169 -93
  359. oscura/{filtering → utils/filtering}/filters.py +2 -2
  360. oscura/{filtering → utils/filtering}/introspection.py +2 -2
  361. oscura/utils/geometry.py +31 -0
  362. oscura/utils/imports.py +184 -0
  363. oscura/utils/lazy.py +1 -1
  364. oscura/{math → utils/math}/__init__.py +2 -2
  365. oscura/{math → utils/math}/arithmetic.py +114 -48
  366. oscura/{math → utils/math}/interpolation.py +139 -106
  367. oscura/utils/memory.py +129 -66
  368. oscura/utils/memory_advanced.py +92 -9
  369. oscura/utils/memory_extensions.py +10 -8
  370. oscura/{optimization → utils/optimization}/__init__.py +1 -1
  371. oscura/{optimization → utils/optimization}/search.py +2 -2
  372. oscura/utils/performance/__init__.py +58 -0
  373. oscura/utils/performance/caching.py +889 -0
  374. oscura/utils/performance/lsh_clustering.py +333 -0
  375. oscura/utils/performance/memory_optimizer.py +699 -0
  376. oscura/utils/performance/optimizations.py +675 -0
  377. oscura/utils/performance/parallel.py +654 -0
  378. oscura/utils/performance/profiling.py +661 -0
  379. oscura/{pipeline → utils/pipeline}/base.py +1 -1
  380. oscura/{pipeline → utils/pipeline}/composition.py +1 -1
  381. oscura/{pipeline → utils/pipeline}/parallel.py +3 -2
  382. oscura/{pipeline → utils/pipeline}/pipeline.py +1 -1
  383. oscura/{pipeline → utils/pipeline}/reverse_engineering.py +412 -221
  384. oscura/{search → utils/search}/__init__.py +3 -3
  385. oscura/{search → utils/search}/anomaly.py +188 -58
  386. oscura/utils/search/context.py +294 -0
  387. oscura/{search → utils/search}/pattern.py +138 -10
  388. oscura/utils/serial.py +51 -0
  389. oscura/utils/storage/__init__.py +61 -0
  390. oscura/utils/storage/database.py +1166 -0
  391. oscura/{streaming → utils/streaming}/chunked.py +302 -143
  392. oscura/{streaming → utils/streaming}/progressive.py +1 -1
  393. oscura/{streaming → utils/streaming}/realtime.py +3 -2
  394. oscura/{triggering → utils/triggering}/__init__.py +6 -6
  395. oscura/{triggering → utils/triggering}/base.py +6 -6
  396. oscura/{triggering → utils/triggering}/edge.py +2 -2
  397. oscura/{triggering → utils/triggering}/pattern.py +2 -2
  398. oscura/{triggering → utils/triggering}/pulse.py +115 -74
  399. oscura/{triggering → utils/triggering}/window.py +2 -2
  400. oscura/utils/validation.py +32 -0
  401. oscura/validation/__init__.py +121 -0
  402. oscura/{compliance → validation/compliance}/__init__.py +5 -5
  403. oscura/{compliance → validation/compliance}/advanced.py +5 -5
  404. oscura/{compliance → validation/compliance}/masks.py +1 -1
  405. oscura/{compliance → validation/compliance}/reporting.py +127 -53
  406. oscura/{compliance → validation/compliance}/testing.py +114 -52
  407. oscura/validation/compliance_tests.py +915 -0
  408. oscura/validation/fuzzer.py +990 -0
  409. oscura/validation/grammar_tests.py +596 -0
  410. oscura/validation/grammar_validator.py +904 -0
  411. oscura/validation/hil_testing.py +977 -0
  412. oscura/{quality → validation/quality}/__init__.py +4 -4
  413. oscura/{quality → validation/quality}/ensemble.py +251 -171
  414. oscura/{quality → validation/quality}/explainer.py +3 -3
  415. oscura/{quality → validation/quality}/scoring.py +1 -1
  416. oscura/{quality → validation/quality}/warnings.py +4 -4
  417. oscura/validation/regression_suite.py +808 -0
  418. oscura/validation/replay.py +788 -0
  419. oscura/{testing → validation/testing}/__init__.py +2 -2
  420. oscura/{testing → validation/testing}/synthetic.py +5 -5
  421. oscura/visualization/__init__.py +9 -0
  422. oscura/visualization/accessibility.py +1 -1
  423. oscura/visualization/annotations.py +64 -67
  424. oscura/visualization/colors.py +7 -7
  425. oscura/visualization/digital.py +180 -81
  426. oscura/visualization/eye.py +236 -85
  427. oscura/visualization/interactive.py +320 -143
  428. oscura/visualization/jitter.py +587 -247
  429. oscura/visualization/layout.py +169 -134
  430. oscura/visualization/optimization.py +103 -52
  431. oscura/visualization/palettes.py +1 -1
  432. oscura/visualization/power.py +427 -211
  433. oscura/visualization/power_extended.py +626 -297
  434. oscura/visualization/presets.py +2 -0
  435. oscura/visualization/protocols.py +495 -181
  436. oscura/visualization/render.py +79 -63
  437. oscura/visualization/reverse_engineering.py +171 -124
  438. oscura/visualization/signal_integrity.py +460 -279
  439. oscura/visualization/specialized.py +190 -100
  440. oscura/visualization/spectral.py +670 -255
  441. oscura/visualization/thumbnails.py +166 -137
  442. oscura/visualization/waveform.py +150 -63
  443. oscura/workflows/__init__.py +3 -0
  444. oscura/{batch → workflows/batch}/__init__.py +5 -5
  445. oscura/{batch → workflows/batch}/advanced.py +150 -75
  446. oscura/workflows/batch/aggregate.py +531 -0
  447. oscura/workflows/batch/analyze.py +236 -0
  448. oscura/{batch → workflows/batch}/logging.py +2 -2
  449. oscura/{batch → workflows/batch}/metrics.py +1 -1
  450. oscura/workflows/complete_re.py +1144 -0
  451. oscura/workflows/compliance.py +44 -54
  452. oscura/workflows/digital.py +197 -51
  453. oscura/workflows/legacy/__init__.py +12 -0
  454. oscura/{workflow → workflows/legacy}/dag.py +4 -1
  455. oscura/workflows/multi_trace.py +9 -9
  456. oscura/workflows/power.py +42 -62
  457. oscura/workflows/protocol.py +82 -49
  458. oscura/workflows/reverse_engineering.py +351 -150
  459. oscura/workflows/signal_integrity.py +157 -82
  460. oscura-0.7.0.dist-info/METADATA +661 -0
  461. oscura-0.7.0.dist-info/RECORD +591 -0
  462. oscura/batch/aggregate.py +0 -300
  463. oscura/batch/analyze.py +0 -139
  464. oscura/dsl/__init__.py +0 -73
  465. oscura/exceptions.py +0 -59
  466. oscura/exploratory/fuzzy.py +0 -513
  467. oscura/exploratory/sync.py +0 -384
  468. oscura/exporters/__init__.py +0 -94
  469. oscura/exporters/csv.py +0 -303
  470. oscura/exporters/exporters.py +0 -44
  471. oscura/exporters/hdf5.py +0 -217
  472. oscura/exporters/html_export.py +0 -701
  473. oscura/exporters/json_export.py +0 -291
  474. oscura/exporters/markdown_export.py +0 -367
  475. oscura/exporters/matlab_export.py +0 -354
  476. oscura/exporters/npz_export.py +0 -219
  477. oscura/exporters/spice_export.py +0 -210
  478. oscura/search/context.py +0 -149
  479. oscura/session/__init__.py +0 -34
  480. oscura/session/annotations.py +0 -289
  481. oscura/session/history.py +0 -313
  482. oscura/session/session.py +0 -520
  483. oscura/workflow/__init__.py +0 -13
  484. oscura-0.5.1.dist-info/METADATA +0 -583
  485. oscura-0.5.1.dist-info/RECORD +0 -481
  486. /oscura/core/{config.py → config/legacy.py} +0 -0
  487. /oscura/{extensibility → core/extensibility}/__init__.py +0 -0
  488. /oscura/{extensibility → core/extensibility}/registry.py +0 -0
  489. /oscura/{plugins → core/plugins}/isolation.py +0 -0
  490. /oscura/{schemas → core/schemas}/bus_configuration.json +0 -0
  491. /oscura/{builders → utils/builders}/signal_builder.py +0 -0
  492. /oscura/{optimization → utils/optimization}/parallel.py +0 -0
  493. /oscura/{pipeline → utils/pipeline}/__init__.py +0 -0
  494. /oscura/{streaming → utils/streaming}/__init__.py +0 -0
  495. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/WHEEL +0 -0
  496. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/entry_points.txt +0 -0
  497. {oscura-0.5.1.dist-info → oscura-0.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,212 @@
1
+ """CoAP option definitions and parsing helpers.
2
+
3
+ Provides option number to name mappings, content format definitions,
4
+ and helper functions for decoding CoAP options.
5
+
6
+ References:
7
+ RFC 7252 Section 5.10: Option Definitions
8
+ RFC 7252 Section 12.3: CoAP Content-Formats Registry
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ from typing import Any, ClassVar
14
+
15
+ # CoAP option number to name mapping (RFC 7252)
16
+ OPTIONS: dict[int, str] = {
17
+ 1: "If-Match",
18
+ 3: "Uri-Host",
19
+ 4: "ETag",
20
+ 5: "If-None-Match",
21
+ 6: "Observe", # RFC 7641
22
+ 7: "Uri-Port",
23
+ 8: "Location-Path",
24
+ 11: "Uri-Path",
25
+ 12: "Content-Format",
26
+ 14: "Max-Age",
27
+ 15: "Uri-Query",
28
+ 17: "Accept",
29
+ 20: "Location-Query",
30
+ 23: "Block2", # RFC 7959
31
+ 27: "Block1", # RFC 7959
32
+ 28: "Size2", # RFC 7959
33
+ 35: "Proxy-Uri",
34
+ 39: "Proxy-Scheme",
35
+ 60: "Size1", # RFC 7959
36
+ }
37
+
38
+ # CoAP content format codes (RFC 7252)
39
+ CONTENT_FORMATS: dict[int, str] = {
40
+ 0: "text/plain; charset=utf-8",
41
+ 40: "application/link-format",
42
+ 41: "application/xml",
43
+ 42: "application/octet-stream",
44
+ 47: "application/exi",
45
+ 50: "application/json",
46
+ 60: "application/cbor",
47
+ # Additional formats from IANA registry
48
+ 100: "application/senml+json",
49
+ 101: "application/sensml+json",
50
+ 110: "application/senml+cbor",
51
+ 111: "application/sensml+cbor",
52
+ 112: "application/senml-exi",
53
+ 113: "application/sensml-exi",
54
+ 256: "application/coap-group+json",
55
+ 10000: "application/pkcs7-mime; smime-type=server-generated-key",
56
+ 10001: "application/pkcs7-mime; smime-type=certs-only",
57
+ 10002: "application/pkcs8",
58
+ 10003: "application/csrattrs",
59
+ 10004: "application/pkcs10",
60
+ 10005: "application/pkix-cert",
61
+ }
62
+
63
+
64
+ class OptionParser:
65
+ """Helper class for parsing CoAP options.
66
+
67
+ Provides methods for decoding option values based on their option number
68
+ and handling CoAP option delta encoding.
69
+
70
+ Example:
71
+ >>> parser = OptionParser()
72
+ >>> value = parser.decode_value(11, b"temperature")
73
+ >>> print(value)
74
+ 'temperature'
75
+ """
76
+
77
+ # Empty format options (no value)
78
+ EMPTY_OPTIONS: ClassVar[set[int]] = {5} # If-None-Match
79
+
80
+ # Opaque options (bytes)
81
+ OPAQUE_OPTIONS: ClassVar[set[int]] = {1, 4} # If-Match, ETag
82
+
83
+ # String options (UTF-8)
84
+ STRING_OPTIONS: ClassVar[set[int]] = {3, 8, 11, 15, 20, 35, 39}
85
+
86
+ # Unsigned integer options
87
+ UINT_OPTIONS: ClassVar[set[int]] = {6, 7, 12, 14, 17, 23, 27, 28, 60}
88
+
89
+ @staticmethod
90
+ def decode_value(option_num: int, value: bytes) -> str | int | bytes:
91
+ """Decode option value based on option number.
92
+
93
+ Args:
94
+ option_num: CoAP option number.
95
+ value: Raw option value bytes.
96
+
97
+ Returns:
98
+ Decoded value as string, int, or bytes depending on option type.
99
+
100
+ Example:
101
+ >>> parser = OptionParser()
102
+ >>> parser.decode_value(11, b"sensor")
103
+ 'sensor'
104
+ >>> parser.decode_value(12, b"\\x00\\x32")
105
+ 50
106
+ """
107
+ if option_num in OptionParser.EMPTY_OPTIONS:
108
+ return b""
109
+
110
+ if not value:
111
+ # Empty value - return appropriate type
112
+ if option_num in OptionParser.STRING_OPTIONS:
113
+ return ""
114
+ if option_num in OptionParser.UINT_OPTIONS:
115
+ return 0
116
+ return b""
117
+
118
+ if option_num in OptionParser.STRING_OPTIONS:
119
+ try:
120
+ return value.decode("utf-8")
121
+ except UnicodeDecodeError:
122
+ return value
123
+
124
+ if option_num in OptionParser.UINT_OPTIONS:
125
+ return int.from_bytes(value, "big")
126
+
127
+ # Default to opaque (bytes)
128
+ return value
129
+
130
+ @staticmethod
131
+ def parse_extended_value(base: int, data: bytes, offset: int) -> tuple[int, int]:
132
+ """Parse extended delta or length value.
133
+
134
+ CoAP uses extended encoding for delta/length values >= 13:
135
+ - 13: value is (base value from next byte) + 13
136
+ - 14: value is (base value from next 2 bytes) + 269
137
+ - 15: reserved (payload marker or error)
138
+
139
+ Args:
140
+ base: Base value (0-15) from option header nibble.
141
+ data: Complete message data.
142
+ offset: Current offset in data.
143
+
144
+ Returns:
145
+ Tuple of (actual_value, bytes_consumed).
146
+
147
+ Raises:
148
+ ValueError: If extended format is invalid or data insufficient.
149
+
150
+ Example:
151
+ >>> parser = OptionParser()
152
+ >>> value, consumed = parser.parse_extended_value(13, b"\\x05\\x00", 0)
153
+ >>> value, consumed
154
+ (18, 1)
155
+ """
156
+ if base < 13:
157
+ return base, 0
158
+
159
+ if base == 13:
160
+ if len(data) < offset + 1:
161
+ raise ValueError("Insufficient data for extended option delta/length")
162
+ return data[offset] + 13, 1
163
+
164
+ if base == 14:
165
+ if len(data) < offset + 2:
166
+ raise ValueError("Insufficient data for extended option delta/length")
167
+ return int.from_bytes(data[offset : offset + 2], "big") + 269, 2
168
+
169
+ # base == 15
170
+ raise ValueError("Invalid option delta/length value (15)")
171
+
172
+
173
+ def format_block_option(value: int) -> dict[str, Any]:
174
+ """Parse Block1/Block2 option value.
175
+
176
+ Block options encode: NUM (block number), M (more flag), SZX (size exponent).
177
+
178
+ Format (variable length, 1-3 bytes):
179
+ 0 1 2 3 4 5 6 7
180
+ +-+-+-+-+-+-+-+-+
181
+ | NUM |M| SZX |
182
+ +-+-+-+-+-+-+-+-+
183
+
184
+ Args:
185
+ value: Block option value as unsigned integer.
186
+
187
+ Returns:
188
+ Dictionary with 'num' (block number), 'more' (more flag), and 'size' (block size).
189
+
190
+ Example:
191
+ >>> result = format_block_option(0x08) # Block 0, no more, size 16
192
+ >>> result['num'], result['more'], result['size']
193
+ (0, False, 16)
194
+ """
195
+ num = value >> 4
196
+ more = bool((value >> 3) & 0x01)
197
+ szx = value & 0x07
198
+ size = 2 ** (szx + 4) # Size = 2^(SZX+4), range: 16-1024 bytes
199
+
200
+ return {
201
+ "num": num,
202
+ "more": more,
203
+ "size": size,
204
+ }
205
+
206
+
207
+ __all__ = [
208
+ "CONTENT_FORMATS",
209
+ "OPTIONS",
210
+ "OptionParser",
211
+ "format_block_option",
212
+ ]
@@ -0,0 +1,21 @@
1
+ """LoRaWAN protocol decoder package.
2
+
3
+ Provides LoRaWAN MAC layer parsing and payload decryption support.
4
+ """
5
+
6
+ from oscura.iot.lorawan.decoder import (
7
+ LoRaWANDecoder,
8
+ LoRaWANFrame,
9
+ LoRaWANKeys,
10
+ decode_lorawan_frame,
11
+ )
12
+ from oscura.iot.lorawan.mac_commands import MAC_COMMANDS, parse_mac_command
13
+
14
+ __all__ = [
15
+ "MAC_COMMANDS",
16
+ "LoRaWANDecoder",
17
+ "LoRaWANFrame",
18
+ "LoRaWANKeys",
19
+ "decode_lorawan_frame",
20
+ "parse_mac_command",
21
+ ]
@@ -0,0 +1,206 @@
1
+ """LoRaWAN cryptographic operations.
2
+
3
+ This module provides AES-128 encryption/decryption and CMAC operations
4
+ for LoRaWAN payload security as defined in LoRaWAN Specification 1.0.3.
5
+
6
+ Security:
7
+ Uses cryptography library (modern, actively maintained) instead of deprecated PyCrypto.
8
+ All cryptographic operations follow LoRaWAN 1.0.3 specification.
9
+
10
+ References:
11
+ LoRaWAN Specification 1.0.3: https://lora-alliance.org/resource_hub/lorawan-specification-v1-0-3/
12
+ Section 4.3.3 - MAC Frame Payload Encryption (FRMPayload)
13
+ Section 4.4 - Message Integrity Code (MIC)
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ from typing import Literal
19
+
20
+
21
+ def decrypt_payload(
22
+ frm_payload: bytes,
23
+ key: bytes,
24
+ dev_addr: int,
25
+ fcnt: int,
26
+ direction: Literal["up", "down"],
27
+ ) -> bytes:
28
+ """Decrypt LoRaWAN FRMPayload using AES-128 in CTR mode.
29
+
30
+ Args:
31
+ frm_payload: Encrypted payload bytes.
32
+ key: AES-128 key (16 bytes) - AppSKey or NwkSKey.
33
+ dev_addr: Device address (4 bytes).
34
+ fcnt: Frame counter.
35
+ direction: Direction "up" (uplink) or "down" (downlink).
36
+
37
+ Returns:
38
+ Decrypted payload bytes.
39
+
40
+ Raises:
41
+ ValueError: If key is not 16 bytes.
42
+ ImportError: If cryptography library is not available.
43
+
44
+ Example:
45
+ >>> key = bytes.fromhex("2B7E151628AED2A6ABF7158809CF4F3C")
46
+ >>> encrypted = bytes.fromhex("0123456789ABCDEF")
47
+ >>> decrypted = decrypt_payload(encrypted, key, 0x01020304, 1, "up")
48
+ """
49
+ try:
50
+ from cryptography.hazmat.backends import default_backend
51
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
52
+ except ImportError as exc:
53
+ msg = (
54
+ "cryptography library is required for LoRaWAN encryption. "
55
+ "Install with: pip install cryptography"
56
+ )
57
+ raise ImportError(msg) from exc
58
+
59
+ if len(key) != 16:
60
+ msg = f"Key must be 16 bytes, got {len(key)}"
61
+ raise ValueError(msg)
62
+
63
+ if len(frm_payload) == 0:
64
+ return b""
65
+
66
+ # Direction byte: 0x00 for uplink, 0x01 for downlink
67
+ dir_byte = 0x00 if direction == "up" else 0x01
68
+
69
+ # Number of 16-byte blocks needed
70
+ num_blocks = (len(frm_payload) + 15) // 16
71
+
72
+ # Generate keystream by encrypting counter blocks
73
+ keystream = b""
74
+ for i in range(num_blocks):
75
+ # Build encryption block A_i (16 bytes)
76
+ # A_i = 0x01 | 0x00000000 | Dir | DevAddr | FCnt | 0x00 | i
77
+ a = bytearray(16)
78
+ a[0] = 0x01 # Encryption flag
79
+ # a[1:5] = 0x00000000 (already zero)
80
+ a[5] = dir_byte
81
+ a[6:10] = dev_addr.to_bytes(4, "little")
82
+ a[10:14] = fcnt.to_bytes(4, "little")
83
+ # a[14] = 0x00 (already zero)
84
+ a[15] = i + 1
85
+
86
+ # Encrypt the block using AES in ECB mode
87
+ # Security: ECB mode is required by LoRaWAN spec (Section 4.3.3)
88
+ # Each counter block is unique, so ECB mode is safe here
89
+ cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())
90
+ encryptor = cipher.encryptor()
91
+ keystream += encryptor.update(bytes(a)) + encryptor.finalize()
92
+
93
+ # XOR payload with keystream
94
+ decrypted = bytes(
95
+ p ^ k for p, k in zip(frm_payload, keystream[: len(frm_payload)], strict=False)
96
+ )
97
+ return decrypted
98
+
99
+
100
+ def compute_mic(
101
+ data: bytes,
102
+ key: bytes,
103
+ dev_addr: int,
104
+ fcnt: int,
105
+ direction: Literal["up", "down"],
106
+ ) -> int:
107
+ """Compute LoRaWAN Message Integrity Code (MIC) using AES-CMAC.
108
+
109
+ Args:
110
+ data: Message data (MHDR | FHDR | FPort | FRMPayload).
111
+ key: Network session key (NwkSKey, 16 bytes).
112
+ dev_addr: Device address (4 bytes).
113
+ fcnt: Frame counter.
114
+ direction: Direction "up" (uplink) or "down" (downlink).
115
+
116
+ Returns:
117
+ 32-bit MIC value.
118
+
119
+ Raises:
120
+ ValueError: If key is not 16 bytes.
121
+ ImportError: If cryptography library is not available.
122
+
123
+ Example:
124
+ >>> key = bytes.fromhex("2B7E151628AED2A6ABF7158809CF4F3C")
125
+ >>> data = bytes.fromhex("40010203040001000100")
126
+ >>> mic = compute_mic(data, key, 0x01020304, 1, "up")
127
+ """
128
+ try:
129
+ from cryptography.hazmat.backends import default_backend
130
+ from cryptography.hazmat.primitives import cmac
131
+ from cryptography.hazmat.primitives.ciphers import algorithms
132
+ except ImportError as exc:
133
+ msg = (
134
+ "cryptography library is required for LoRaWAN MIC computation. "
135
+ "Install with: pip install cryptography"
136
+ )
137
+ raise ImportError(msg) from exc
138
+
139
+ if len(key) != 16:
140
+ msg = f"Key must be 16 bytes, got {len(key)}"
141
+ raise ValueError(msg)
142
+
143
+ # Direction byte: 0x00 for uplink, 0x01 for downlink
144
+ dir_byte = 0x00 if direction == "up" else 0x01
145
+
146
+ # Build MIC computation block B_0 (16 bytes)
147
+ # B_0 = 0x49 | 0x00000000 | Dir | DevAddr | FCnt | 0x00 | len(msg)
148
+ b0 = bytearray(16)
149
+ b0[0] = 0x49 # MIC flag
150
+ # b0[1:5] = 0x00000000 (already zero)
151
+ b0[5] = dir_byte
152
+ b0[6:10] = dev_addr.to_bytes(4, "little")
153
+ b0[10:14] = fcnt.to_bytes(4, "little")
154
+ # b0[14] = 0x00 (already zero)
155
+ b0[15] = len(data)
156
+
157
+ # Compute CMAC over B_0 | msg
158
+ c = cmac.CMAC(algorithms.AES(key), backend=default_backend())
159
+ c.update(bytes(b0))
160
+ c.update(data)
161
+ mac = c.finalize()
162
+
163
+ # Return first 4 bytes as 32-bit integer (little-endian)
164
+ mic = int.from_bytes(mac[:4], "little")
165
+ return mic
166
+
167
+
168
+ def verify_mic(
169
+ data: bytes,
170
+ received_mic: int,
171
+ key: bytes,
172
+ dev_addr: int,
173
+ fcnt: int,
174
+ direction: Literal["up", "down"],
175
+ ) -> bool:
176
+ """Verify LoRaWAN Message Integrity Code (MIC).
177
+
178
+ Args:
179
+ data: Message data (MHDR | FHDR | FPort | FRMPayload).
180
+ received_mic: Received MIC value.
181
+ key: Network session key (NwkSKey, 16 bytes).
182
+ dev_addr: Device address (4 bytes).
183
+ fcnt: Frame counter.
184
+ direction: Direction "up" (uplink) or "down" (downlink).
185
+
186
+ Returns:
187
+ True if MIC is valid, False otherwise.
188
+
189
+ Example:
190
+ >>> key = bytes.fromhex("2B7E151628AED2A6ABF7158809CF4F3C")
191
+ >>> data = bytes.fromhex("40010203040001000100")
192
+ >>> is_valid = verify_mic(data, 0x12345678, key, 0x01020304, 1, "up")
193
+ """
194
+ try:
195
+ computed_mic = compute_mic(data, key, dev_addr, fcnt, direction)
196
+ return computed_mic == received_mic
197
+ except (ImportError, ValueError):
198
+ # If crypto is unavailable, we can't verify
199
+ return False
200
+
201
+
202
+ __all__ = [
203
+ "compute_mic",
204
+ "decrypt_payload",
205
+ "verify_mic",
206
+ ]