Hash Generator — Kotlin source
Compute SHA-1, SHA-256, SHA-384 and SHA-512 hashes of any text at once, using the browser's native SubtleCrypto. Copy each digest. 100% client-side.
This is the Kotlin implementation — the same logic the interactive tool runs, in a shareable, citable form.
// hash — SHA-1 / SHA-256 / SHA-384 / SHA-512 digest of a UTF-8 string.
//
// Language: Kotlin 1.9 (JVM, standard library + java.security)
// Source: CosmoDev polyglot showcase port of the `hash` tool, ported from
// src/tools/HashGenerator.tsx (the canonical TypeScript island).
// License: display source — part of CosmoDev's polyglot tool pages.
//
// Kotlin/JVM has no crypto in kotlin-stdlib, so the idiomatic path is the
// JDK's java.security.MessageDigest — the same vetted provider set the Java
// port of this tool uses. All four names are standard JCA algorithm strings;
// no external dependencies are needed.
//
// Behavior mirrors the TypeScript reference: UTF-8 input, lowercase hex
// output, and rejection of unknown algorithm names. MessageDigest's checked
// NoSuchAlgorithmException is translated into IllegalArgumentException —
// the Kotlin standing of the Python port's ValueError. SHA-1 is offered for
// legacy compatibility only; it is not collision-resistant.
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
/** Pure logic of the CosmoDev `hash` tool. */
object HashTool {
/** Canonical algorithm names. The spellings match the TypeScript union so
* the same string works across every port. */
const val SHA1: String = "SHA-1"
const val SHA256: String = "SHA-256" // default algorithm
const val SHA384: String = "SHA-384"
const val SHA512: String = "SHA-512"
/** Every supported algorithm, in the order the React island renders them. */
val ALGORITHMS: List<String> = listOf(SHA1, SHA256, SHA384, SHA512)
/**
* Computes the named digest of [text] and returns it as lowercase hex.
*
* The text is UTF-8 encoded before hashing, so the result is correct for
* arbitrary Unicode (emoji, accents, CJK). A null or empty [algorithm]
* selects SHA-256 — the default parameter the TypeScript reference
* declares. An unknown name throws [IllegalArgumentException].
*/
fun digest(text: String, algorithm: String = SHA256): String {
val name = algorithm.takeIf { it.isNotEmpty() } ?: SHA256
// The supported set is fixed by the tool. Checking it here — before
// getInstance — rejects unknown names with IllegalArgumentException
// and stops the JCA from accepting digests the tool does not offer
// ("MD5" passes the provider lookup but is outside this contract).
require(name in ALGORITHMS) { "Unsupported hash algorithm: $name" }
val md: MessageDigest = try {
// A fresh instance per call: MessageDigest is stateful.
MessageDigest.getInstance(name)
} catch (e: NoSuchAlgorithmException) {
throw IllegalArgumentException("Unsupported hash algorithm: $name", e)
}
val hash = md.digest(text.toByteArray(Charsets.UTF_8))
// Two lowercase hex digits per byte — %02x formats a Byte as its
// unsigned two-digit hex value.
return hash.joinToString(separator = "", prefix = "", postfix = "") { "%02x".format(it) }
}
/**
* Computes every supported digest of [text] — the Kotlin shape of the
* Record the React island renders. Each hash is computed independently.
* The map preserves the canonical algorithm order (buildMap keeps
* insertion order through LinkedHashMap, exactly like the Java port).
*/
fun hashAll(text: String): Map<String, String> = buildMap {
for (algorithm in ALGORITHMS) {
put(algorithm, digest(text, algorithm))
}
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →