{"record":{"id":"e2a50ad4ed8c0a54","repo":"grafana/k6","slug":"key-derivation-not-implemented-for-algorithm-s","errorCode":null,"errorMessage":"key derivation not implemented for algorithm %s","messagePattern":"key derivation not implemented for algorithm (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/webcrypto/key.go","lineNumber":230,"sourceCode":"type KeyDeriver interface {\n\tDeriveKey(\n\t\tprivateKey *CryptoKey,\n\t\tki KeyImporter,\n\t\tkgl KeyGetLengther,\n\t\tkeyUsages []CryptoKeyUsage,\n\t\textractable bool,\n\t) (*CryptoKey, error)\n}\n\nfunc newKeyDeriver(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (KeyDeriver, error) {\n\tvar kd KeyDeriver\n\tvar err error\n\n\tswitch normalized.Name {\n\tcase PBKDF2:\n\t\tkd, err = newPBKDF2DeriveParams(rt, normalized, params)\n\tdefault:\n\t\treturn nil, errors.New(\"key derivation not implemented for algorithm \" + normalized.Name)\n\t}\n\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn kd, nil\n}\n\n// KeyGetLengther is the interface implemented by the parameters used to\n// get the key length of cryptographic keys\ntype KeyGetLengther interface {\n\tGetKeyLength() int\n}\n\nfunc newKeyGetLengther(rt *sobek.Runtime, normalized Algorithm, params sobek.Value) (KeyGetLengther, error) {\n\tvar kgi KeyGetLengther\n\tvar err error","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/grafana/k6/blob/01ffac6f245854c1b8adc6a69857c76a15f90022/internal/js/modules/k6/webcrypto/key.go#L212-L248","documentation":"Returned when crypto.subtle.deriveKey is called with a base algorithm k6 does not implement. newKeyDeriver (internal/js/modules/k6/webcrypto/key.go:230) supports only PBKDF2, so any other normalized algorithm name — ECDH, HKDF, or a misspelling — hits the default branch and the deriveKey promise rejects with 'key derivation not implemented for algorithm <name>'. Note that deriveBits has its own deriver and does support ECDH, so deriveKey is the narrower API.","triggerScenarios":"crypto.subtle.deriveKey({ name: 'ECDH', public: peerPublic }, myPrivate, { name: 'AES-GCM', length: 256 }, false, ['encrypt']) or crypto.subtle.deriveKey({ name: 'HKDF', hash: 'SHA-256', salt, info }, ikm, ...) — both reject with this message. A typo like 'PBKDF' also lands here because normalization must yield exactly 'PBKDF2'.","commonSituations":"Porting browser or Node.js WebCrypto code that supports ECDH/HKDF deriveKey and assuming k6 covers the same surface; password-based scripts where the algorithm string was changed; scripts written against xk6-webcrypto versions older than the integrated module.","solutions":["For password-based derivation, switch to PBKDF2: crypto.subtle.deriveKey({ name: 'PBKDF2', salt, iterations: 100000, hash: 'SHA-256' }, passwordKey, derived, extractable, usages)","For ECDH or HKDF material, replace deriveKey with deriveBits followed by importKey: const bits = await crypto.subtle.deriveBits(alg, baseKey, 256); const key = await crypto.subtle.importKey('raw', bits, { name: 'AES-GCM', length: 256 }, false, ['encrypt'])","Check the algorithm name spelling — it must normalize to exactly 'PBKDF2'","Track the grafana/xk6-webcrypto repository for ECDH/HKDF deriveKey support and upgrade k6 when it lands"],"exampleFix":"// before (ECDH deriveKey — unsupported)\nconst aesKey = await crypto.subtle.deriveKey(\n  { name: 'ECDH', public: peerPublic }, myPrivate,\n  { name: 'AES-GCM', length: 256 }, false, ['encrypt']);\n\n// after (deriveBits + importKey)\nconst bits = await crypto.subtle.deriveBits(\n  { name: 'ECDH', public: peerPublic }, myPrivate, 256);\nconst aesKey = await crypto.subtle.importKey(\n  'raw', bits, { name: 'AES-GCM', length: 256 }, false, ['encrypt']);","handlingStrategy":"fallback","validationCode":"const DERIVE_KEY_BASE_ALGORITHMS = new Set(['PBKDF2']);\n\nasync function deriveKeyCompat(algorithm, baseKey, derivedKeyType, extractable, usages) {\n  if (DERIVE_KEY_BASE_ALGORITHMS.has(algorithm.name)) {\n    return crypto.subtle.deriveKey(algorithm, baseKey, derivedKeyType, extractable, usages);\n  }\n  // k6 deriveKey only supports PBKDF2 — fall back to deriveBits + importKey\n  const bits = await crypto.subtle.deriveBits(algorithm, baseKey, derivedKeyType.length);\n  return crypto.subtle.importKey('raw', bits, derivedKeyType, extractable, usages);\n}","typeGuard":null,"tryCatchPattern":"try {\n  key = await crypto.subtle.deriveKey(alg, baseKey, derived, extractable, usages);\n} catch (err) {\n  if (/key derivation not implemented/.test(String(err))) {\n    const bits = await crypto.subtle.deriveBits(alg, baseKey, derived.length);\n    key = await crypto.subtle.importKey('raw', bits, derived, extractable, usages);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Pin expectations to k6's coverage: deriveKey supports only PBKDF2 today","Write new derivation code as deriveBits + importKey — it works for PBKDF2, ECDH and ports cleanly","Watch the grafana/xk6-webcrypto roadmap before relying on ECDH/HKDF deriveKey"],"tags":["webcrypto","derivekey","pbkdf2","hkdf","ecdh","unsupported-algorithm"],"backgroundTag":"unsupported-crypto-algorithm","analyzedSha":"01ffac6f245854c1b8adc6a69857c76a15f90022","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}