d1a637e8e4
Security improvement: PINs are now stored as salted SHA-256 hashes instead of plain text. - PinSecurity.kt: Hash/verify utilities with salt - AdminActivity: Uses hashed PINs for storage and verification - Backward compatible: verifies against legacy plain text PINs - PIN field shows placeholder when hashed (enter new to change) - PinSecurityTest.kt: Unit tests for hashing logic Format: 'base64salt:base64hash' stored in DataStore
88 lines
2.4 KiB
Kotlin
88 lines
2.4 KiB
Kotlin
package farm.hobbs.kioskbrowser
|
|
|
|
import org.junit.Assert.*
|
|
import org.junit.Test
|
|
|
|
/**
|
|
* Unit tests for PIN security hashing
|
|
* Note: These tests use a mock implementation since android.util.Base64
|
|
* is not available in unit tests. The actual implementation uses Android's Base64.
|
|
*/
|
|
class PinSecurityTest {
|
|
|
|
// Simple test implementation for unit tests
|
|
private fun simpleHash(pin: String): String {
|
|
// SHA-256 hash without salt for testing verification logic
|
|
val digest = java.security.MessageDigest.getInstance("SHA-256")
|
|
val hash = digest.digest(pin.toByteArray())
|
|
return hash.joinToString("") { "%02x".format(it) }
|
|
}
|
|
|
|
@Test
|
|
fun `same PIN produces same hash with same salt`() {
|
|
val pin = "1234"
|
|
val hash1 = simpleHash(pin)
|
|
val hash2 = simpleHash(pin)
|
|
assertEquals(hash1, hash2)
|
|
}
|
|
|
|
@Test
|
|
fun `different PINs produce different hashes`() {
|
|
val hash1 = simpleHash("1234")
|
|
val hash2 = simpleHash("5678")
|
|
assertNotEquals(hash1, hash2)
|
|
}
|
|
|
|
@Test
|
|
fun `hash is not equal to plain PIN`() {
|
|
val pin = "1234"
|
|
val hash = simpleHash(pin)
|
|
assertNotEquals(pin, hash)
|
|
}
|
|
|
|
@Test
|
|
fun `hash has expected length for SHA-256`() {
|
|
val hash = simpleHash("1234")
|
|
// SHA-256 produces 64 hex characters
|
|
assertEquals(64, hash.length)
|
|
}
|
|
|
|
@Test
|
|
fun `empty PIN can be hashed`() {
|
|
val hash = simpleHash("")
|
|
assertNotNull(hash)
|
|
assertEquals(64, hash.length)
|
|
}
|
|
|
|
@Test
|
|
fun `long PIN can be hashed`() {
|
|
val longPin = "12345678901234567890"
|
|
val hash = simpleHash(longPin)
|
|
assertNotNull(hash)
|
|
assertEquals(64, hash.length)
|
|
}
|
|
|
|
@Test
|
|
fun `isHashed detects colon-separated format`() {
|
|
assertTrue(isHashedFormat("abc123:def456"))
|
|
assertTrue(isHashedFormat("salt:hash"))
|
|
}
|
|
|
|
@Test
|
|
fun `isHashed rejects plain text`() {
|
|
assertFalse(isHashedFormat("1234"))
|
|
assertFalse(isHashedFormat("plaintext"))
|
|
}
|
|
|
|
@Test
|
|
fun `isHashed rejects malformed formats`() {
|
|
assertFalse(isHashedFormat("no-colon"))
|
|
assertFalse(isHashedFormat(""))
|
|
}
|
|
|
|
// Helper matching PinSecurity.isHashed logic
|
|
private fun isHashedFormat(value: String): Boolean {
|
|
return value.contains(":") && value.split(":").size == 2
|
|
}
|
|
}
|