A modern I/O library that complements java.io and java.nio to make it much easier to access, store, and process your data.
—
Okio provides built-in hashing and cryptographic operations for data integrity and security. These operations can be performed on ByteString, Buffer, and streaming data through Sources and Sinks.
Compute hashes directly on ByteString instances.
/**
* Computes MD5 hash of ByteString content (deprecated)
* @return ByteString containing MD5 hash (16 bytes)
*/
abstract fun ByteString.md5(): ByteString
/**
* Computes SHA-1 hash of ByteString content (deprecated)
* @return ByteString containing SHA-1 hash (20 bytes)
*/
abstract fun ByteString.sha1(): ByteString
/**
* Computes SHA-256 hash of ByteString content
* @return ByteString containing SHA-256 hash (32 bytes)
*/
abstract fun ByteString.sha256(): ByteString
/**
* Computes SHA-512 hash of ByteString content
* @return ByteString containing SHA-512 hash (64 bytes)
*/
abstract fun ByteString.sha512(): ByteString
/**
* Computes HMAC-SHA1 with the given key (deprecated)
* @param key Secret key for HMAC computation
* @return ByteString containing HMAC-SHA1 (20 bytes)
*/
@Deprecated("Use hmacSha256 instead", ReplaceWith("hmacSha256(key)"))
abstract fun ByteString.hmacSha1(key: ByteString): ByteString
/**
* Computes HMAC-SHA256 with the given key
* @param key Secret key for HMAC computation
* @return ByteString containing HMAC-SHA256 (32 bytes)
*/
abstract fun ByteString.hmacSha256(key: ByteString): ByteString
/**
* Computes HMAC-SHA512 with the given key
* @param key Secret key for HMAC computation
* @return ByteString containing HMAC-SHA512 (64 bytes)
*/
abstract fun ByteString.hmacSha512(key: ByteString): ByteStringUsage Examples:
val data = "Hello, World!".encodeUtf8()
val key = "secret-key".encodeUtf8()
// Basic hashing
val md5 = data.md5()
println("MD5: ${md5.hex()}")
val sha256 = data.sha256()
println("SHA-256: ${sha256.hex()}")
val sha512 = data.sha512()
println("SHA-512: ${sha512.hex()}")
// HMAC with key
val hmac256 = data.hmacSha256(key)
println("HMAC-SHA256: ${hmac256.hex()}")
val hmac512 = data.hmacSha512(key)
println("HMAC-SHA512: ${hmac512.hex()}")Compute hashes on Buffer content without consuming the data.
/**
* Computes MD5 hash of Buffer content (deprecated)
* @return ByteString containing MD5 hash
*/
fun Buffer.md5(): ByteString
/**
* Computes SHA-1 hash of Buffer content (deprecated)
* @return ByteString containing SHA-1 hash
*/
fun Buffer.sha1(): ByteString
/**
* Computes SHA-256 hash of Buffer content
* @return ByteString containing SHA-256 hash
*/
fun Buffer.sha256(): ByteString
/**
* Computes SHA-512 hash of Buffer content
* @return ByteString containing SHA-512 hash
*/
fun Buffer.sha512(): ByteString
/**
* Computes HMAC-SHA1 of Buffer content (deprecated)
* @param key Secret key for HMAC computation
* @return ByteString containing HMAC-SHA1
*/
@Deprecated("Use hmacSha256 instead")
fun Buffer.hmacSha1(key: ByteString): ByteString
/**
* Computes HMAC-SHA256 of Buffer content
* @param key Secret key for HMAC computation
* @return ByteString containing HMAC-SHA256
*/
fun Buffer.hmacSha256(key: ByteString): ByteString
/**
* Computes HMAC-SHA512 of Buffer content
* @param key Secret key for HMAC computation
* @return ByteString containing HMAC-SHA512
*/
fun Buffer.hmacSha512(key: ByteString): ByteStringUsage Examples:
val buffer = Buffer()
buffer.writeUtf8("Hello, World!")
buffer.writeInt(42)
// Hash without consuming buffer data
val hash = buffer.sha256()
println("Buffer SHA-256: ${hash.hex()}")
println("Buffer still has ${buffer.size} bytes")
// HMAC of buffer content
val key = "secret".encodeUtf8()
val hmac = buffer.hmacSha256(key)
println("Buffer HMAC: ${hmac.hex()}")Compute hashes while reading from Sources or writing to Sinks.
/**
* Sink that computes a hash while writing data
* Wraps another sink and computes hash of all data written
*/
abstract class HashingSink : Sink {
/**
* Current hash value of all data written so far
*/
abstract val hash: ByteString
companion object {
/**
* Creates a HashingSink that computes MD5 (deprecated)
* @param sink Underlying sink to write to
* @return HashingSink that computes MD5
*/
fun md5(sink: Sink): HashingSink
/**
* Creates a HashingSink that computes SHA-1 (deprecated)
* @param sink Underlying sink to write to
* @return HashingSink that computes SHA-1
*/
fun sha1(sink: Sink): HashingSink
/**
* Creates a HashingSink that computes SHA-256
* @param sink Underlying sink to write to
* @return HashingSink that computes SHA-256
*/
fun sha256(sink: Sink): HashingSink
/**
* Creates a HashingSink that computes SHA-512
* @param sink Underlying sink to write to
* @return HashingSink that computes SHA-512
*/
fun sha512(sink: Sink): HashingSink
/**
* Creates a HashingSink that computes HMAC-SHA1 (deprecated)
* @param sink Underlying sink to write to
* @param key Secret key for HMAC computation
* @return HashingSink that computes HMAC-SHA1
*/
@Deprecated("Use hmacSha256 instead")
fun hmacSha1(sink: Sink, key: ByteString): HashingSink
/**
* Creates a HashingSink that computes HMAC-SHA256
* @param sink Underlying sink to write to
* @param key Secret key for HMAC computation
* @return HashingSink that computes HMAC-SHA256
*/
fun hmacSha256(sink: Sink, key: ByteString): HashingSink
/**
* Creates a HashingSink that computes HMAC-SHA512
* @param sink Underlying sink to write to
* @param key Secret key for HMAC computation
* @return HashingSink that computes HMAC-SHA512
*/
fun hmacSha512(sink: Sink, key: ByteString): HashingSink
}
}
/**
* Source that computes a hash while reading data
* Wraps another source and computes hash of all data read
*/
abstract class HashingSource : Source {
/**
* Current hash value of all data read so far
*/
abstract val hash: ByteString
companion object {
/**
* Creates a HashingSource that computes MD5 (deprecated)
* @param source Underlying source to read from
* @return HashingSource that computes MD5
*/
fun md5(source: Source): HashingSource
/**
* Creates a HashingSource that computes SHA-1 (deprecated)
* @param source Underlying source to read from
* @return HashingSource that computes SHA-1
*/
fun sha1(source: Source): HashingSource
/**
* Creates a HashingSource that computes SHA-256
* @param source Underlying source to read from
* @return HashingSource that computes SHA-256
*/
fun sha256(source: Source): HashingSource
/**
* Creates a HashingSource that computes SHA-512
* @param source Underlying source to read from
* @return HashingSource that computes SHA-512
*/
fun sha512(source: Source): HashingSource
/**
* Creates a HashingSource that computes HMAC-SHA1 (deprecated)
* @param source Underlying source to read from
* @param key Secret key for HMAC computation
* @return HashingSource that computes HMAC-SHA1
*/
@Deprecated("Use hmacSha256 instead")
fun hmacSha1(source: Source, key: ByteString): HashingSource
/**
* Creates a HashingSource that computes HMAC-SHA256
* @param source Underlying source to read from
* @param key Secret key for HMAC computation
* @return HashingSource that computes HMAC-SHA256
*/
fun hmacSha256(source: Source, key: ByteString): HashingSource
/**
* Creates a HashingSource that computes HMAC-SHA512
* @param source Underlying source to read from
* @param key Secret key for HMAC computation
* @return HashingSource that computes HMAC-SHA512
*/
fun hmacSha512(source: Source, key: ByteString): HashingSource
}
}Usage Examples:
// Hash while writing to file
val path = "/tmp/data.txt".toPath()
val fileSink = FileSystem.SYSTEM.sink(path)
val hashingSink = HashingSink.sha256(fileSink)
val bufferedSink = hashingSink.buffer()
bufferedSink.writeUtf8("Hello, World!")
bufferedSink.writeInt(42)
bufferedSink.close()
println("File SHA-256: ${hashingSink.hash.hex()}")
// Hash while reading from file
val fileSource = FileSystem.SYSTEM.source(path)
val hashingSource = HashingSource.sha256(fileSource)
val bufferedSource = hashingSource.buffer()
val content = bufferedSource.readUtf8()
val number = bufferedSource.readInt()
bufferedSource.close()
println("Content: $content, Number: $number")
println("Read SHA-256: ${hashingSource.hash.hex()}")
// HMAC while streaming
val key = "secret-key".encodeUtf8()
val hmacSink = HashingSink.hmacSha256(blackholeSink(), key)
val buffer = Buffer()
hmacSink.write(buffer.writeUtf8("Streaming data"), 13)
hmacSink.flush()
println("Streaming HMAC: ${hmacSink.hash.hex()}")Common patterns for verifying data integrity.
/**
* Verifies data integrity by comparing computed hash with expected hash
* @param expectedHash Expected hash value
* @param actualHash Computed hash value
* @return true if hashes match
*/
fun verifyHash(expectedHash: ByteString, actualHash: ByteString): Boolean =
expectedHash == actualHash
/**
* Verifies data integrity by comparing hex-encoded hashes
* @param expectedHex Expected hash as hex string
* @param actualHash Computed hash value
* @return true if hashes match
*/
fun verifyHashHex(expectedHex: String, actualHash: ByteString): Boolean =
expectedHex.lowercase() == actualHash.hex()Usage Examples:
// Download and verify file integrity
val expectedSha256 = "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3"
val downloadedData = "hello".encodeUtf8()
val actualHash = downloadedData.sha256()
val isValid = verifyHashHex(expectedSha256, actualHash)
println("File integrity: ${if (isValid) "VALID" else "INVALID"}")
// Verify HMAC for authentication
val message = "authenticated message".encodeUtf8()
val sharedKey = "shared-secret".encodeUtf8()
val computedHmac = message.hmacSha256(sharedKey)
// Later, verify the message
val receivedMessage = "authenticated message".encodeUtf8()
val receivedHmac = computedHmac // would come from sender
val verificationHmac = receivedMessage.hmacSha256(sharedKey)
val isAuthentic = verifyHash(receivedHmac, verificationHmac)
println("Message authentic: ${if (isAuthentic) "YES" else "NO"}")
// Stream large file and verify hash
val largeFile = "/tmp/large-file.dat".toPath()
val expectedHash = "expected-hash-value".decodeHex()
val source = FileSystem.SYSTEM.source(largeFile)
val hashingSource = HashingSource.sha256(source)
val buffer = Buffer()
// Read entire file through hashing source
while (!hashingSource.exhausted()) {
hashingSource.read(buffer, 8192)
buffer.clear() // Process data in chunks
}
hashingSource.close()
val fileValid = verifyHash(expectedHash, hashingSource.hash)
println("Large file integrity: ${if (fileValid) "VALID" else "INVALID"}")Install with Tessl CLI
npx tessl i tessl/maven-com-squareup-okio--okio-jvm