cbom-tools 0.1.0 → 0.2.0

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.
package/README.md CHANGED
@@ -40,6 +40,19 @@ Exit codes:
40
40
  - `0` — no changes
41
41
  - `1` — changes detected
42
42
  - `2` — file not found or parse error
43
+ - `3` — (reserved) quantum-vulnerable/weak algorithm detection (planned for 0.2.0)
44
+
45
+ ## Testing
46
+
47
+ ```
48
+ npm test
49
+ ```
50
+
51
+ 17 CLI contract tests (Node built-in `node:test`, zero dependencies):
52
+ both binaries are spawned as child processes and checked against edge
53
+ inputs — empty directory, dependencies-only, source-only, an 800-file
54
+ tree (occurrence cap, `node_modules` / `.git` / dotfile skipping),
55
+ unreachable directories, missing argument values, and malformed JSON.
43
56
 
44
57
  ## Example (real output)
45
58
 
@@ -2,7 +2,7 @@
2
2
  "ML-KEM": {
3
3
  "assetType": "algorithm",
4
4
  "algorithmProperties": {
5
- "primitive": "KEM"
5
+ "primitive": "kem"
6
6
  },
7
7
  "implementationPlatform": "javascript",
8
8
  "certificationLevel": "known-answer-tested",
@@ -13,7 +13,7 @@
13
13
  "NTT": {
14
14
  "assetType": "algorithm",
15
15
  "algorithmProperties": {
16
- "primitive": "MATH"
16
+ "primitive": "other"
17
17
  },
18
18
  "implementationPlatform": "javascript",
19
19
  "certificationLevel": "known-answer-tested",
@@ -24,9 +24,9 @@
24
24
  "SHA-256": {
25
25
  "assetType": "algorithm",
26
26
  "algorithmProperties": {
27
- "primitive": "HASH"
27
+ "primitive": "hash"
28
28
  },
29
- "implementationPlatform": "javascript",
29
+ "implementationPlatform": "javascript, python",
30
30
  "certificationLevel": "known-answer-tested",
31
31
  "quantumSecurity": {
32
32
  "level": "weak"
@@ -35,7 +35,7 @@
35
35
  "SM2": {
36
36
  "assetType": "algorithm",
37
37
  "algorithmProperties": {
38
- "primitive": "SIGN"
38
+ "primitive": "signature"
39
39
  },
40
40
  "implementationPlatform": "javascript",
41
41
  "certificationLevel": "known-answer-tested",
@@ -46,7 +46,7 @@
46
46
  "P-256/ECDH": {
47
47
  "assetType": "algorithm",
48
48
  "algorithmProperties": {
49
- "primitive": "ECC"
49
+ "primitive": "key-agree"
50
50
  },
51
51
  "implementationPlatform": "javascript",
52
52
  "certificationLevel": "known-answer-tested",
@@ -57,7 +57,7 @@
57
57
  "Double-Ratchet": {
58
58
  "assetType": "algorithm",
59
59
  "algorithmProperties": {
60
- "primitive": "PROTO"
60
+ "primitive": "other"
61
61
  },
62
62
  "implementationPlatform": "javascript",
63
63
  "certificationLevel": "known-answer-tested",
@@ -68,7 +68,7 @@
68
68
  "SM3": {
69
69
  "assetType": "algorithm",
70
70
  "algorithmProperties": {
71
- "primitive": "HASH"
71
+ "primitive": "hash"
72
72
  },
73
73
  "implementationPlatform": "javascript",
74
74
  "certificationLevel": "known-answer-tested",
@@ -79,7 +79,7 @@
79
79
  "ML-DSA/fml-dsa": {
80
80
  "assetType": "algorithm",
81
81
  "algorithmProperties": {
82
- "primitive": "SIGN"
82
+ "primitive": "signature"
83
83
  },
84
84
  "implementationPlatform": "javascript",
85
85
  "certificationLevel": "known-answer-tested",
@@ -90,7 +90,7 @@
90
90
  "SM4": {
91
91
  "assetType": "algorithm",
92
92
  "algorithmProperties": {
93
- "primitive": "SYM"
93
+ "primitive": "block-cipher"
94
94
  },
95
95
  "implementationPlatform": "javascript",
96
96
  "certificationLevel": "known-answer-tested",
@@ -101,7 +101,7 @@
101
101
  "AES": {
102
102
  "assetType": "algorithm",
103
103
  "algorithmProperties": {
104
- "primitive": "SYM"
104
+ "primitive": "block-cipher"
105
105
  },
106
106
  "implementationPlatform": "javascript",
107
107
  "certificationLevel": "known-answer-tested",
@@ -112,7 +112,128 @@
112
112
  "SLH-DSA": {
113
113
  "assetType": "algorithm",
114
114
  "algorithmProperties": {
115
- "primitive": "SIGN"
115
+ "primitive": "signature"
116
+ },
117
+ "implementationPlatform": "javascript",
118
+ "certificationLevel": "known-answer-tested",
119
+ "quantumSecurity": {
120
+ "level": "safe"
121
+ }
122
+ },
123
+ "ChaCha20-Poly1305": {
124
+ "assetType": "algorithm",
125
+ "algorithmProperties": {
126
+ "primitive": "ae"
127
+ },
128
+ "implementationPlatform": "c",
129
+ "certificationLevel": "known-answer-tested",
130
+ "quantumSecurity": {
131
+ "level": "safe"
132
+ }
133
+ },
134
+ "X25519": {
135
+ "assetType": "algorithm",
136
+ "algorithmProperties": {
137
+ "primitive": "kem"
138
+ },
139
+ "implementationPlatform": "c",
140
+ "certificationLevel": "known-answer-tested",
141
+ "quantumSecurity": {
142
+ "level": "vulnerable"
143
+ }
144
+ },
145
+ "Ed25519": {
146
+ "assetType": "algorithm",
147
+ "algorithmProperties": {
148
+ "primitive": "signature"
149
+ },
150
+ "implementationPlatform": "c",
151
+ "certificationLevel": "known-answer-tested",
152
+ "quantumSecurity": {
153
+ "level": "vulnerable"
154
+ }
155
+ },
156
+ "Blake2b": {
157
+ "assetType": "algorithm",
158
+ "algorithmProperties": {
159
+ "primitive": "hash"
160
+ },
161
+ "implementationPlatform": "c",
162
+ "certificationLevel": "known-answer-tested",
163
+ "quantumSecurity": {
164
+ "level": "weak"
165
+ }
166
+ },
167
+ "Argon2i": {
168
+ "assetType": "algorithm",
169
+ "algorithmProperties": {
170
+ "primitive": "kdf"
171
+ },
172
+ "implementationPlatform": "c",
173
+ "certificationLevel": "known-answer-tested",
174
+ "quantumSecurity": {
175
+ "level": "safe"
176
+ }
177
+ },
178
+ "AES-GCM": {
179
+ "assetType": "algorithm",
180
+ "algorithmProperties": {
181
+ "primitive": "ae"
182
+ },
183
+ "implementationPlatform": "c",
184
+ "certificationLevel": "known-answer-tested",
185
+ "quantumSecurity": {
186
+ "level": "weak"
187
+ }
188
+ },
189
+ "SHA-512": {
190
+ "assetType": "algorithm",
191
+ "algorithmProperties": {
192
+ "primitive": "hash"
193
+ },
194
+ "implementationPlatform": "c",
195
+ "certificationLevel": "known-answer-tested",
196
+ "quantumSecurity": {
197
+ "level": "weak"
198
+ }
199
+ },
200
+ "ECDH": {
201
+ "assetType": "algorithm",
202
+ "algorithmProperties": {
203
+ "primitive": "kem"
204
+ },
205
+ "implementationPlatform": "c",
206
+ "certificationLevel": "known-answer-tested",
207
+ "quantumSecurity": {
208
+ "level": "vulnerable"
209
+ }
210
+ },
211
+ "RSA": {
212
+ "assetType": "algorithm",
213
+ "algorithmProperties": {
214
+ "primitive": "pke"
215
+ },
216
+ "implementationPlatform": "c",
217
+ "certificationLevel": "known-answer-tested",
218
+ "quantumSecurity": {
219
+ "level": "vulnerable"
220
+ }
221
+ },
222
+ "Keccak": {
223
+ "assetType": "algorithm",
224
+ "algorithmProperties": {
225
+ "primitive": "other"
226
+ },
227
+ "implementationPlatform": "javascript",
228
+ "certificationLevel": "known-answer-tested",
229
+ "quantumSecurity": {
230
+ "level": "safe"
231
+ }
232
+ },
233
+ "SHA3-256": {
234
+ "assetType": "algorithm",
235
+ "algorithmProperties": {
236
+ "primitive": "hash"
116
237
  },
117
238
  "implementationPlatform": "javascript",
118
239
  "certificationLevel": "known-answer-tested",
@@ -120,10 +241,10 @@
120
241
  "level": "safe"
121
242
  }
122
243
  },
123
- "TLA+": {
244
+ "SHA3-512": {
124
245
  "assetType": "algorithm",
125
246
  "algorithmProperties": {
126
- "primitive": "PROTO"
247
+ "primitive": "hash"
127
248
  },
128
249
  "implementationPlatform": "javascript",
129
250
  "certificationLevel": "known-answer-tested",
@@ -131,4 +252,4 @@
131
252
  "level": "safe"
132
253
  }
133
254
  }
134
- }
255
+ }
package/cbom-diff.js CHANGED
@@ -17,7 +17,7 @@
17
17
  * 0 — 无变更
18
18
  * 1 — 有信息性变更(算法属性升级等)
19
19
  * 2 — 有警告性变更(算法删除、新经典算法引用等)
20
- * 3 — 有严重变更(量子脆弱算法被引入)
20
+ * 3 — (reserved) 量子脆弱/弱算法引入检测(0.2.0 规划)
21
21
  */
22
22
 
23
23
  const { execSync } = require('child_process');
@@ -55,7 +55,12 @@ function loadCBOM(hash) {
55
55
  console.error(`✕ cbom-diff: file not found: ${filePath}`);
56
56
  process.exit(2);
57
57
  }
58
- return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
58
+ try {
59
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
60
+ } catch (e) {
61
+ console.error(`✕ cbom-diff: invalid JSON in ${filePath}: ${e.message}`);
62
+ process.exit(2);
63
+ }
59
64
  }
60
65
  // 2. Git mode
61
66
  if (gitMode) {
@@ -121,7 +126,7 @@ if (oldCBOM && newCBOM) {
121
126
  ref,
122
127
  name: c.name,
123
128
  type: assetType,
124
- risk: classifyRisk(assetType),
129
+ risk: classifyRisk(crypto),
125
130
  });
126
131
  }
127
132
  });
@@ -206,8 +211,8 @@ if (hasCriticalAdd) {
206
211
  // ════════════════════════════
207
212
  // 算法风险分类
208
213
  // ════════════════════════════
209
- function classifyRisk(assetType) {
210
- const type = (assetType || '').toLowerCase();
214
+ function classifyRisk(cryptoProps) {
215
+ const type = ((cryptoProps && cryptoProps.assetType) || '').toLowerCase();
211
216
  // PQC algorithms: safe additions
212
217
  if (/kem|sign|signature|post.quantum|pqc|mlkem|mldsa|slh/i.test(type)) return 'info';
213
218
  // Primitive/verification: neutral
@@ -216,6 +221,8 @@ function classifyRisk(assetType) {
216
221
  if (/ecc|ecdh|p-256|sm2|curve/i.test(type)) return 'warning';
217
222
  // Classic symmetric: info (still safe with large keys)
218
223
  if (/sym|sm4|aes|gcm/i.test(type)) return 'info';
224
+ // TODO(v0.2.0): add 'critical' exit code for quantum-vulnerable algorithms
225
+ // using cryptoProps.quantumSecurity?.level
219
226
  // Unknown: treat as warning
220
227
  return 'warning';
221
228
  }
package/cbom-scan.cjs CHANGED
@@ -11,6 +11,7 @@ const fs = require('fs');
11
11
  const path = require('path');
12
12
 
13
13
  const ALGO_META = JSON.parse(fs.readFileSync(path.join(__dirname, 'algo-metadata.json'), 'utf-8'));
14
+ const PKG = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf-8'));
14
15
 
15
16
  const NAME_ALIASES = {
16
17
  'ML-KEM-768': 'ML-KEM',
@@ -20,6 +21,7 @@ const NAME_ALIASES = {
20
21
  'ML-DSA-44': 'ML-DSA/fml-dsa',
21
22
  'ML-DSA-65': 'ML-DSA/fml-dsa',
22
23
  'ML-DSA-87': 'ML-DSA/fml-dsa',
24
+ 'Keccak-256': 'Keccak',
23
25
  };
24
26
 
25
27
  function lookupMeta(name) {
@@ -52,11 +54,32 @@ const DEFAULT_RULES = {
52
54
  { re: /\bsm2\b/gi, algs: ['SM2'] },
53
55
  { re: /\bsm3\b/gi, algs: ['SM3'] },
54
56
  { re: /\bsm4\b/gi, algs: ['SM4'] },
55
- ],
57
+ // === C/C++ 编译库(monocypher)===
58
+ { re: /\bcrypto_lock\b/g, algs: ['ChaCha20-Poly1305'] },
59
+ { re: /\bcrypto_unlock\b/g, algs: ['ChaCha20-Poly1305'] },
60
+ { re: /\bcrypto_x25519/g, algs: ['X25519'] },
61
+ { re: /\bcrypto_sign/g, algs: ['Ed25519'] },
62
+ { re: /\bcrypto_check\b/g, algs: ['Ed25519'] },
63
+ { re: /\bcrypto_blake2b/g, algs: ['Blake2b'] },
64
+ { re: /\bcrypto_argon2i\b/g, algs: ['Argon2i'] },
65
+ { re: /\bcrypto_key_exchange\b/g, algs: ['X25519'] },
66
+ // === C/C++ 通用(mbedtls)===
67
+ { re: /\bmbedtls_sha256/g, algs: ['SHA-256'] },
68
+ { re: /\bmbedtls_sha512/g, algs: ['SHA-512'] },
69
+ { re: /\bmbedtls_aes/g, algs: ['AES'] },
70
+ { re: /\bmbedtls_gcm/g, algs: ['AES-GCM'] },
71
+ { re: /\bmbedtls_ecdh/g, algs: ['ECDH'] },
72
+ { re: /\bmbedtls_rsa/g, algs: ['RSA'] },
73
+
74
+ // Python hashlib (MAVLink2 signing, pymavlink sample)
75
+ { re: /import\s+hashlib/g, algs: ['SHA-256'] },
76
+ { re: /hashlib\.sha256\(/g, algs: ['SHA-256'] },
77
+ { re: /hashlib\.new\(\s*["']sha256["']/gi, algs: ['SHA-256'] },
78
+ ],
56
79
  };
57
80
 
58
81
  const SKIP_DIRS = new Set(['node_modules', 'dist', 'build', 'coverage', '.git', '.cache']);
59
- const SCAN_EXT = /\.(cjs|mjs|js|ts|tsx|jsx)$/;
82
+ const SCAN_EXT = /\.(cjs|mjs|js|ts|tsx|jsx|cpp|c|h|hpp|py)$/;
60
83
  const MAX_OCC_PER_ALGO = 50;
61
84
 
62
85
  function loadPackageDeps(dir) {
@@ -127,7 +150,7 @@ function toCycloneDX(algorithms) {
127
150
  version: 1,
128
151
  metadata: {
129
152
  timestamp: new Date().toISOString(),
130
- tools: [{ name: 'cbom-scan', version: '0.1.0', vendor: 'FIBEMATE' }],
153
+ tools: [{ name: 'cbom-scan', version: PKG.version, vendor: 'FIBEMATE' }],
131
154
  },
132
155
  components: [...algorithms.keys()].sort().map(name => {
133
156
  const meta = lookupMeta(name);
@@ -136,7 +159,20 @@ function toCycloneDX(algorithms) {
136
159
  name,
137
160
  'bom-ref': `crypto:${name}`,
138
161
  };
139
- if (meta) comp.cryptoProperties = meta;
162
+ if (meta) {
163
+ comp.cryptoProperties = {
164
+ assetType: meta.assetType,
165
+ algorithmProperties: meta.algorithmProperties,
166
+ };
167
+ const props = [];
168
+ if (meta.implementationPlatform)
169
+ props.push({ name: 'fibemate:implementationLanguages', value: meta.implementationPlatform });
170
+ if (meta.certificationLevel)
171
+ props.push({ name: 'fibemate:testingStatus', value: meta.certificationLevel });
172
+ if (meta.quantumSecurity?.level)
173
+ props.push({ name: 'fibemate:quantumSecurity:level', value: meta.quantumSecurity.level });
174
+ if (props.length) comp.properties = props;
175
+ }
140
176
  const occ = algorithms.get(name);
141
177
  if (occ && occ.length) comp.evidence = { occurrences: occ };
142
178
  return comp;
@@ -146,7 +182,16 @@ function toCycloneDX(algorithms) {
146
182
 
147
183
  function main() {
148
184
  const args = process.argv.slice(2);
149
- const dir = args.includes('--dir') ? args[args.indexOf('--dir') + 1] : process.cwd();
185
+ const dirFlag = args.indexOf('--dir');
186
+ let dir = process.cwd();
187
+ if (dirFlag !== -1) {
188
+ const v = args[dirFlag + 1];
189
+ if (!v || v.startsWith('--')) {
190
+ console.error('usage: cbom-scan [--dir <path>] [--out <file>]');
191
+ process.exit(2);
192
+ }
193
+ dir = v;
194
+ }
150
195
  const outPath = args.includes('--out') ? args[args.indexOf('--out') + 1] : null;
151
196
 
152
197
  const deps = loadPackageDeps(dir);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cbom-tools",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Crypto Bill of Materials — scan, diff, report (CycloneDX 1.6 CBOM)",
5
5
  "license": "Apache-2.0",
6
6
  "author": "刘天赫 <research@fibemate.net>",
@@ -14,5 +14,12 @@
14
14
  "algo-metadata.json",
15
15
  "README.md",
16
16
  "LICENSE"
17
- ]
18
- }
17
+ ],
18
+ "scripts": {
19
+ "test": "node --test"
20
+ },
21
+ "devDependencies": {
22
+ "ajv": "^8.20.0",
23
+ "ajv-formats": "^3.0.1"
24
+ }
25
+ }