This is a repositoy of Google/Tink Mapper for KMM(Kotlin Multiplatform Mobile)
This wrapper library allows you to use Tink Primitive Encryption in your Kotlin Multiplatform Mobile project.
KMM currently does not have a Crypto Library that can be used as a de facto standard.
Of course, we can implement encryption using the expect/actual modifier.
But, CCCrypto has a limitation of supported algorithm.(e.g, it can not be use AES-GCM)
Primitive | Interfaces |
---|---|
Authenticated Encryption with Associated Data (AEAD) | AEAD |
Streaming AEAD | StreamingAEAD |
Deterministic AEAD | DeterministicAEAD |
Message Authentication Code (MAC) | MAC |
Pseudo Random Function Family (PRF) | Prf, PrfSet |
Hybrid encryption | HybridEncrypt, HybridDecrypt |
Digital signatures | PublicKeySign, PublicKeyVerify |
Primitive | Java | Objective-C | Tink-KMM |
---|---|---|---|
AEAD | yes | yes | yes |
Streaming AEAD | yes | no | no |
Deterministic AEAD | yes | yes | yes |
MAC | yes | yes | yes |
PRF | yes | no | no |
Digital signatures | yes | yes | yes |
Hybrid encryption | yes | yes | yes |
Primitive | Implementation | Java | Objective-C | Tink-KMM |
---|---|---|---|---|
AEAD | AES-GCM | yes | yes | yes |
AES-GCM-SIV | yes | no | no | |
AES-CTR-HMAC | yes | yes | yes | |
AES-EAX | yes | yes | yes | |
KMS Envelope | yes | no | no | |
CHACHA20-POLY1305 | yes | no | no | |
XCHACHA20-POLY1305 | yes | yes | yes | |
Streaming AEAD | AES-GCM-HKDF-STREAMING | yes | no | no |
AES-CTR-HMAC-STREAMING | yes | no | no | |
Deterministic AEAD | AES-SIV | yes | yes | yes |
MAC | HMAC-SHA2 | yes | yes | yes |
AES-CMAC | yes | yes | yes | |
PRF | HKDF-SHA2 | yes | no | no |
HMAC-SHA2 | yes | no | no | |
AES-CMAC | yes | no | no | |
Digital Signatures | ECDSA over NIST curves | yes | yes | yes |
Ed25519 | yes | yes | yes | |
RSA-SSA-PKCS1 | yes | yes | yes | |
RSA-SSA-PSS | yes | yes | yes | |
Hybrid Encryption | HPKE | yes | no | no |
ECIES with AEAD and HKDF | yes | yes | yes | |
ECIES with DeterministicAEAD and HKDF | yes | no | no |
Version | Kotlin | Tink-android | Tink-ObjC |
---|---|---|---|
0.0.1 | 1.8.20 | 1.7.0 | 1.7.0 |
0.0.2 ~ 0.0.3 | 1.8.21 | 1.7.0 | 1.7.0 |
0.0.4 | 1.8.22 | 1.7.0 | 1.7.0 |
0.0.5 | 1.9.0 | 1.7.0 | 1.7.0 |
0.0.6 | 1.9.10 | 1.7.0 | 1.7.0 |
0.0.7 | 1.9.21 | 1.7.0 | 1.7.0 |
Warning
Tink-ObjC 1.7.0 has not been released to CocoaPods yet.
https://github.com/google/tink/issues/583
https://github.com/google/tink/issues/641
so, you need to build Tink-ObjC 1.7.0 by yourself.
you can use my fork RyuNen344/tink, and Makefile can be used as a reference about how to build Tink-ObjC 1.7.0.
add the following to your settings.gradle
and build.gradle
file:
repositories {
mavenCentral()
}
kotlin {
// if you want to use without CocoaPods, you need to link with your Tink.framework like below.
iosX64 {
binaries {
framework {
linkerOpts(
listOf(
"-framework",
"Tink",
"-Fpath/to/Tink.framework",
"-rpath",
"path/to/Tink.framework",
"-ObjC",
)
)
}
}
}
commonMain {
dependencies {
implementation "io.github.ryunen344.tink:tink:$tink_kmm_version"
}
}
}
you can use Tink-KMM like java Tink.
import io.github.ryunen344.tink.aead.AeadConfig
import io.github.ryunen344.tink.aead.register
import io.github.ryunen344.tink.daead.DeterministicAeadConfig
import io.github.ryunen344.tink.daead.register
import io.github.ryunen344.tink.hybrid.HybridConfig
import io.github.ryunen344.tink.hybrid.register
import io.github.ryunen344.tink.mac.MacConfig
import io.github.ryunen344.tink.mac.register
import io.github.ryunen344.tink.signature.SignatureConfig
import io.github.ryunen344.tink.signature.register
AeadConfig.register()
DeterministicAeadConfig.register()
HybridConfig.register()
MacConfig.register()
SignatureConfig.register()
import io.github.ryunen344.tink.KeyTemplateSet
import io.github.ryunen344.tink.KeysetHandleGenerator
import io.github.ryunen344.tink.generateNew
KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_GCM.template())
Note Defined available key templates in KeyTemplateSet
val writer = BinaryKeysetWriter()
// 1. write keyset to writer
handle.writeCleartext(writer)
// 2. get ByteArray from writer and save serialized somewhere
val serialized = writer.write()
val writer = BinaryKeysetWriter()
// 1. write keyset to writer
handle.writeNoSecret(writer)
// 2. get ByteArray from writer(if keyset has secret key, throw exception)
val serialized = writer.write()
// read with AEAD
val masterKey: AEAD
KeysetHandleGenerator.read(serialized, masterKey)
// read ByteArray from somewhere
KeysetHandleGenerator.readClearText(BinaryKeysetReader(serialized))
// read json string from somewhere
KeysetHandleGenerator.readClearText(JsonKeysetReader("json string"))
// read ByteArray with secret key from somewhere
KeysetHandleGenerator.readNoSecret(serialized)
import io.github.ryunen344.tink.aead.Aead
import io.github.ryunen344.tink.KeyTemplateSet
import io.github.ryunen344.tink.KeysetHandleGenerator
import io.github.ryunen344.tink.generateNew
import io.github.ryunen344.tink.getPrimitive
// 1. Generate the key material.
val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_GCM.template())
// 2. Get the primitive.
val aead = handle.getPrimitive(Aead::class)
// 3. Use the primitive to encrypt a plaintext,
val ciphertext = aead.encrypt(plaintext, associatedData)
// ... or to decrypt a ciphertext.
val decrypted = aead.decrypt(ciphertext, associatedData)
import io.github.ryunen344.tink.daead.DeterministicAead
import io.github.ryunen344.tink.KeyTemplateSet
import io.github.ryunen344.tink.KeysetHandleGenerator
import io.github.ryunen344.tink.generateNew
import io.github.ryunen344.tink.getPrimitive
// 1. Generate the key material.
val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_GCM.template())
// 2. Get the primitive.
val daead = handle.getPrimitive(DeterministicAead::class)
// 3. Use the primitive to encrypt a plaintext,
val ciphertext = daead.encrypt(plaintext, associatedData)
// ... or to decrypt a ciphertext.
val decrypted = daead.decrypt(ciphertext, associatedData)
import io.github.ryunen344.tink.hybrid.HybridEncrypt
import io.github.ryunen344.tink.hybrid.HybridDecrypt
import io.github.ryunen344.tink.KeyTemplateSet
import io.github.ryunen344.tink.KeysetHandleGenerator
import io.github.ryunen344.tink.generateNew
import io.github.ryunen344.tink.getPrimitive
import io.github.ryunen344.tink.publicKeysetHandle
// 1. Generate the key material.
val privateKeysetHandle = KeysetHandleGenerator.generateNew(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM.template())
val publicKeysetHandle = privateKeysetHandle.publicKeysetHandle()
// 2. Get the primitives.
val hybridEncrypt = publicKeysetHandle.getPrimitive(HybridEncrypt::class)
val hybridDecrypt = privateKeysetHandle.getPrimitive(HybridDecrypt::class)
// 3. Use the primitives to encrypt and decrypt.
val ciphertext = hybridEncrypt.encrypt(plaintext, contextInfo)
val decrypted = hybridDecrypt.decrypt(ciphertext, contextInfo)
import io.github.ryunen344.tink.mac.Mac
import io.github.ryunen344.tink.KeyTemplateSet
import io.github.ryunen344.tink.KeysetHandleGenerator
import io.github.ryunen344.tink.generateNew
import io.github.ryunen344.tink.getPrimitive
// 1. Generate the key material.
val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.HMAC_SHA256_128BITTAG.template())
// 2. Get the primitive.
val mac = handle.getPrimitive(Mac::class)
// 3. Use the primitive to compute a tag.
val tag = mac.computeMac(plaintext)
// ... or to verify a tag.
mac.verifyMac(tag, plaintext)
import io.github.ryunen344.tink.signature.PublicKeySign
import io.github.ryunen344.tink.signature.PublicKeyVerify
import io.github.ryunen344.tink.KeyTemplateSet
import io.github.ryunen344.tink.KeysetHandleGenerator
import io.github.ryunen344.tink.generateNew
import io.github.ryunen344.tink.getPrimitive
import io.github.ryunen344.tink.publicKeysetHandle
// 1. Generate the key material.
val privateHandle = KeysetHandleGenerator.generateNew(KeyTemplateSet.ECDSA_P256.template())
val publicHandle = privateHandle.publicKeysetHandle()
// 2. Get the primitive.
val signer = privateHandle.getPrimitive(PublicKeySign::class)
val verifier = publicHandle.getPrimitive(PublicKeyVerify::class)
// 3. Use the primitive to sign a message.
val signature = signer.sign(message)
// ... or to verify a signature.
verifier.verify(signature, message)
This library also supports be used in Swift directory.
try! AeadConfig.companion.register()
let template = try! KeyTemplateSet.aes256Gcm.template()
let handle = try! KeysetHandleGenerator.companion.generateNew(keyTemplate: template)
let aead = try! KeysetHandleKt.getPrimitive(handle, kClass: TinkPrimitiveKt.aead) as! Aead
let ciphertext = try! aead.encrypt(plaintext, with: associatedData)
let decrypted = try! aead.decrypt(ciphertext, with: associatedData)