Added java implementation of _pwhash_
This commit is contained in:
		
							parent
							
								
									2b4d8aa4b1
								
							
						
					
					
						commit
						fe4134a65f
					
				@ -1,5 +1,6 @@
 | 
			
		||||
package com.ionspin.kotlin.crypto.pwhash
 | 
			
		||||
 | 
			
		||||
import com.ionspin.kotlin.crypto.LibsodiumInitializer
 | 
			
		||||
import com.ionspin.kotlin.crypto.util.toHexString
 | 
			
		||||
import kotlin.random.Random
 | 
			
		||||
import kotlin.random.nextUBytes
 | 
			
		||||
@ -14,44 +15,53 @@ import kotlin.test.assertTrue
 | 
			
		||||
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()}")
 | 
			
		||||
        LibsodiumInitializer.initializeWithCallback {
 | 
			
		||||
            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()}")
 | 
			
		||||
            assertTrue {
 | 
			
		||||
                hashedPassword.toHexString().equals("e762ee529e90e3bbc242c23e8e2f963ab9a17ed9e79f89a00c71261a979207b2213cc" +
 | 
			
		||||
                        "0330c53f410a9c8933c46e8642dc542efc0660c69e255b601c7244ef6b0")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @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
 | 
			
		||||
        LibsodiumInitializer.initializeWithCallback {
 | 
			
		||||
            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.strNeedsRehash(hashedPassword, crypto_pwhash_OPSLIMIT_MIN, crypto_pwhash_MEMLIMIT_MIN) == 0
 | 
			
		||||
        }
 | 
			
		||||
            assertTrue {
 | 
			
		||||
                PasswordHash.strVerify(
 | 
			
		||||
                    hashedPassword,
 | 
			
		||||
                    password
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        assertTrue {
 | 
			
		||||
            PasswordHash.strNeedsRehash(hashedPassword, crypto_pwhash_OPSLIMIT_MIN, crypto_pwhash_MEMLIMIT_SENSITIVE) == 1
 | 
			
		||||
        }
 | 
			
		||||
            assertTrue {
 | 
			
		||||
                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