Adding pwhash native and tests
This commit is contained in:
parent
65bf54765f
commit
2b4d8aa4b1
@ -7,25 +7,25 @@ package com.ionspin.kotlin.crypto.pwhash
|
|||||||
|
|
||||||
const val crypto_pwhash_BYTES_MIN = 16U
|
const val crypto_pwhash_BYTES_MIN = 16U
|
||||||
const val crypto_pwhash_MEMLIMIT_INTERACTIVE = 67108864U
|
const val crypto_pwhash_MEMLIMIT_INTERACTIVE = 67108864U
|
||||||
const val crypto_pwhash_MEMLIMIT_MIN = 8192U
|
const val crypto_pwhash_MEMLIMIT_MIN = 8192
|
||||||
const val crypto_pwhash_MEMLIMIT_MODERATE = 268435456U
|
const val crypto_pwhash_MEMLIMIT_MODERATE = 268435456
|
||||||
const val crypto_pwhash_MEMLIMIT_SENSITIVE = 1073741824U
|
const val crypto_pwhash_MEMLIMIT_SENSITIVE = 1073741824
|
||||||
const val crypto_pwhash_OPSLIMIT_INTERACTIVE = 2U
|
const val crypto_pwhash_OPSLIMIT_INTERACTIVE = 2
|
||||||
const val crypto_pwhash_OPSLIMIT_MAX = 4294967295U
|
const val crypto_pwhash_OPSLIMIT_MAX = 4294967295UL
|
||||||
const val crypto_pwhash_OPSLIMIT_MIN = 1U
|
const val crypto_pwhash_OPSLIMIT_MIN = 1UL
|
||||||
const val crypto_pwhash_OPSLIMIT_MODERATE = 3U
|
const val crypto_pwhash_OPSLIMIT_MODERATE = 3UL
|
||||||
const val crypto_pwhash_OPSLIMIT_SENSITIVE = 4U
|
const val crypto_pwhash_OPSLIMIT_SENSITIVE = 4UL
|
||||||
const val crypto_pwhash_PASSWD_MAX = 4294967295U
|
const val crypto_pwhash_PASSWD_MAX = 4294967295
|
||||||
const val crypto_pwhash_PASSWD_MIN = 0U
|
const val crypto_pwhash_PASSWD_MIN = 0
|
||||||
const val crypto_pwhash_SALTBYTES = 16U
|
const val crypto_pwhash_SALTBYTES = 16
|
||||||
const val crypto_pwhash_STRBYTES = 128U
|
const val crypto_pwhash_STRBYTES = 128
|
||||||
const val crypto_pwhash_STRPREFIX = "\$argon2id$"
|
const val crypto_pwhash_STRPREFIX = "\$argon2id$"
|
||||||
|
|
||||||
val crypto_pwhash_argon2id_ALG_ARGON2ID13 = 2
|
val crypto_pwhash_argon2id_ALG_ARGON2ID13 = 2
|
||||||
val crypto_pwhash_argon2i_ALG_ARGON2I13 = 1
|
val crypto_pwhash_argon2i_ALG_ARGON2I13 = 1
|
||||||
val crypto_pwhash_ALG_DEFAULT = crypto_pwhash_argon2id_ALG_ARGON2ID13
|
val crypto_pwhash_ALG_DEFAULT = crypto_pwhash_argon2id_ALG_ARGON2ID13
|
||||||
|
|
||||||
class PasswordHashFailed() : RuntimeException("Password hashing failed")
|
class PasswordHashingFailed() : RuntimeException("Password hashing failed")
|
||||||
|
|
||||||
expect object PasswordHash {
|
expect object PasswordHash {
|
||||||
/**
|
/**
|
||||||
@ -55,7 +55,7 @@ expect object PasswordHash {
|
|||||||
* and other data stores. No extra information has to be stored in order to verify the password.
|
* and other data stores. No extra information has to be stored in order to verify the password.
|
||||||
* The function returns 0 on success and -1 if it didn't complete successfully.
|
* The function returns 0 on success and -1 if it didn't complete successfully.
|
||||||
*/
|
*/
|
||||||
fun str(password: String, opslimit: ULong, memlimit: Int): String
|
fun str(password: String, opslimit: ULong, memlimit: Int): UByteArray
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a password verification string str matches the parameters opslimit and memlimit, and the current default algorithm.
|
* Check if a password verification string str matches the parameters opslimit and memlimit, and the current default algorithm.
|
||||||
@ -63,6 +63,13 @@ expect object PasswordHash {
|
|||||||
* The function returns 0 if the parameters already match the given ones.
|
* The function returns 0 if the parameters already match the given ones.
|
||||||
* It returns -1 on error. If it happens, applications may want to compute a correct hash the next time the user logs in.
|
* It returns -1 on error. If it happens, applications may want to compute a correct hash the next time the user logs in.
|
||||||
*/
|
*/
|
||||||
fun strNeedsRehash(password: String, opslimit: ULong, memlimit: Int): Boolean
|
fun strNeedsRehash(passwordHash: UByteArray, opslimit: ULong, memlimit: Int): Int
|
||||||
fun strVerify(passwordHash: String, password: UByteArray): Boolean
|
|
||||||
|
/**
|
||||||
|
* his function verifies that str is a valid password verification string (as generated by crypto_pwhash_str()) for passwd whose length is passwdlen.
|
||||||
|
* str has to be zero-terminated.
|
||||||
|
* It returns 0 if the verification succeeds, and -1 on error.
|
||||||
|
*/
|
||||||
|
fun strVerify(passwordHash: UByteArray, password: String): Boolean
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.pwhash
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.util.toHexString
|
||||||
|
import kotlin.random.Random
|
||||||
|
import kotlin.random.nextUBytes
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Ugljesa Jovanovic
|
||||||
|
* ugljesa.jovanovic@ionspin.com
|
||||||
|
* on 21-Sep-2020
|
||||||
|
*/
|
||||||
|
class PasswordHashTest {
|
||||||
|
@Test
|
||||||
|
fun testPasswordHash() {
|
||||||
|
val randomBytes = Random(0).nextUBytes(crypto_pwhash_SALTBYTES)
|
||||||
|
val password = "correct horse battery staple"
|
||||||
|
val hashedPassword = PasswordHash.pwhash(
|
||||||
|
64,
|
||||||
|
password,
|
||||||
|
randomBytes,
|
||||||
|
crypto_pwhash_OPSLIMIT_MIN,
|
||||||
|
crypto_pwhash_MEMLIMIT_MIN,
|
||||||
|
crypto_pwhash_ALG_DEFAULT
|
||||||
|
)
|
||||||
|
println("Hashed password: ${hashedPassword.toHexString()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testPasswordHashForStorage() {
|
||||||
|
val password = "correct horse battery staple"
|
||||||
|
val hashedPassword = PasswordHash.str(
|
||||||
|
password,
|
||||||
|
crypto_pwhash_OPSLIMIT_MIN,
|
||||||
|
crypto_pwhash_MEMLIMIT_MIN
|
||||||
|
)
|
||||||
|
println("Hashed password for storage: ${hashedPassword.toHexString()}")
|
||||||
|
|
||||||
|
assertTrue {
|
||||||
|
PasswordHash.strVerify(
|
||||||
|
hashedPassword,
|
||||||
|
password
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue {
|
||||||
|
PasswordHash.strNeedsRehash(hashedPassword, crypto_pwhash_OPSLIMIT_MIN, crypto_pwhash_MEMLIMIT_MIN) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue {
|
||||||
|
PasswordHash.strNeedsRehash(hashedPassword, crypto_pwhash_OPSLIMIT_MIN, crypto_pwhash_MEMLIMIT_SENSITIVE) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO strNeedsRehash -1 case?
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,11 @@ import com.ionspin.kotlin.crypto.util.toPtr
|
|||||||
import kotlinx.cinterop.addressOf
|
import kotlinx.cinterop.addressOf
|
||||||
import kotlinx.cinterop.convert
|
import kotlinx.cinterop.convert
|
||||||
import kotlinx.cinterop.pin
|
import kotlinx.cinterop.pin
|
||||||
|
import kotlinx.cinterop.toCValues
|
||||||
import libsodium.crypto_pwhash
|
import libsodium.crypto_pwhash
|
||||||
import libsodium.crypto_pwhash_str
|
import libsodium.crypto_pwhash_str
|
||||||
import libsodium.crypto_pwhash_str_needs_rehash
|
import libsodium.crypto_pwhash_str_needs_rehash
|
||||||
|
import libsodium.crypto_pwhash_str_verify
|
||||||
|
|
||||||
actual object PasswordHash {
|
actual object PasswordHash {
|
||||||
/**
|
/**
|
||||||
@ -30,7 +32,7 @@ actual object PasswordHash {
|
|||||||
val hashedPasswordPinned = hashedPassword.pin()
|
val hashedPasswordPinned = hashedPassword.pin()
|
||||||
val saltPinned = salt.pin()
|
val saltPinned = salt.pin()
|
||||||
|
|
||||||
crypto_pwhash(
|
val hashingResult = crypto_pwhash(
|
||||||
hashedPasswordPinned.toPtr(),
|
hashedPasswordPinned.toPtr(),
|
||||||
outputLength.convert(),
|
outputLength.convert(),
|
||||||
password,
|
password,
|
||||||
@ -42,6 +44,9 @@ actual object PasswordHash {
|
|||||||
)
|
)
|
||||||
saltPinned.unpin()
|
saltPinned.unpin()
|
||||||
hashedPasswordPinned.unpin()
|
hashedPasswordPinned.unpin()
|
||||||
|
if (hashingResult != 0) {
|
||||||
|
throw PasswordHashingFailed()
|
||||||
|
}
|
||||||
|
|
||||||
return hashedPassword
|
return hashedPassword
|
||||||
}
|
}
|
||||||
@ -56,8 +61,8 @@ actual object PasswordHash {
|
|||||||
* and other data stores. No extra information has to be stored in order to verify the password.
|
* and other data stores. No extra information has to be stored in order to verify the password.
|
||||||
* The function returns 0 on success and -1 if it didn't complete successfully.
|
* The function returns 0 on success and -1 if it didn't complete successfully.
|
||||||
*/
|
*/
|
||||||
actual fun str(password: String, opslimit: ULong, memlimit: Int): String {
|
actual fun str(password: String, opslimit: ULong, memlimit: Int): UByteArray {
|
||||||
val output = ByteArray(crypto_pwhash_STRBYTES.toInt())
|
val output = ByteArray(crypto_pwhash_STRBYTES)
|
||||||
val outputPinned = output.pin()
|
val outputPinned = output.pin()
|
||||||
crypto_pwhash_str(
|
crypto_pwhash_str(
|
||||||
outputPinned.addressOf(0),
|
outputPinned.addressOf(0),
|
||||||
@ -68,7 +73,7 @@ actual object PasswordHash {
|
|||||||
)
|
)
|
||||||
outputPinned.unpin()
|
outputPinned.unpin()
|
||||||
|
|
||||||
return output.decodeToString()
|
return output.asUByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,20 +83,32 @@ actual object PasswordHash {
|
|||||||
* It returns -1 on error. If it happens, applications may want to compute a correct hash the next time the user logs in.
|
* It returns -1 on error. If it happens, applications may want to compute a correct hash the next time the user logs in.
|
||||||
*/
|
*/
|
||||||
actual fun strNeedsRehash(
|
actual fun strNeedsRehash(
|
||||||
password: String,
|
passwordHash: UByteArray,
|
||||||
opslimit: ULong,
|
opslimit: ULong,
|
||||||
memlimit: Int
|
memlimit: Int
|
||||||
): Boolean {
|
): Int {
|
||||||
val password = password.encodeToByteArray()
|
val result = crypto_pwhash_str_needs_rehash(
|
||||||
crypto_pwhash_str_needs_rehash(
|
passwordHash.asByteArray().toCValues(),
|
||||||
,
|
|
||||||
opslimit,
|
opslimit,
|
||||||
memlimit.convert()
|
memlimit.convert()
|
||||||
)
|
)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun strVerify(passwordHash: String, password: UByteArray): Boolean {
|
/**
|
||||||
TODO("Not yet implemented")
|
* his function verifies that str is a valid password verification string (as generated by crypto_pwhash_str()) for passwd whose length is passwdlen.
|
||||||
|
* str has to be zero-terminated.
|
||||||
|
* It returns 0 if the verification succeeds, and -1 on error.
|
||||||
|
*/
|
||||||
|
actual fun strVerify(passwordHash: UByteArray, password: String): Boolean {
|
||||||
|
val result = crypto_pwhash_str_verify(
|
||||||
|
passwordHash.asByteArray().toCValues(),
|
||||||
|
password,
|
||||||
|
password.length.convert()
|
||||||
|
)
|
||||||
|
return result == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user