gitoriaLog in with ident

gitoria

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commit4a2d71254a2d7125initial commitmre4a2d7125/plugins/crypto/server.hl

3.3 KB

  1. \* hl:crypto — passwords first. Native realm wrapper (see server.js for the JS twin).
  2. The whole surface is six calls, and four of them exist to serve the first two.
  3. What this plugin is FOR is that an application never stores a password: it
  4. stores the answer to "could this password have produced that", and the answer
  5. carries its own algorithm and cost so it stays readable when both change.
  6. hash(password, options) the stored value — a PHC string
  7. verify(password, stored) true / false, in constant time
  8. parsePhc(stored) what a stored value says about itself
  9. kdf() which algorithm THIS host hashes with
  10. sha256(data) content hashing (fast on purpose — not for passwords)
  11. randomBytes(n, encoding) n bytes from the kernel CSPRNG
  12. The realm is SERVER (plugin.json). A password never crosses to the client, so
  13. importing this file is also a declaration about where the importing code runs. *\
  14. \* Hash a password for storage. Returns a self-describing PHC string:
  15. $argon2id$v=19$m=32768,t=2,p=1$<salt>$<hash>
  16. $scrypt$ln=15,r=8,p=1$<salt>$<hash>
  17. Every call salts freshly, so hashing the same password twice gives two
  18. different strings and both verify.
  19. `options` is optional: { cost = 15; kdf = "argon2id" }
  20. cost base-2 log of the working memory in KiB — 15 is 32 MiB, the default.
  21. CAPPED to 10..17 (1 MiB .. 128 MiB); the string records what was
  22. actually used, so asking for 999 and reading the result back is how
  23. you see the cap rather than being told about it.
  24. kdf force an algorithm instead of taking the host's best one. Normally
  25. unnecessary: `hash` picks argon2id when the system libcrypto has it
  26. (OpenSSL >= 3.2) and scrypt otherwise, and `verify` reads both. *\
  27. hash(password, options) {
  28. return __native("crypto.hash", password, options)
  29. }
  30. \* Check a password against a stored PHC string. The comparison is constant-time
  31. and the answer is a plain boolean: a wrong password, a truncated string, a
  32. flipped character and a string that is not PHC at all are all `false`. A
  33. stored string whose ALGORITHM this host cannot compute is a loud error
  34. instead, because answering `false` to that would read as "wrong password". *\
  35. verify(password, stored) {
  36. return __native("crypto.verify", password, stored)
  37. }
  38. \* Read a stored string without the password:
  39. { kdf = "argon2id"; version = 19; params = { m; t; p }; saltLen; hashLen }
  40. { kdf = "scrypt"; version = null; params = { ln; r; p }; saltLen; hashLen }
  41. `null` when the string is not a PHC string this plugin understands — which is
  42. also the cheapest way to spot a store that was never migrated. *\
  43. parsePhc(stored) {
  44. return __native("crypto.parse", stored)
  45. }
  46. \* Which algorithm `hash()` writes with on this host. Reporting only — nothing
  47. needs to branch on it, because every stored string names its own. *\
  48. kdf() {
  49. return __native("crypto.kdf")
  50. }
  51. \* SHA-256 of a string, as 64 lowercase hex characters. Content hashing: fast by
  52. design, and therefore exactly the wrong tool for a password. *\
  53. sha256(data) {
  54. return __native("crypto.sha256", data)
  55. }
  56. \* n random bytes from the kernel CSPRNG, rendered as "hex" (the default) or
  57. "base64". n is 1..1024. Suitable for session ids, one-time tokens and nonces. *\
  58. randomBytes(n, encoding) {
  59. return __native("crypto.random_bytes", n, encoding)
  60. }

Branches

Latest commits

  • 4a2d7125initial commitmre