// Detectorul Go: importurile pachetelor crypto/* (in Go un import nefolosit nu compileaza, deci // importul e o dovada de folosire, cu exceptia importului gol "_"), apelurile cu parametri si // configuratia tls.Config. import { argumente, imparteArgumente, escapeRe } from './context.mjs'; import { grupTls, jws } from './catalog.mjs'; const PACHETE = { 'crypto/rsa': { grup: 'RSA' }, 'crypto/dsa': { grup: 'DSA' }, 'crypto/ecdsa': { grup: 'ECDSA' }, 'crypto/elliptic': { grup: 'EC' }, 'crypto/ecdh': { grup: 'ECDH' }, 'crypto/ed25519': { grup: 'EDDSA', nume: 'Ed25519' }, 'golang.org/x/crypto/ed25519': { grup: 'EDDSA', nume: 'Ed25519' }, 'golang.org/x/crypto/curve25519': { grup: 'XDH', nume: 'X25519' }, 'crypto/md5': { grup: 'HASH', hash: 'MD5' }, 'crypto/sha1': { grup: 'HASH', hash: 'SHA1' }, 'golang.org/x/crypto/md4': { grup: 'HASH', hash: 'MD4' }, 'golang.org/x/crypto/ripemd160': { grup: 'HASH', hash: 'RIPEMD160' }, 'crypto/sha256': { grup: 'HASH', hash: 'SHA256' }, 'crypto/sha512': { grup: 'HASH', hash: 'SHA512' }, 'crypto/sha3': { grup: 'HASH', hash: 'SHA3-256' }, 'golang.org/x/crypto/sha3': { grup: 'HASH', hash: 'SHA3-256' }, 'crypto/des': { grup: 'CIPHER', nume: 'DES' }, 'crypto/rc4': { grup: 'CIPHER', nume: 'RC4' }, 'golang.org/x/crypto/blowfish': { grup: 'CIPHER', nume: 'Blowfish' }, 'crypto/aes': { grup: 'CIPHER', nume: 'AES' }, 'golang.org/x/crypto/chacha20poly1305': { grup: 'CIPHER', nume: 'ChaCha20-Poly1305' }, 'crypto/mlkem': { grup: 'MLKEM' }, 'golang.org/x/crypto/bcrypt': { grup: 'KDF', nume: 'bcrypt' }, 'golang.org/x/crypto/argon2': { grup: 'KDF', nume: 'Argon2' }, 'golang.org/x/crypto/scrypt': { grup: 'KDF', nume: 'scrypt' }, 'golang.org/x/crypto/pbkdf2': { grup: 'KDF', nume: 'PBKDF2' }, 'crypto/pbkdf2': { grup: 'KDF', nume: 'PBKDF2' }, 'crypto/hkdf': { grup: 'KDF', nume: 'HKDF' }, 'golang.org/x/crypto/ssh': { grup: 'SSH' }, 'github.com/ethereum/go-ethereum/crypto': { grup: 'SECP256K1', nota: 'go-ethereum crypto package: accounts and signatures are secp256k1 ECDSA.' }, 'github.com/ethereum/go-ethereum/crypto/secp256k1': { grup: 'SECP256K1' }, 'github.com/decred/dcrd/dcrec/secp256k1': { grup: 'SECP256K1' }, 'github.com/btcsuite/btcd/btcec': { grup: 'SECP256K1' }, 'github.com/cloudflare/circl/sign/ed25519': { grup: 'EDDSA', nume: 'Ed25519' }, 'github.com/cloudflare/circl/sign/slhdsa': { grup: 'SLHDSA' }, 'github.com/cloudflare/circl/kem/hybrid': { grup: 'HYBRID-KEX', nume: 'hybrid KEM (circl)' }, }; function pachetActiv(cale) { if (PACHETE[cale]) return PACHETE[cale]; let m; if ((m = /^github\.com\/cloudflare\/circl\/sign\/mldsa\/mldsa(44|65|87)$/.exec(cale))) return { grup: 'MLDSA', param: m[1] }; if ((m = /^github\.com\/cloudflare\/circl\/kem\/mlkem\/mlkem(512|768|1024)$/.exec(cale))) return { grup: 'MLKEM', param: m[1] }; if ((m = /^github\.com\/cloudflare\/circl\/sign\/dilithium\/mode(2|3|5)$/.exec(cale))) return { grup: 'PREPQ', nume: `Dilithium${m[1]}`, primitiv: 'signature' }; if ((m = /^github\.com\/cloudflare\/circl\/kem\/kyber\/kyber(512|768|1024)$/.exec(cale))) return { grup: 'PREPQ', nume: `Kyber${m[1]}`, primitiv: 'kem' }; if (/^github\.com\/btcsuite\/btcd\/btcec(\/v\d+)?$/.test(cale) || /^github\.com\/decred\/dcrd\/dcrec\/secp256k1(\/v\d+)?$/.test(cale)) return { grup: 'SECP256K1' }; if (/^github\.com\/golang-jwt\/jwt(\/v\d+)?$/.test(cale)) return { grup: 'LIB-MULTI', nume: 'golang-jwt', motiv: 'Imports golang-jwt; no SigningMethod reference recognized in this file.' }; if (cale === 'crypto/tls') return { grup: 'TLS', param: 'negotiated', motiv: 'crypto/tls with default settings' }; return null; } export function importuriGo(ctx) { const r = []; const c = ctx.code; const adauga = (alias, cale, pos) => r.push({ alias: alias || cale.split('/').filter((x) => !/^v\d+$/.test(x)).pop(), gol: alias === '_', cale, pos }); for (const m of c.matchAll(/(^|\n)[ \t]*import[ \t]+(?:([\w.]+)[ \t]+)?("([^"\n]+)")/g)) { adauga(m[2], m[4], m.index + m[0].indexOf(m[3])); } for (const m of c.matchAll(/(^|\n)[ \t]*import[ \t]*\(([^)]*)\)/g)) { const bloc = m[2]; const baza = m.index + m[0].indexOf('(') + 1; for (const x of bloc.matchAll(/(?:^|\n)[ \t]*(?:([\w.]+)[ \t]+)?("([^"\n]+)")/g)) { adauga(x[1], x[3], baza + x.index + x[0].indexOf(x[2])); } } return r; } export function detecteazaGo(ctx) { const imp = importuriGo(ctx); const alias = (cale) => { const i = imp.find((x) => x.cale === cale && !x.gol); return i ? escapeRe(i.alias) : null; }; const apel = (cale, functii) => { const a = alias(cale); if (!a) return []; return ctx.potriviri(new RegExp(`(? { const dupa = ctx.code.slice(m.index + m[0].length); const p = /^\s*\(/.exec(dupa); if (!p) return { text: '', parti: [] }; const a = argumente(ctx, m.index + m[0].length + p[0].length); return { ...a, parti: imparteArgumente(ctx, a.start, a.end) }; }; const pachetHash = { md5: 'MD5', sha1: 'SHA1', sha256: 'SHA256', sha512: 'SHA512', sha3: 'SHA3-256' }; // apelurile cu parametri for (const m of apel('crypto/rsa', 'GenerateKey|GenerateMultiPrimeKey')) { const a = args(m); const ult = a.parti[a.parti.length - 1]; ctx.adauga(m.index, `rsa.${m[1]}`, 'call', { grup: 'RSA', param: ult && /^\d+$/.test(ult.text) ? ult.text : undefined, functii: ['keygen'] }, { bucata: m[0] + (ult ? ult.text : '') }); } for (const m of apel('crypto/rsa', 'EncryptOAEP|DecryptOAEP|EncryptPKCS1v15|DecryptPKCS1v15|SignPSS|SignPKCS1v15|VerifyPSS|VerifyPKCS1v15')) { const a = args(m); const h = /\bcrypto\s*\.\s*(MD5|SHA1|SHA224|SHA256|SHA384|SHA512)\b/.exec(a.text); const sig = /^(Sign|Verify)/.test(m[1]); ctx.adauga(m.index, `rsa.${m[1]}`, 'call', { grup: 'RSA', primitiv: sig ? 'signature' : 'pke', padding: /OAEP/.test(m[1]) ? 'oaep' : /PKCS1v15/.test(m[1]) ? 'pkcs1v15' : 'other', hash: h ? h[1] : undefined, functii: [/^Sign/.test(m[1]) ? 'sign' : /^Verify/.test(m[1]) ? 'verify' : /^Encrypt/.test(m[1]) ? 'encrypt' : 'decrypt'] }, { bucata: m[0] }); } const ell = alias('crypto/elliptic'); const consumate = new Set(); for (const m of apel('crypto/ecdsa', 'GenerateKey|Sign|SignASN1|Verify|VerifyASN1')) { const a = args(m); let curba; if (ell && m[1] === 'GenerateKey') { const k = new RegExp(`${ell}\\s*\\.\\s*(P224|P256|P384|P521)\\s*\\(`).exec(a.text); if (k) { curba = k[1]; consumate.add(a.start + k.index); } } ctx.adauga(m.index, `ecdsa.${m[1]}`, 'call', { grup: 'ECDSA', curba, functii: [m[1] === 'GenerateKey' ? 'keygen' : /^Sign/.test(m[1]) ? 'sign' : 'verify'] }, { bucata: m[0] + (curba ? ` ${curba}` : '') }); } for (const m of apel('crypto/elliptic', 'P224|P256|P384|P521')) { if (consumate.has(m.index)) continue; ctx.adauga(m.index, `elliptic.${m[1]}`, 'call', { grup: 'EC', curba: m[1] }, { bucata: m[0] }); } for (const m of apel('crypto/ecdh', 'X25519|P256|P384|P521')) { ctx.adauga(m.index, `ecdh.${m[1]}`, 'call', m[1] === 'X25519' ? { grup: 'XDH', nume: 'X25519', functii: ['keygen'] } : { grup: 'ECDH', curba: m[1], functii: ['keygen'] }, { bucata: m[0] }); } for (const cale of ['crypto/ed25519', 'golang.org/x/crypto/ed25519']) { for (const m of apel(cale, 'GenerateKey|Sign|Verify|NewKeyFromSeed|VerifyWithOptions')) { ctx.adauga(m.index, `ed25519.${m[1]}`, 'call', { grup: 'EDDSA', nume: 'Ed25519', functii: [m[1] === 'Sign' ? 'sign' : /^Verify/.test(m[1]) ? 'verify' : 'keygen'] }, { bucata: m[0] }); } } for (const [cale, fn] of [['crypto/md5', 'New|Sum'], ['crypto/sha1', 'New|Sum'], ['crypto/sha256', 'New|New224|Sum256|Sum224'], ['crypto/sha512', 'New|New384|Sum512|Sum384|New512_256'], ['crypto/sha3', 'New256|New384|New512|Sum256|Sum384|Sum512|NewSHAKE128|NewSHAKE256'], ['golang.org/x/crypto/sha3', 'New256|New384|New512|Sum256|Sum384|Sum512|NewLegacyKeccak256']]) { for (const m of apel(cale, fn)) { const dupa = ctx.code.slice(m.index + m[0].length, m.index + m[0].length + 3); if (!/^\s*\(/.test(dupa)) continue; // referinta de functie (de ex. hmac.New(sha1.New, ...)) se raporteaza la hmac const pk = cale.split('/').pop(); let h = pachetHash[pk]; if (/224/.test(m[1])) h = 'SHA224'; if (/384/.test(m[1])) h = pk === 'sha3' ? 'SHA3-384' : 'SHA384'; if (/512_256/.test(m[1])) h = 'SHA512/256'; if (pk === 'sha3' && /512/.test(m[1])) h = 'SHA3-512'; if (/SHAKE128/.test(m[1])) h = 'SHAKE128'; if (/SHAKE256/.test(m[1])) h = 'SHAKE256'; if (/Keccak/.test(m[1])) h = 'KECCAK256'; ctx.adauga(m.index, `${pk}.${m[1]}`, 'call', { grup: 'HASH', hash: h, functii: ['digest'] }, { bucata: m[0] }); } } for (const m of apel('crypto/hmac', 'New')) { const a = args(m); const k = /^(\w+)\s*\.\s*New(\d*)\b/.exec(a.parti[0] ? a.parti[0].text : ''); const pk = k ? imp.find((x) => x.alias === k[1]) : null; const baza = pk ? pachetHash[pk.cale.split('/').pop()] : null; const h = baza ? (k[2] === '384' ? 'SHA384' : k[2] === '224' ? 'SHA224' : baza) : null; ctx.adauga(m.index, 'hmac.New', 'call', h ? { grup: 'MAC', hash: h, functii: ['tag'] } : { grup: 'UNKNOWN', motiv: `hmac.New hash "${a.parti[0] ? a.parti[0].text : '?'}" cannot be resolved statically.` }, { bucata: m[0] + (a.parti[0] ? `(${a.parti[0].text}` : '') }); } for (const m of apel('crypto/des', 'NewCipher|NewTripleDESCipher')) { ctx.adauga(m.index, `des.${m[1]}`, 'call', { grup: 'CIPHER', nume: m[1] === 'NewCipher' ? 'DES' : '3DES', functii: ['encrypt'] }, { bucata: m[0] }); } for (const m of apel('crypto/rc4', 'NewCipher')) ctx.adauga(m.index, 'rc4.NewCipher', 'call', { grup: 'CIPHER', nume: 'RC4', functii: ['encrypt'] }, { bucata: m[0] }); for (const m of apel('crypto/aes', 'NewCipher')) ctx.adauga(m.index, 'aes.NewCipher', 'call', { grup: 'CIPHER', nume: 'AES', functii: ['encrypt'] }, { bucata: m[0] }); for (const m of apel('crypto/mlkem', 'GenerateKey768|GenerateKey1024|NewEncapsulationKey768|NewEncapsulationKey1024|NewDecapsulationKey768|NewDecapsulationKey1024')) { ctx.adauga(m.index, `mlkem.${m[1]}`, 'call', { grup: 'MLKEM', param: /1024/.test(m[1]) ? '1024' : '768', functii: [/^Generate/.test(m[1]) ? 'keygen' : 'other'] }, { bucata: m[0] }); } const eth = alias('github.com/ethereum/go-ethereum/crypto'); if (eth) { for (const m of ctx.potriviri(new RegExp(`(? /^github\.com\/golang-jwt\/jwt(\/v\d+)?$/.test(x.cale)); if (jwtI) { for (const m of ctx.potriviri(new RegExp(`(?