fix: set limit to passsword kdf iterations on cloudflare workers

This commit is contained in:
Tienson Qin
2025-12-30 22:40:43 +08:00
parent e5964202d8
commit 3b14336474
2 changed files with 35 additions and 31 deletions

View File

@@ -120,10 +120,11 @@
digest (.digest js/crypto.subtle "SHA-256" data)]
(to-hex digest)))
(def password-kdf-iterations 210000)
(def password-kdf-max-iterations 90000)
(def password-kdf-iterations 90000)
(defn bytes->base64url [bytes]
(let [binary (apply str (map #(js/String.fromCharCode %) (array-seq bytes)))
(defn bytes->base64url [data]
(let [binary (apply str (map #(js/String.fromCharCode %) (array-seq data)))
b64 (js/btoa binary)]
(-> b64
(string/replace #"\+" "-")
@@ -139,18 +140,19 @@
#js {:name "PBKDF2"}
false
#js ["deriveBits"])
iterations (min password-kdf-iterations password-kdf-max-iterations)
derived (.deriveBits js/crypto.subtle
#js {:name "PBKDF2"
:hash "SHA-256"
:salt salt
:iterations password-kdf-iterations}
:iterations iterations}
crypto-key
256)
derived-bytes (js/Uint8Array. derived)
salt-encoded (bytes->base64url salt)
hash-encoded (bytes->base64url derived-bytes)]
(str "pbkdf2$sha256$"
password-kdf-iterations
iterations
"$"
salt-encoded
"$"
@@ -176,32 +178,34 @@
(= "pbkdf2" (nth parts 0))
(= "sha256" (nth parts 1)))
false
(js-await [iterations (js/parseInt (nth parts 2))
salt (base64url->uint8array (nth parts 3))
expected (base64url->uint8array (nth parts 4))
crypto-key (.importKey js/crypto.subtle
"raw"
(.encode text-encoder password)
#js {:name "PBKDF2"}
false
#js ["deriveBits"])
derived (.deriveBits js/crypto.subtle
#js {:name "PBKDF2"
:hash "SHA-256"
:salt salt
:iterations iterations}
crypto-key
(* 8 (.-length expected)))
derived-bytes (js/Uint8Array. derived)]
(if (not= (.-length derived-bytes) (.-length expected))
(js-await [iterations (js/parseInt (nth parts 2))]
(if (> iterations password-kdf-max-iterations)
false
(let [mismatch (reduce (fn [acc idx]
(bit-or acc
(bit-xor (aget derived-bytes idx)
(aget expected idx))))
0
(range (.-length expected)))]
(zero? mismatch)))))))
(js-await [salt (base64url->uint8array (nth parts 3))
expected (base64url->uint8array (nth parts 4))
crypto-key (.importKey js/crypto.subtle
"raw"
(.encode text-encoder password)
#js {:name "PBKDF2"}
false
#js ["deriveBits"])
derived (.deriveBits js/crypto.subtle
#js {:name "PBKDF2"
:hash "SHA-256"
:salt salt
:iterations iterations}
crypto-key
(* 8 (.-length expected)))
derived-bytes (js/Uint8Array. derived)]
(if (not= (.-length derived-bytes) (.-length expected))
false
(let [mismatch (reduce (fn [acc idx]
(bit-or acc
(bit-xor (aget derived-bytes idx)
(aget expected idx))))
0
(range (.-length expected)))]
(zero? mismatch)))))))))
(defn hmac-sha256 [key message]
(js-await [crypto-key (.importKey js/crypto.subtle

View File

@@ -10,7 +10,7 @@
[logseq.publish.model :as publish-model]))
;; Timestamp in milliseconds used for cache busting static assets.
(defonce version 1767100530314)
(defonce version 1767105766059)
(def ref-regex
(js/RegExp. "\\[\\[([0-9a-fA-F-]{36})\\]\\]|\\(\\(([0-9a-fA-F-]{36})\\)\\)" "g"))