Symmetric Encryption¶
Symmetric encryption uses a single shared key to encrypt and decrypt data. The modes on this page – AES-CBC, AES-CTR, and AES-ECB – provide confidentiality only. They do not detect tampering or verify integrity of the ciphertext.
Prefer AEAD for new applications
For most use cases, AEAD algorithms like AES-GCM provide both encryption and authentication. Use the modes on this page only when a protocol or legacy system requires them.
Assumed imports
import dev.whyoleg.cryptography.*
import dev.whyoleg.cryptography.algorithms.*
val provider = CryptographyProvider.Default
Basic Usage¶
Get the algorithm, generate a key, create a cipher, and encrypt/decrypt. AES-CBC enables PKCS#7
padding by default, so plaintext of any length is accepted:
val aesCbc = provider.get(AES.CBC)
val key = aesCbc.keyGenerator().generateKey()
val cipher = key.cipher() // padding enabled by default
// Encrypt
val ciphertext = cipher.encrypt(plaintext = "secret message".encodeToByteArray())
// Decrypt
val plaintext = cipher.decrypt(ciphertext = ciphertext)
println(plaintext.decodeToString()) // secret message
Each call to encrypt generates a fresh random IV and prepends it to the output: [IV | ciphertext].
When you pass this to decrypt, the library splits it automatically.
The cipher is reusable – call encrypt and decrypt as many times as needed.
To disable padding (plaintext must then be a multiple of 16 bytes):
val cipher = key.cipher(padding = false)
Custom IV¶
By default, a random IV is generated and prepended to the ciphertext. If your protocol requires
a specific IV, use encryptWithIv and decryptWithIv:
val cipher = key.cipher()
val iv = ByteArray(16) // 16 bytes for AES-CBC
val ciphertext = cipher.encryptWithIv(
iv = iv,
plaintext = "secret".encodeToByteArray()
)
// With custom IV, the output does NOT contain the IV -- only the ciphertext
val plaintext = cipher.decryptWithIv(
iv = iv,
ciphertext = ciphertext
)
Warning
Reusing an IV with the same key weakens or breaks encryption security depending on the mode. Only use custom IVs when you have a reliable mechanism to guarantee uniqueness.
Streaming¶
For large data that does not fit in memory, use the kotlinx-io streaming API.
The cipher provides an ability to transform RawSource via
encryptingSource and decryptingSource
as well as RawSink with encryptingSink and decryptingSink:
val cipher = key.cipher()
// Pull-based: wrap a source
val encryptedSource: RawSource = cipher.encryptingSource(plaintextSource)
val decryptedSource: RawSource = cipher.decryptingSource(ciphertextSource)
// Push-based: wrap a sink
val encryptingSink: RawSink = cipher.encryptingSink(destinationSink)
val decryptingSink: RawSink = cipher.decryptingSink(plaintextSink)
Custom IV variants are also available: encryptingSourceWithIv,
encryptingSinkWithIv, decryptingSourceWithIv,
decryptingSinkWithIv.
Supported Algorithms¶
| Algorithm | JDK | WebCrypto | Apple | CryptoKit | OpenSSL3 |
|---|---|---|---|---|---|
| AES-CBC | |||||
| AES-CTR | |||||
| AES-ECB |
|||||
| AES-OFB |
|||||
| AES-CFB |
|||||
| AES-CFB8 |