Search code examples
kotlinkotlin-exposedargon2-ffi

Encoding a password with argon2 and save on PostgreSQL


I'm trying to encox user password to save in postgresql database. Using kotlin and argon2. I did the functions and in the tests, it works perfectly. But when I save it in the database, and I try to compare the passwords, it always gives an error. Could anyone help?

I created the following functions:

private val argon2 = Argon2Factory.create(Argon2Factory.Argon2Types.ARGON2id, 32, 64)

fun String.encode(): String = argon2.hash(3, 64 * 1024, 1, this.toCharArray())

fun String.checkEncoding(hash: String): Boolean = argon2.verify(hash, this.toCharArray())

and in tests, everything works perfectly

class HashingTest : ShouldSpec({
  context("Encoding a string") {
    should("encode correctly") {
      val dataOne = "S@!sc_%kah"
      val encondeOne = dataOne.encode()
      val dataTwo = "S@!sc_%kah"
      dataTwo.checkEncoding(encondeOne) shouldBe true // works fine!
    }
  }
})

When I save to the database, and try to compare, I always get an error

//ENTITY

data class User(
  override val id: UUID,
  val username: String,
  val password: String,
) : IEntity


//INSERT SCRITP -> EXPOSED FRAMEWORK

private fun newUser(schema: String, entity: User) {
  val table = toUserTable(schema)
  table
    .insert {
      it[id] = entity.id
      it[username] = entity.username 
      it[password] = entity.password.encode()
    }
}

//FIND USER

fun findUser(schema: String, model: SignInModel): User? {
  val table = toUserTable(schema)
  val user = table
    .select { table.username eq model.username }
    .firstNotNullOfOrNull { toUser(schema, it) }
  val verifying = model.password.checkEncoding(user!!.password) // ERROR HERE, ALWAYS RETURNS FALSE
  return when (verifying) {
    true -> user
    false -> null
  }
}



Solution

  • I don't know if you used your findUser() and newUser() in a transaction but queries must be called in a transaction like below:

    private fun newUser(schema: String, entity: User) {
        val table = toUserTable(schema)
        transaction {
            table
               .insert {
                   it[id] = entity.id
                   it[username] = entity.username 
                   it[password] = entity.password.encode()
                }
        }
    }
    

    and:

    fun findUser(schema: String, model: SignInModel): User? {
      val table = toUserTable(schema)
      val user = transaction {
          table
            .select { table.username eq model.username }
            .firstNotNullOfOrNull { toUser(schema, it) }
      }
    
      val verifying = model.password.checkEncoding(user!!.password)
      return when (verifying) {
        true -> user
        false -> null
      }
    }