Hashing with Compose Multiplatform

<< RETURN: Coding / Kotlin / Coding with Kotlin

Overview

Hashing with Compose Multiplatform in Kotlin is simple, by using an existing Java Library called Message Digest which takes in an array of bytes, hashes them, and returns the hashed value as an array of bytes. We just need to specify the hash type as well as supply it with the byte array to hash.

Hashing Sample Code

Kotlin
import java.security.MessageDigest

fun main() {
  val input = "Hello World".toByteArray()
  val md = MessageDigest.getInstance("SHA256")
  val bytes = md.digest(input)
  var hash = ""
  bytes.forEach { byte ->
      hash += String.format("%02X", byte)
  }
  println(hash)
}

/*
A591A6D40BF420404A011733CFB7B190D62C65BF0BCDA32B57B277D9AD9F146E
*/

The sample code above acquires the SHA256 hash value of the string “Hello World”. It converts the string to an array of bytes, hashes it, then converts the hashed bytes to a hex string.

There are many different hashing algorithms, you can get a list of available algorithms with Message Digest by using the Security class.

Kotlin
import java.security.Security

val algorithms = Security.getAlgorithms("MessageDigest")
var algoStr = ""

for (algorithm in algorithms) {
    algoStr += "$algorithm "
}
println(algoStr)

/*
SHA3-512 SHA-1 SHA-384 SHA3-384 SHA-224 SHA-512/256 SHA-256 MD2 SHA-512/224 SHA3-256 SHA-512 SHA3-224 MD5
*/

Compose Multiplatform Example

Kotlin
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material.icons.filled.KeyboardArrowUp
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import java.security.MessageDigest
import java.security.Security


@Composable
@Preview
fun App() {
    var mExpanded by remember { mutableStateOf(false) }
    var mSelectedText by remember { mutableStateOf("") }
    var text by remember { mutableStateOf("") }

    // Up Icon when expanded and down icon when collapsed
    val icon = if (mExpanded)
        Icons.Filled.KeyboardArrowUp
    else
        Icons.Filled.KeyboardArrowDown

    MaterialTheme {
        Column(modifier = Modifier.fillMaxSize().padding(10.dp, 10.dp, 10.dp, 10.dp),
            horizontalAlignment = Alignment.Start) {
            Row(modifier = Modifier.fillMaxWidth().padding(5.dp, 5.dp),
                verticalAlignment = Alignment.Top) {
                TextField(
                    value = text,
                    onValueChange = { text = it },
                    label = { Text("Output") },
                    modifier = Modifier.fillMaxWidth().padding(10.dp, 10.dp, 10.dp, 0.dp)
                )
            }
            Row(modifier = Modifier.fillMaxWidth().padding(5.dp, 5.dp),
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.Center) {

                Column(modifier = Modifier.padding(10.dp, 10.dp, 10.dp, 10.dp)) {
                    OutlinedTextField(
                        value = mSelectedText,
                        onValueChange = { mSelectedText = it },
                        label = {Text("Select Hash Type")},
                        trailingIcon = {
                            Icon(icon,"contentDescription",
                                Modifier.clickable { mExpanded = !mExpanded })
                        },
                        modifier = Modifier.width(250.dp),
                        readOnly = true
                    )
                    DropdownMenu(
                        expanded = mExpanded,
                        onDismissRequest = { mExpanded = false }
                    ) {
                        val hashList = getHashOptions()
                        hashList.forEach { label ->
                            DropdownMenuItem(onClick = {
                                mSelectedText = label
                                mExpanded = false
                            }) {
                                Text(text = label)
                            }
                        }
                    }
                }
                Column(modifier = Modifier.padding(10.dp, 10.dp, 10.dp, 10.dp)) {
                    Button(onClick = {
                        text = generateHash(text, mSelectedText)
                    }) {
                        Text("Generate Hash")
                    }
                }
            }
        }
    }
}

fun main() = application {
    Window(onCloseRequest = ::exitApplication, title = "Simple Hash Generator") {
        App()
    }
}

fun getHashOptions(): List<String> {
    return Security.getAlgorithms("MessageDigest").toList()
}

fun generateHash(text: String, hashType: String): String {
    val input = text.toByteArray()
    val md = MessageDigest.getInstance(hashType)
    val bytes = md.digest(input)
    var hash = ""
    bytes.forEach { byte ->
        hash += String.format("%02X", byte)
    }
    return hash
}

Using Compose Multiplatform, I created a simple hashing program with a pretty exhaustive list of hash types to choose from.

Github

If copying the above code doesn’t work, you can clone it from my Github repository: SimpleHasher.

Next Up

TBD