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 +13 -0
- package/algo-metadata.json +136 -15
- package/cbom-diff.js +12 -5
- package/cbom-scan.cjs +50 -5
- package/package.json +10 -3
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
|
|
package/algo-metadata.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"ML-KEM": {
|
|
3
3
|
"assetType": "algorithm",
|
|
4
4
|
"algorithmProperties": {
|
|
5
|
-
"primitive": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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": "
|
|
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
|
-
"
|
|
244
|
+
"SHA3-512": {
|
|
124
245
|
"assetType": "algorithm",
|
|
125
246
|
"algorithmProperties": {
|
|
126
|
-
"primitive": "
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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:
|
|
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)
|
|
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
|
|
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.
|
|
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
|
+
}
|