Skip to content

Latest commit

 

History

History
341 lines (264 loc) · 13.5 KB

README.md

File metadata and controls

341 lines (264 loc) · 13.5 KB

Tink-KMM

Maven Central License: MIT test codecov badge-android badge-ios badge-silicon

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.

Why this library?

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)

Tink Primitives

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

Supported primitives and their implementations

Primitives supported by language

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 implementations supported by language

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

Compatibility

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.

Installation

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"
        }
    }
}

Usage

you can use Tink-KMM like java Tink.

Initialization

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()

Generate new keys and keysets

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

Serialize and Deserialize

Serialize with KeysetWriter

Cleartext
val writer = BinaryKeysetWriter()

// 1. write keyset to writer
handle.writeCleartext(writer)

// 2. get ByteArray from writer and save serialized somewhere
val serialized = writer.write()
NoSecret
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()

Deserialize with KeysetReader

Binary
// 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)

Obtaining and using primitives

AEAD

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)

DeterministicAEAD

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)

HybridAEAD

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)

MAC

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)

Signature

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)

Swift(Optional)

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)