Password

io.eezo.auth.Password$package.Password
object Password

Attributes

Source
Password.scala
Graph
Supertypes
class Object
trait Matchable
class Any
Self type
Password.type

Members list

Type members

Classlikes

final class Plain

What a login form decodes to: the text as typed, alive only until it is hashed or verified.

What a login form decodes to: the text as typed, alive only until it is hashed or verified.

A class whose toString redacts, for the reason Secret's is one: the failure this type exists to prevent is the plain text reaching a log, and a log line is written by interpolating whatever is in scope. An opaque type over String cannot defend against that, since toString is a member of Any and an extension method never wins against one, so the redaction would be a comment rather than a guarantee.

There is no way back to the text from outside this module, which is what makes storing one impossible rather than merely discouraged.

Attributes

Companion
object
Source
Password.scala
Supertypes
class Object
trait Matchable
class Any
object Plain

Attributes

Companion
class
Source
Password.scala
Supertypes
class Object
trait Matchable
class Any
Self type
Plain.type

Value members

Concrete methods

def hash(plain: Plain): Password

The hash of a plain text, at Strength, under a fresh salt.

The hash of a plain text, at Strength, under a fresh salt.

Attributes

Source
Password.scala
def stored(hash: String): Password

A hash already made, as read out of a row or written into a seed script. Takes the string at its word: what algorithm and cost it names is what verify will use, which is what lets a test seed a cheap hash and an application store an expensive one.

A hash already made, as read out of a row or written into a seed script. Takes the string at its word: what algorithm and cost it names is what verify will use, which is what lets a test seed a cheap hash and an application store an expensive one.

Attributes

Source
Password.scala

Givens

Givens

The stored hash as a form field.

The stored hash as a form field.

show is empty for every value, a real hash included, so no page ever paints one: a hash is not a secret from the database, but it is an offline attack for anyone who reads the page it was rendered into. read hashes, which is what puts the hashing between the browser and the case class rather than in a handler somebody has to remember to write.

Attributes

Source
Password.scala

Extensions

Extensions

extension (password: Password)
def value: String

The hash as text, for the Column[Password] an application writes beside its model.

The hash as text, for the Column[Password] an application writes beside its model.

Attributes

Source
Password.scala
def verify(plain: Plain): Boolean

Whether plain is the text this hash was made from.

Whether plain is the text this hash was made from.

Reads the algorithm and cost out of the stored string rather than assuming Strength, so a hash written before the cost moved still verifies. Nothing rehashes on a successful login yet: that needs a second cost in the wild to be worth the write on every sign in.

Until it does, a moved Strength costs a little of what dummy buys. A row still at the old cost verifies at a different speed than the dummy built at the new one, so the two branches stop matching for those rows. What that leaks is "this account is older than the cost change", not "this email exists", since every row written since moves at the same speed as a miss, and it is accepted at that price.

A stored string that is not a bcrypt hash throws rather than answering false. That is a column holding something eezo did not write, and it is worth a 500 on one login: answering false would read as a wrong password forever, and nothing anywhere would say why.

Attributes

Source
Password.scala