Codersee
Kotlin on the backend
Codersee
Kotlin on the backend
In this article, we will learn a bit more about Kotlin password hashing, PBKDF2, and how to write a Kotlin code with PBKDF2 in practice.
Hello and welcome to the article about Kotlin password hashing with PBKDF2 (to be even more specific- with PBKDF2WithHmacSHA512).
In this hands-on guide, we will:
Well, password hashing is the process of taking a password and applying a mathematical function (the hash function) to it to produce a fixed-size string of characters- the hash value (also known as digest).
It’s worth mentioning, that it is a one-way operation. We simply can’t reverse the process and obtain the key from a hash value. So even if attackers gain access to the hashed password in our database, obtaining the original password is difficult.
But difficult, doesn’t mean impossible. Although the process can’t be reversed, attackers can try to crack the password using different combinations of characters and computing the hash value for each combination. And because of that, password hashing algorithms are designed to be computationally expensive, meaning that it takes a long time to compute the hash value for a given password.
So, given these points, we can clearly see that password hashing is important not only when working with Kotlin.
Before we dive into the Kotlin password hashing with pbkdf2, let’s learn more about salt.
Salt is a random value that is generated and added to the input data before it is hashed. Thanks to that, the resulting hash will be different even if the original passwords are the same, making it even harder to crack the hashed passwords using precomputed hash tables (also known as rainbow tables).
And as the last thing before the practice part, let’s take a look at a couple of password hashing algorithms, which we can use when working with Kotlin:
So, with all of that being said, we can finally start the coding part. As I mentioned in the beginning, we will see how to hash passwords in Kotlin with PBKDF2WithHmacSHA512.
Don’t worry about this monster- it’s a name of an algorithm, which we will use when requesting an instance of SecretKeyFactory. Without going into much detail here, our little monster will generate a 512 bits hash value. (And if you’re interested in a more detailed answer, then check out this StackOverflow topic).
Firstly, let’s implement a function responsible for generating random salt:
fun generateRandomSalt(): ByteArray { val random = SecureRandom() val salt = ByteArray(16) random.nextBytes(salt) return salt }
16-byte salt will be enough. Whatsoever, we create a SecureRandom instance using the default constructor.
But, if we would like to pick a specific algorithm, then we can use the getInstance method instead:
SecureRandom.getInstance("PKCS11")
We can find the list of all supported algorithms right here.
Lastly, if we would like to convert the ByteArray to a hex String, we can use the formatHex:
private fun ByteArray.toHexString(): String = HexFormat.of().formatHex(this) // so that later, we can simply run: salt.toHexString()
As the last thing in our Kotlin password hashing with PBKDF2, let’s implement the generateHash:
private const val ALGORITHM = "PBKDF2WithHmacSHA512" private const val ITERATIONS = 120_000 private const val KEY_LENGTH = 256 private const val SECRET = "SomeRandomSecret" fun generateHash(password: String, salt: String): String { val combinedSalt = "$salt$SECRET".toByteArray() val factory: SecretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM) val spec: KeySpec = PBEKeySpec(password.toCharArray(), combinedSalt, ITERATIONS, KEY_LENGTH) val key: SecretKey = factory.generateSecret(spec) val hash: ByteArray = key.encoded return hash.toHexString() }
As we can see in the first line of our function, we combine the salt with an additional SECRET value. Oftentimes, the salt value is generated for each user in our system, which means that we have to persist it in the database, as well. So, in case our database data are leaked, we can reduce the risk of password cracking through this additional step.
For simplicity, the secret value is stored as a constant, but in a real-life scenario, we’d rather pass it as an environment variable
In the following lines, we define a SecretKeyFactory instance and a KeySpec with the desired password, salt, iterations and key length values.
When it comes to the number of iterations, in 2021 OWASP recommended 120,000 iterations for PBKDF2-HMAC-SHA512. The key length is equivalent to the chance for a hash collision, so it’s good for it to be at least 128 bits.
And that would be all for this article covering Kotlin password hashing with the PBKDF2 topic.
If you enjoyed this content, then you might also be interested in one of the following posts:
Let me know in the comments section about your thoughts! 🙂
Let me first say that this tutorial is very detailed and educational.
But I have one question. How do you use these functions in your project. In case you can’t tell, I am a newbie when it comes to writing and developing Android App.
Thank you,
Hey hi hello David!
In general, Android apps (like a web, or desktop apps) serve as the clients in a typical client-server communication.
Which means, that typically, your Android app will not be responsible for password hashing, but rather server. And on Android side, you will be doing requests, like for example POST /login with some request body in JSON, like
{ “email”: “one@codersee.com”, “password”: “somePwd” }
And then, the server will be responsible for the hashing etc
If you would like to, then you will find a bunch of content on my blog, YT, or you can join my course https://codersee.com/courses/ktor-server-pro/ for the step-by-step approach 😉