Added java implementation of _pwhash_
This commit is contained in:
parent
2b4d8aa4b1
commit
fe4134a65f
@ -1,5 +1,6 @@
|
|||||||
package com.ionspin.kotlin.crypto.pwhash
|
package com.ionspin.kotlin.crypto.pwhash
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.LibsodiumInitializer
|
||||||
import com.ionspin.kotlin.crypto.util.toHexString
|
import com.ionspin.kotlin.crypto.util.toHexString
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
import kotlin.random.nextUBytes
|
import kotlin.random.nextUBytes
|
||||||
@ -14,44 +15,53 @@ import kotlin.test.assertTrue
|
|||||||
class PasswordHashTest {
|
class PasswordHashTest {
|
||||||
@Test
|
@Test
|
||||||
fun testPasswordHash() {
|
fun testPasswordHash() {
|
||||||
val randomBytes = Random(0).nextUBytes(crypto_pwhash_SALTBYTES)
|
LibsodiumInitializer.initializeWithCallback {
|
||||||
val password = "correct horse battery staple"
|
val randomBytes = Random(0).nextUBytes(crypto_pwhash_SALTBYTES)
|
||||||
val hashedPassword = PasswordHash.pwhash(
|
val password = "correct horse battery staple"
|
||||||
64,
|
val hashedPassword = PasswordHash.pwhash(
|
||||||
password,
|
64,
|
||||||
randomBytes,
|
password,
|
||||||
crypto_pwhash_OPSLIMIT_MIN,
|
randomBytes,
|
||||||
crypto_pwhash_MEMLIMIT_MIN,
|
crypto_pwhash_OPSLIMIT_MIN,
|
||||||
crypto_pwhash_ALG_DEFAULT
|
crypto_pwhash_MEMLIMIT_MIN,
|
||||||
)
|
crypto_pwhash_ALG_DEFAULT
|
||||||
println("Hashed password: ${hashedPassword.toHexString()}")
|
)
|
||||||
|
println("Hashed password: ${hashedPassword.toHexString()}")
|
||||||
|
assertTrue {
|
||||||
|
hashedPassword.toHexString().equals("e762ee529e90e3bbc242c23e8e2f963ab9a17ed9e79f89a00c71261a979207b2213cc" +
|
||||||
|
"0330c53f410a9c8933c46e8642dc542efc0660c69e255b601c7244ef6b0")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPasswordHashForStorage() {
|
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 {
|
LibsodiumInitializer.initializeWithCallback {
|
||||||
PasswordHash.strVerify(
|
val password = "correct horse battery staple"
|
||||||
hashedPassword,
|
val hashedPassword = PasswordHash.str(
|
||||||
password
|
password,
|
||||||
|
crypto_pwhash_OPSLIMIT_MIN,
|
||||||
|
crypto_pwhash_MEMLIMIT_MIN
|
||||||
)
|
)
|
||||||
}
|
println("Hashed password for storage: ${hashedPassword.toHexString()}")
|
||||||
|
|
||||||
assertTrue {
|
assertTrue {
|
||||||
PasswordHash.strNeedsRehash(hashedPassword, crypto_pwhash_OPSLIMIT_MIN, crypto_pwhash_MEMLIMIT_MIN) == 0
|
PasswordHash.strVerify(
|
||||||
}
|
hashedPassword,
|
||||||
|
password
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
assertTrue {
|
assertTrue {
|
||||||
PasswordHash.strNeedsRehash(hashedPassword, crypto_pwhash_OPSLIMIT_MIN, crypto_pwhash_MEMLIMIT_SENSITIVE) == 1
|
PasswordHash.strNeedsRehash(hashedPassword, crypto_pwhash_OPSLIMIT_MIN, crypto_pwhash_MEMLIMIT_MIN) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO strNeedsRehash -1 case?
|
assertTrue {
|
||||||
|
PasswordHash.strNeedsRehash(hashedPassword, crypto_pwhash_OPSLIMIT_MIN, crypto_pwhash_MEMLIMIT_SENSITIVE) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO strNeedsRehash -1 case?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
package com.ionspin.kotlin.crypto.pwhash
|
||||||
|
|
||||||
|
import com.ionspin.kotlin.crypto.LibsodiumInitializer.sodium
|
||||||
|
import com.sun.jna.NativeLong
|
||||||
|
|
||||||
|
actual object PasswordHash {
|
||||||
|
/**
|
||||||
|
* The crypto_pwhash() function derives an outlen bytes long key from a password passwd whose length is passwdlen
|
||||||
|
* and a salt salt whose fixed length is crypto_pwhash_SALTBYTES bytes. passwdlen should be at least crypto_pwhash_
|
||||||
|
* PASSWD_MIN and crypto_pwhash_PASSWD_MAX. outlen should be at least crypto_pwhash_BYTES_MIN = 16 (128 bits) and
|
||||||
|
* at most crypto_pwhash_BYTES_MAX.
|
||||||
|
*
|
||||||
|
* See https://libsodium.gitbook.io/doc/password_hashing/default_phf for more details
|
||||||
|
*/
|
||||||
|
actual fun pwhash(
|
||||||
|
outputLength: Int,
|
||||||
|
password: String,
|
||||||
|
salt: UByteArray,
|
||||||
|
opsLimit: ULong,
|
||||||
|
memLimit: Int,
|
||||||
|
algorithm: Int
|
||||||
|
): UByteArray {
|
||||||
|
val hashedPassword = UByteArray(outputLength)
|
||||||
|
|
||||||
|
sodium.crypto_pwhash(
|
||||||
|
hashedPassword.asByteArray(),
|
||||||
|
outputLength.toLong(),
|
||||||
|
password.encodeToByteArray(),
|
||||||
|
password.length.toLong(),
|
||||||
|
salt.asByteArray(),
|
||||||
|
opsLimit.toLong(),
|
||||||
|
NativeLong(memLimit.toLong()),
|
||||||
|
algorithm
|
||||||
|
)
|
||||||
|
|
||||||
|
return hashedPassword
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The crypto_pwhash_str() function puts an ASCII encoded string into out, which includes:
|
||||||
|
* the result of a memory-hard, CPU-intensive hash function applied to the password passwd of length passwdlen
|
||||||
|
* the automatically generated salt used for the previous computation
|
||||||
|
* the other parameters required to verify the password, including the algorithm identifier, its version, opslimit and memlimit.
|
||||||
|
* out must be large enough to hold crypto_pwhash_STRBYTES bytes, but the actual output string may be shorter.
|
||||||
|
* The output string is zero-terminated, includes only ASCII characters and can be safely stored into SQL databases
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
actual fun str(password: String, opslimit: ULong, memlimit: Int): UByteArray {
|
||||||
|
val output = ByteArray(crypto_pwhash_STRBYTES)
|
||||||
|
sodium.crypto_pwhash_str(
|
||||||
|
output,
|
||||||
|
password.encodeToByteArray(),
|
||||||
|
password.length.toLong(),
|
||||||
|
opslimit.toLong(),
|
||||||
|
NativeLong(memlimit.toLong())
|
||||||
|
)
|
||||||
|
return output.asUByteArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a password verification string str matches the parameters opslimit and memlimit, and the current default algorithm.
|
||||||
|
* The function returns 1 if the string appears to be correct, but doesn't match the given parameters. In that situation, applications may want to compute a new hash using the current parameters the next time the user logs in.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
actual fun strNeedsRehash(
|
||||||
|
passwordHash: UByteArray,
|
||||||
|
opslimit: ULong,
|
||||||
|
memlimit: Int
|
||||||
|
): Int {
|
||||||
|
return sodium.crypto_pwhash_str_needs_rehash(
|
||||||
|
passwordHash.asByteArray(),
|
||||||
|
opslimit.toLong(),
|
||||||
|
NativeLong(memlimit.toLong())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 = sodium.crypto_pwhash_str_verify(
|
||||||
|
passwordHash.asByteArray(),
|
||||||
|
password.encodeToByteArray(),
|
||||||
|
password.length.toLong()
|
||||||
|
)
|
||||||
|
|
||||||
|
return result == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user