├── .ruby-version ├── version.txt ├── .xcode-version ├── scripts ├── danger │ └── Dangerfile ├── utilities └── doctor ├── .github ├── CODEOWNERS ├── codeql │ └── codeql-config.yml ├── actions │ ├── xcode-select │ │ └── action.yml │ ├── konan │ │ └── action.yml │ └── sdkman │ │ └── action.yml ├── release.yml └── workflows │ ├── codeql.yml │ ├── lint.yml │ ├── release-please.yml │ └── test.yml ├── .gitmodules ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── iosApp ├── iosApp │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── iOSApp.swift │ ├── Info.plist │ └── ContentView.swift ├── iosApp.xcodeproj │ ├── project.xcworkspace │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── iosApp.xcscheme ├── build.gradle.kts └── iosAppTests │ └── iosAppTests.swift ├── .sdkmanrc ├── tink ├── src │ ├── commonMain │ │ └── kotlin │ │ │ └── io │ │ │ └── github │ │ │ └── ryunen344 │ │ │ └── tink │ │ │ ├── KeyTemplate.kt │ │ │ ├── TinkPrimitive.kt │ │ │ ├── KeysetReader.kt │ │ │ ├── BinaryKeysetWriter.kt │ │ │ ├── exception │ │ │ ├── IOException.kt │ │ │ ├── JsonException.kt │ │ │ └── GeneralSecurityException.kt │ │ │ ├── BinaryKeysetReader.kt │ │ │ ├── KeysetWriter.kt │ │ │ ├── mac │ │ │ ├── MacConfig.kt │ │ │ └── Mac.kt │ │ │ ├── aead │ │ │ ├── AeadConfig.kt │ │ │ └── Aead.kt │ │ │ ├── hybrid │ │ │ ├── HybridConfig.kt │ │ │ ├── HybridEncrypt.kt │ │ │ └── HybridDecrypt.kt │ │ │ ├── signature │ │ │ ├── SignatureConfig.kt │ │ │ ├── PublicKeySign.kt │ │ │ └── PublicKeyVerify.kt │ │ │ ├── daead │ │ │ ├── DeterministicAeadConfig.kt │ │ │ └── DeterministicAead.kt │ │ │ ├── JsonKeysetReader.kt │ │ │ ├── config │ │ │ └── TinkConfig.kt │ │ │ ├── KeysetHandle.kt │ │ │ ├── KeysetHandleGenerator.kt │ │ │ └── KeyTemplateSet.kt │ ├── nativeInterop │ │ └── cinterop │ │ │ └── Tink.def │ ├── androidMain │ │ └── kotlin │ │ │ └── io │ │ │ └── github │ │ │ └── ryunen344 │ │ │ └── tink │ │ │ ├── KeyTemplate.kt │ │ │ ├── exception │ │ │ ├── IOException.kt │ │ │ ├── JsonException.kt │ │ │ └── GeneralSecurityException.kt │ │ │ ├── KeysetReader.kt │ │ │ ├── BinaryKeysetReader.kt │ │ │ ├── KeyTemplateSet.kt │ │ │ ├── KeysetWriter.kt │ │ │ ├── mac │ │ │ ├── MacConfig.kt │ │ │ └── AndroidMac.kt │ │ │ ├── aead │ │ │ ├── AeadConfig.kt │ │ │ └── AndroidAead.kt │ │ │ ├── config │ │ │ └── TinkConfig.kt │ │ │ ├── hybrid │ │ │ ├── HybridConfig.kt │ │ │ ├── AndroidHybridEncrypt.kt │ │ │ └── AndroidHybridDecrypt.kt │ │ │ ├── signature │ │ │ ├── SignatureConfig.kt │ │ │ ├── AndroidPublicKeySign.kt │ │ │ └── AndroidPublicKeyVerify.kt │ │ │ ├── daead │ │ │ ├── DeterministicAeadConfig.kt │ │ │ └── AndroidDeterministicAead.kt │ │ │ ├── JsonKeysetWriter.kt │ │ │ ├── JsonKeysetReader.kt │ │ │ ├── BinaryKeysetWriter.kt │ │ │ ├── KeysetHandleGenerator.kt │ │ │ └── KeysetHandle.kt │ ├── iosMain │ │ └── kotlin │ │ │ └── io │ │ │ └── github │ │ │ └── ryunen344 │ │ │ └── tink │ │ │ ├── KeyTemplate.kt │ │ │ ├── KeysetReader.kt │ │ │ ├── exception │ │ │ ├── IOException.kt │ │ │ ├── JsonException.kt │ │ │ └── GeneralSecurityException.kt │ │ │ ├── KeysetWriter.kt │ │ │ ├── BinaryKeysetWriter.kt │ │ │ ├── util │ │ │ ├── CPointer.kt │ │ │ ├── MemScope.kt │ │ │ ├── NSError.kt │ │ │ └── NSData.kt │ │ │ ├── mac │ │ │ ├── MacConfig.kt │ │ │ └── DarwinMac.kt │ │ │ ├── aead │ │ │ ├── AeadConfig.kt │ │ │ └── DarwinAead.kt │ │ │ ├── config │ │ │ └── TinkConfig.kt │ │ │ ├── hybrid │ │ │ ├── HybridConfig.kt │ │ │ ├── DarwinHybridEncrypt.kt │ │ │ └── DarwinHybridDecrypt.kt │ │ │ ├── BinaryKeysetReader.kt │ │ │ ├── signature │ │ │ ├── SignatureConfig.kt │ │ │ ├── DarwinPublicKeyVerify.kt │ │ │ └── DarwinPublicKeySign.kt │ │ │ ├── daead │ │ │ ├── DeterministicAeadConfig.kt │ │ │ └── DarwinDeterministicAead.kt │ │ │ ├── JsonKeysetReader.kt │ │ │ ├── TinkPrimitive.kt │ │ │ ├── KeysetHandleGenerator.kt │ │ │ ├── KeysetHandle.kt │ │ │ └── KeyTemplateSet.kt │ ├── commonTest │ │ └── kotlin │ │ │ └── io │ │ │ └── github │ │ │ └── ryunen344 │ │ │ └── tink │ │ │ ├── aead │ │ │ ├── AeadConfigTest.kt │ │ │ └── AeadTest.kt │ │ │ ├── KeyTemplateTest.kt │ │ │ ├── KeysetWriterTest.kt │ │ │ ├── daead │ │ │ └── DeterministicAeadTest.kt │ │ │ ├── mac │ │ │ └── MacTest.kt │ │ │ └── hybrid │ │ │ └── HybridTest.kt │ ├── iosTest │ │ └── kotlin │ │ │ └── io │ │ │ └── github │ │ │ └── ryunen344 │ │ │ └── tink │ │ │ └── KeysetReaderTest.kt │ └── androidUnitTest │ │ └── kotlin │ │ └── io │ │ └── github │ │ └── ryunen344 │ │ └── tink │ │ └── KeysetReaderTest.kt └── build.gradle.kts ├── Gemfile ├── .bundle └── config ├── Framework ├── Podfile ├── Podfile.lock └── Makefile ├── .idea └── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── .editorconfig ├── .yamllint ├── Makefile ├── .gitignore ├── gradle.properties ├── LICENSE ├── renovate.json5 ├── settings.gradle.kts ├── gradlew.bat ├── Gemfile.lock ├── CHANGELOG.md ├── gradlew └── README.md /.ruby-version: -------------------------------------------------------------------------------- 1 | 3.3.6 2 | -------------------------------------------------------------------------------- /version.txt: -------------------------------------------------------------------------------- 1 | 0.0.7 2 | -------------------------------------------------------------------------------- /.xcode-version: -------------------------------------------------------------------------------- 1 | 14.3.1 2 | -------------------------------------------------------------------------------- /scripts/danger/Dangerfile: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @RyuNen344 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "TinkStub"] 2 | path = TinkStub 3 | url = https://github.com/RyuNen344/tink.git 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RyuNen344/tink-kmm/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /iosApp/iosApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } -------------------------------------------------------------------------------- /.sdkmanrc: -------------------------------------------------------------------------------- 1 | # Enable auto-env through the sdkman_auto_env config 2 | # Add key=value pairs of SDKs to use below 3 | java=17.0.7-tem 4 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/KeyTemplate.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | expect class KeyTemplate 4 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/TinkPrimitive.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | interface TinkPrimitive 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | gem 'cocoapods', '1.16.2' 6 | gem 'xcpretty', '0.4.0' 7 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/KeysetReader.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | expect open class KeysetReader 4 | -------------------------------------------------------------------------------- /tink/src/nativeInterop/cinterop/Tink.def: -------------------------------------------------------------------------------- 1 | depends = Security 2 | language = Objective-C 3 | package = com.google.crypto.tink 4 | modules = Tink 5 | -------------------------------------------------------------------------------- /iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } -------------------------------------------------------------------------------- /.bundle/config: -------------------------------------------------------------------------------- 1 | --- 2 | BUNDLE_PATH: ".bundle/vendor/bundle" 3 | BUNDLE_BIN: ".bundle/vendor/bin" 4 | BUNDLE_RETRY: "3" 5 | BUNDLE_JOBS: "4" 6 | BUNDLE_CLEAN: "true" 7 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/BinaryKeysetWriter.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | expect class BinaryKeysetWriter() : KeysetWriter 4 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/exception/IOException.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.exception 2 | 3 | expect class IOException : Exception 4 | -------------------------------------------------------------------------------- /Framework/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '11.0' 2 | 3 | install! 'cocoapods', integrate_targets: false 4 | use_frameworks! 5 | 6 | target 'Tink' do 7 | pod 'Tink', '1.6.1' 8 | end 9 | -------------------------------------------------------------------------------- /iosApp/iosApp/iOSApp.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | @main 4 | struct iOSApp: App { 5 | var body: some Scene { 6 | WindowGroup { 7 | ContentView() 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/KeyTemplate.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | actual typealias KeyTemplate = com.google.crypto.tink.KeyTemplate 4 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/exception/JsonException.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.exception 2 | 3 | expect class JsonException : RuntimeException 4 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/exception/IOException.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.exception 2 | 3 | actual typealias IOException = java.io.IOException 4 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/BinaryKeysetReader.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | expect class BinaryKeysetReader(bytes: ByteArray) : KeysetReader 4 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/KeysetWriter.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | expect abstract class KeysetWriter { 4 | abstract fun write(): ByteArray 5 | } 6 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/exception/GeneralSecurityException.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.exception 2 | 3 | expect class GeneralSecurityException : Exception 4 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/exception/JsonException.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.exception 2 | 3 | actual typealias JsonException = com.google.gson.JsonParseException 4 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/KeyTemplate.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import com.google.crypto.tink.TINKKeyTemplate 4 | 5 | actual typealias KeyTemplate = TINKKeyTemplate 6 | -------------------------------------------------------------------------------- /.github/codeql/codeql-config.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL config" 2 | queries: 3 | - uses: security-experimental 4 | - uses: security-extended 5 | - uses: security-and-quality 6 | paths-ignore: 7 | - "vendor" 8 | - "TinkStub" 9 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/KeysetReader.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import com.google.crypto.tink.TINKKeysetReader 4 | 5 | actual open class KeysetReader(val native: TINKKeysetReader) 6 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/exception/GeneralSecurityException.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.exception 2 | 3 | actual typealias GeneralSecurityException = java.security.GeneralSecurityException 4 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/exception/IOException.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.exception 2 | 3 | actual class IOException(message: String? = null, cause: Throwable? = null) : Exception(message, cause) 4 | -------------------------------------------------------------------------------- /iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/exception/JsonException.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.exception 2 | 3 | actual class JsonException(message: String? = null, cause: Throwable? = null) : RuntimeException(message, cause) 4 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/exception/GeneralSecurityException.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.exception 2 | 3 | actual class GeneralSecurityException(message: String? = null, cause: Throwable? = null) : Exception(message, cause) 4 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/KeysetWriter.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import platform.Foundation.NSData 4 | 5 | actual abstract class KeysetWriter { 6 | var value: NSData? = null 7 | actual abstract fun write(): ByteArray 8 | } 9 | -------------------------------------------------------------------------------- /tink/src/commonTest/kotlin/io/github/ryunen344/tink/aead/AeadConfigTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.aead 2 | 3 | import kotlin.test.Test 4 | 5 | class AeadConfigTest { 6 | @Test 7 | fun test_invoke_register() { 8 | AeadConfig.register() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/KeysetReader.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | internal typealias NativeKeysetReader = com.google.crypto.tink.KeysetReader 4 | 5 | actual open class KeysetReader(private val native: NativeKeysetReader) : NativeKeysetReader by native 6 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/BinaryKeysetWriter.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import io.github.ryunen344.tink.util.toByteArray 4 | 5 | actual class BinaryKeysetWriter : KeysetWriter() { 6 | override fun write(): ByteArray = value?.toByteArray() ?: ByteArray(0) 7 | } 8 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/BinaryKeysetReader.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | typealias NativeBinaryKeysetReader = com.google.crypto.tink.BinaryKeysetReader 4 | 5 | actual class BinaryKeysetReader actual constructor(bytes: ByteArray) : 6 | KeysetReader(NativeBinaryKeysetReader.withBytes(bytes)) 7 | -------------------------------------------------------------------------------- /iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/mac/MacConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.mac 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | class MacConfig { 6 | companion object 7 | } 8 | 9 | @Throws(GeneralSecurityException::class) 10 | expect fun MacConfig.Companion.register() 11 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/aead/AeadConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.aead 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | class AeadConfig { 6 | companion object 7 | } 8 | 9 | @Throws(GeneralSecurityException::class) 10 | expect fun AeadConfig.Companion.register() 11 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/KeyTemplateSet.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import com.google.crypto.tink.KeyTemplates 4 | import io.github.ryunen344.tink.exception.GeneralSecurityException 5 | 6 | @Throws(GeneralSecurityException::class) 7 | actual fun KeyTemplateSet.template(): KeyTemplate = KeyTemplates.get(value) 8 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/KeysetWriter.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | internal typealias NativeKeysetWriter = com.google.crypto.tink.KeysetWriter 4 | 5 | actual abstract class KeysetWriter(private val native: NativeKeysetWriter) : NativeKeysetWriter by native { 6 | actual abstract fun write(): ByteArray 7 | } 8 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/hybrid/HybridConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.hybrid 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | class HybridConfig { 6 | companion object 7 | } 8 | 9 | @Throws(GeneralSecurityException::class) 10 | expect fun HybridConfig.Companion.register() 11 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/signature/SignatureConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.signature 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | class SignatureConfig { 6 | companion object 7 | } 8 | 9 | @Throws(GeneralSecurityException::class) 10 | expect fun SignatureConfig.Companion.register() 11 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/mac/MacConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.mac 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeMacConfig = com.google.crypto.tink.mac.MacConfig 6 | 7 | @Throws(GeneralSecurityException::class) 8 | actual fun MacConfig.Companion.register() = NativeMacConfig.register() 9 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/daead/DeterministicAeadConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.daead 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | class DeterministicAeadConfig { 6 | companion object 7 | } 8 | 9 | @Throws(GeneralSecurityException::class) 10 | expect fun DeterministicAeadConfig.Companion.register() 11 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/aead/AeadConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.aead 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeAeadConfig = com.google.crypto.tink.aead.AeadConfig 6 | 7 | @Throws(GeneralSecurityException::class) 8 | actual fun AeadConfig.Companion.register() = NativeAeadConfig.register() 9 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/config/TinkConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.config 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeTinkConfig = com.google.crypto.tink.config.TinkConfig 6 | 7 | @Throws(GeneralSecurityException::class) 8 | actual fun TinkConfig.Companion.register() = NativeTinkConfig.register() 9 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/signature/PublicKeySign.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.signature 2 | 3 | import io.github.ryunen344.tink.TinkPrimitive 4 | import io.github.ryunen344.tink.exception.GeneralSecurityException 5 | 6 | interface PublicKeySign : TinkPrimitive { 7 | @Throws(GeneralSecurityException::class) 8 | fun sign(data: ByteArray): ByteArray 9 | } 10 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/hybrid/HybridConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.hybrid 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeHybridConfig = com.google.crypto.tink.hybrid.HybridConfig 6 | 7 | @Throws(GeneralSecurityException::class) 8 | actual fun HybridConfig.Companion.register() = NativeHybridConfig.register() 9 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/JsonKeysetReader.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import io.github.ryunen344.tink.exception.JsonException 4 | 5 | @Suppress("UnusedPrivateProperty") 6 | expect class JsonKeysetReader 7 | @Throws(JsonException::class) 8 | constructor(bytes: ByteArray) : KeysetReader { 9 | @Throws(JsonException::class) 10 | constructor(json: String) 11 | } 12 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/signature/PublicKeyVerify.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.signature 2 | 3 | import io.github.ryunen344.tink.TinkPrimitive 4 | import io.github.ryunen344.tink.exception.GeneralSecurityException 5 | 6 | interface PublicKeyVerify : TinkPrimitive { 7 | @Throws(GeneralSecurityException::class) 8 | fun verify(signature: ByteArray, data: ByteArray) 9 | } 10 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/hybrid/HybridEncrypt.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.hybrid 2 | 3 | import io.github.ryunen344.tink.TinkPrimitive 4 | import io.github.ryunen344.tink.exception.GeneralSecurityException 5 | 6 | interface HybridEncrypt : TinkPrimitive { 7 | @Throws(GeneralSecurityException::class) 8 | fun encrypt(plaintext: ByteArray, contextInfo: ByteArray): ByteArray 9 | } 10 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/signature/SignatureConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.signature 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeSignatureConfig = com.google.crypto.tink.signature.SignatureConfig 6 | 7 | @Throws(GeneralSecurityException::class) 8 | actual fun SignatureConfig.Companion.register() = NativeSignatureConfig.register() 9 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/hybrid/HybridDecrypt.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.hybrid 2 | 3 | import io.github.ryunen344.tink.TinkPrimitive 4 | import io.github.ryunen344.tink.exception.GeneralSecurityException 5 | 6 | interface HybridDecrypt : TinkPrimitive { 7 | @Throws(GeneralSecurityException::class) 8 | fun decrypt(ciphertext: ByteArray, contextInfo: ByteArray): ByteArray 9 | } 10 | -------------------------------------------------------------------------------- /Framework/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - rapidjson (1.1.0) 3 | - Tink (1.6.1): 4 | - rapidjson (~> 1.1.0) 5 | 6 | DEPENDENCIES: 7 | - Tink 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - rapidjson 12 | - Tink 13 | 14 | SPEC CHECKSUMS: 15 | rapidjson: 926ddeea70d7a0987b6d746cd9fa51f165467cd3 16 | Tink: 6bc1e1c5381a750ca2ee7e897cc3ee448bfe175d 17 | 18 | PODFILE CHECKSUM: 4dfa7b69ec446116da44c614453bfef4bdf27e7c 19 | 20 | COCOAPODS: 1.12.0 21 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/daead/DeterministicAeadConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.daead 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeDeterministicAeadConfig = com.google.crypto.tink.daead.DeterministicAeadConfig 6 | 7 | @Throws(GeneralSecurityException::class) 8 | actual fun DeterministicAeadConfig.Companion.register() = NativeDeterministicAeadConfig.register() 9 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/JsonKeysetWriter.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import java.io.ByteArrayOutputStream 4 | 5 | typealias NativeJsonKeysetWriter = com.google.crypto.tink.JsonKeysetWriter 6 | 7 | class JsonKeysetWriter( 8 | private val os: ByteArrayOutputStream = ByteArrayOutputStream(), 9 | ) : KeysetWriter(NativeJsonKeysetWriter.withOutputStream(os)) { 10 | override fun write(): ByteArray = os.toByteArray() 11 | } 12 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/mac/Mac.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.mac 2 | 3 | import io.github.ryunen344.tink.TinkPrimitive 4 | import io.github.ryunen344.tink.exception.GeneralSecurityException 5 | 6 | interface Mac : TinkPrimitive { 7 | @Throws(GeneralSecurityException::class) 8 | fun computeMac(data: ByteArray): ByteArray 9 | 10 | @Throws(GeneralSecurityException::class) 11 | fun verifyMac(mac: ByteArray, data: ByteArray) 12 | } 13 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/config/TinkConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.config 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | @Deprecated("Use per-primitive configs, e.g., AeadConfig, HybridConfig, etc.") 6 | class TinkConfig { 7 | companion object 8 | } 9 | 10 | @Deprecated("Use per-primitive configs, e.g., AeadConfig, HybridConfig, etc.") 11 | @Throws(GeneralSecurityException::class) 12 | expect fun TinkConfig.Companion.register() 13 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/util/CPointer.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.util 2 | 3 | import kotlinx.cinterop.ByteVar 4 | import kotlinx.cinterop.CPointer 5 | import kotlinx.cinterop.Pinned 6 | import kotlinx.cinterop.addressOf 7 | import kotlinx.cinterop.pin 8 | 9 | private val emptyAddressByte = ByteArray(1).pin().addressOf(0) 10 | 11 | internal val Pinned.startAddressOf: CPointer 12 | get() = if (get().isNotEmpty()) addressOf(0) else emptyAddressByte 13 | -------------------------------------------------------------------------------- /.github/actions/xcode-select/action.yml: -------------------------------------------------------------------------------- 1 | name: "select xcode" 2 | description: "select xcode defined at .xcode-version" 3 | runs: 4 | using: "composite" 5 | steps: 6 | - name: read .xcode-version 7 | shell: bash 8 | run: | 9 | echo "XCODE_VERSION=$(cat .xcode-version)" >> $GITHUB_ENV 10 | 11 | - name: execute xcode-select 12 | shell: bash 13 | run: | 14 | echo "select $XCODE_VERSION" 15 | sudo xcode-select --switch "/Applications/Xcode_$XCODE_VERSION.app" 16 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/aead/Aead.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.aead 2 | 3 | import io.github.ryunen344.tink.TinkPrimitive 4 | import io.github.ryunen344.tink.exception.GeneralSecurityException 5 | 6 | interface Aead : TinkPrimitive { 7 | @Throws(GeneralSecurityException::class) 8 | fun encrypt(plaintext: ByteArray, associatedData: ByteArray): ByteArray 9 | 10 | @Throws(GeneralSecurityException::class) 11 | fun decrypt(ciphertext: ByteArray, associatedData: ByteArray): ByteArray 12 | } 13 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/JsonKeysetReader.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import io.github.ryunen344.tink.exception.JsonException 4 | 5 | typealias NativeJsonKeysetReader = com.google.crypto.tink.JsonKeysetReader 6 | 7 | actual class JsonKeysetReader 8 | @Throws(JsonException::class) 9 | actual constructor(bytes: ByteArray) : 10 | KeysetReader(NativeJsonKeysetReader.withBytes(bytes)) { 11 | @Throws(JsonException::class) 12 | actual constructor(json: String) : this(json.encodeToByteArray()) 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root=true 2 | 3 | [*] 4 | charset=utf-8 5 | end_of_line=lf 6 | indent_size=4 7 | indent_style=space 8 | insert_final_newline=true 9 | max_line_length=100 10 | tab_width=4 11 | 12 | [{*.bash,*.sh,*.zsh}] 13 | indent_size=2 14 | tab_width=2 15 | 16 | [{*.har,*.json,*.json5}] 17 | indent_size=2 18 | 19 | [{*.toml,*.yaml,*.yml}] 20 | indent_size=2 21 | 22 | [*.{ts,tsx,js}] 23 | max_line_length=120 24 | 25 | [*.{kt,kts}] 26 | max_line_length=120 27 | 28 | [*.mustache] 29 | insert_final_newline=false 30 | 31 | [Makefile] 32 | indent_style=tab 33 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/BinaryKeysetWriter.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import java.io.ByteArrayOutputStream 4 | 5 | typealias NativeBinaryKeysetWriter = com.google.crypto.tink.BinaryKeysetWriter 6 | 7 | actual class BinaryKeysetWriter( 8 | private val os: ByteArrayOutputStream = ByteArrayOutputStream(), 9 | ) : KeysetWriter(NativeBinaryKeysetWriter.withOutputStream(os)) { 10 | 11 | actual constructor() : this(ByteArrayOutputStream()) 12 | 13 | override fun write(): ByteArray = os.toByteArray() 14 | } 15 | -------------------------------------------------------------------------------- /.github/actions/konan/action.yml: -------------------------------------------------------------------------------- 1 | name: "setup konan cache" 2 | description: "chache .konan directory" 3 | runs: 4 | using: "composite" 5 | steps: 6 | - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4 7 | id: cache-sdkman 8 | with: 9 | path: | 10 | ~/.konan 11 | key: v1-konan-${{ runner.os }}-${{ hashFiles('build.gradle.kts') }}-${{ hashFiles('tink/build.gradle.kts') }} 12 | restore-keys: | 13 | v1-konan-${{ runner.os }}-${{ hashFiles('build.gradle.kts') }} 14 | v1-konan-${{ runner.os }} 15 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/daead/DeterministicAead.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.daead 2 | 3 | import io.github.ryunen344.tink.TinkPrimitive 4 | import io.github.ryunen344.tink.exception.GeneralSecurityException 5 | 6 | interface DeterministicAead : TinkPrimitive { 7 | @Throws(GeneralSecurityException::class) 8 | fun encryptDeterministically(plaintext: ByteArray, associatedData: ByteArray): ByteArray 9 | 10 | @Throws(GeneralSecurityException::class) 11 | fun decryptDeterministically(ciphertext: ByteArray, associatedData: ByteArray): ByteArray 12 | } 13 | -------------------------------------------------------------------------------- /tink/src/iosTest/kotlin/io/github/ryunen344/tink/KeysetReaderTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import kotlin.test.Test 4 | 5 | class KeysetReaderTest { 6 | @Test 7 | fun test_read() { 8 | // runCatching { 9 | // AeadConfig().register() 10 | // val aead = KeysetHandleGenerator 11 | // .generateNew(KeyTemplateSet.AES256_GCM.template()) 12 | // .getPrimitive(Aead::class) 13 | // KeysetHandleGenerator.read(TINKKeysetReader(), aead) 14 | // }.onFailure { 15 | // it.printStackTrace() 16 | // } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | extends: default 4 | 5 | rules: 6 | braces: 7 | level: warning 8 | max-spaces-inside: 1 9 | brackets: 10 | level: warning 11 | max-spaces-inside: 1 12 | colons: 13 | level: warning 14 | commas: 15 | level: warning 16 | comments: disable 17 | comments-indentation: disable 18 | document-start: disable 19 | empty-lines: 20 | level: warning 21 | hyphens: 22 | level: warning 23 | indentation: 24 | level: warning 25 | indent-sequences: consistent 26 | line-length: 27 | max: 180 28 | level: warning 29 | allow-non-breakable-inline-mappings: true 30 | truthy: disable 31 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/util/MemScope.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.util 2 | 3 | import kotlinx.cinterop.MemScope 4 | import kotlinx.cinterop.ObjCObjectVar 5 | import kotlinx.cinterop.alloc 6 | import kotlinx.cinterop.memScoped 7 | import kotlinx.cinterop.value 8 | import platform.Foundation.NSError 9 | 10 | internal inline fun memScopedInstance( 11 | block: MemScope.(error: ObjCObjectVar) -> T, 12 | onError: (NSError) -> Unit = {}, 13 | ): T = memScoped { 14 | val error = alloc>() 15 | val instance = block(error) 16 | error.value?.let(onError) 17 | instance 18 | } 19 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/util/NSError.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.util 2 | 3 | import platform.Foundation.NSError 4 | import kotlin.native.internal.ObjCErrorException 5 | 6 | internal fun NSError.asThrowable(): Throwable { 7 | val message = buildString { 8 | append(domain ?: "NSError") 9 | append(" ") 10 | append("code [$code]") 11 | userInfo.forEach { 12 | appendLine("{${it.key} = ${it.value}}") 13 | } 14 | } 15 | return Throwable( 16 | message = message 17 | ) 18 | } 19 | 20 | val Throwable.isNSError: Boolean 21 | get() = this is ObjCErrorException 22 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/util/NSData.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.util 2 | 3 | import kotlinx.cinterop.convert 4 | import kotlinx.cinterop.usePinned 5 | import platform.Foundation.NSData 6 | import platform.Foundation.dataWithBytes 7 | import platform.posix.memcpy 8 | 9 | internal inline fun ByteArray.toNSData(): NSData = usePinned { 10 | NSData.dataWithBytes( 11 | bytes = it.startAddressOf, 12 | length = size.convert() 13 | ) 14 | } 15 | 16 | internal inline fun NSData.toByteArray(): ByteArray = ByteArray(length.toInt()).apply { 17 | usePinned { 18 | memcpy(it.startAddressOf, bytes, length) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PODS_ROOT = ./Framework 2 | STUB_ROOT = ./TinkStub 3 | 4 | .PHONY: clean 5 | clean: 6 | @rm -rf $(PODS_ROOT)/Tink.xcframework 7 | @rm -rf "$(STUB_ROOT)/objc/bazel-*" 8 | 9 | .PHONY: bootstrap-submodule 10 | bootstrap-submodule: 11 | @git submodule init 12 | @git submodule update 13 | 14 | .PHONY: build-bazel 15 | build-bazel: bootstrap-submodule 16 | @cd $(STUB_ROOT)/objc && bazelisk --output_base=./../../build/bazel build --disk_cache=./../../build/bazel --apple_platform_type=ios --xcode_version="$(cat ./../.xcode-version)" //:Tink && cd ../.. 17 | 18 | .PHONY: archive 19 | archive: build-bazel 20 | @unzip -o $(STUB_ROOT)/objc/bazel-bin/Tink.xcframework.zip -d $(PODS_ROOT) 21 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/signature/AndroidPublicKeySign.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.signature 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativePublicKeySign = com.google.crypto.tink.PublicKeySign 6 | 7 | class AndroidPublicKeySign(private val native: NativePublicKeySign) : PublicKeySign, NativePublicKeySign by native { 8 | constructor(handle: com.google.crypto.tink.KeysetHandle) : 9 | this(handle.getPrimitive(NativePublicKeySign::class.java)) 10 | 11 | @Throws(GeneralSecurityException::class) 12 | override fun sign(data: ByteArray): ByteArray = 13 | native.sign(data) 14 | } 15 | -------------------------------------------------------------------------------- /.github/release.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#example-configuration 2 | changelog: 3 | exclude: 4 | labels: 5 | - ignore-for-release 6 | authors: 7 | - octocat 8 | categories: 9 | - title: ⚠️ Breaking Changes 10 | labels: 11 | - breaking-change 12 | - title: 🎉 Exciting New Features 13 | labels: 14 | - enhancement 15 | - title: 🐛 Bug fixes 16 | labels: 17 | - bug 18 | - title: 🌲 Dependency updates 19 | labels: 20 | - dependencies 21 | - dependency 22 | - title: Other Changes 23 | labels: 24 | - "*" 25 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/mac/MacConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.mac 2 | 3 | import com.google.crypto.tink.TINKConfig 4 | import com.google.crypto.tink.TINKMacConfig 5 | import io.github.ryunen344.tink.exception.GeneralSecurityException 6 | import io.github.ryunen344.tink.util.asThrowable 7 | import io.github.ryunen344.tink.util.memScopedInstance 8 | import kotlinx.cinterop.ptr 9 | 10 | @Throws(GeneralSecurityException::class) 11 | actual fun MacConfig.Companion.register(): Unit = 12 | memScopedInstance( 13 | block = { TINKConfig.registerConfig(TINKMacConfig(it.ptr), it.ptr) }, 14 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 15 | ) 16 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/hybrid/AndroidHybridEncrypt.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.hybrid 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeHybridEncrypt = com.google.crypto.tink.HybridEncrypt 6 | 7 | class AndroidHybridEncrypt(private val native: NativeHybridEncrypt) : HybridEncrypt, NativeHybridEncrypt by native { 8 | constructor(handle: com.google.crypto.tink.KeysetHandle) : 9 | this(handle.getPrimitive(NativeHybridEncrypt::class.java)) 10 | 11 | @Throws(GeneralSecurityException::class) 12 | override fun encrypt(plaintext: ByteArray, contextInfo: ByteArray): ByteArray = 13 | native.encrypt(plaintext, contextInfo) 14 | } 15 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/aead/AeadConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.aead 2 | 3 | import com.google.crypto.tink.TINKAeadConfig 4 | import com.google.crypto.tink.TINKConfig 5 | import io.github.ryunen344.tink.exception.GeneralSecurityException 6 | import io.github.ryunen344.tink.util.asThrowable 7 | import io.github.ryunen344.tink.util.memScopedInstance 8 | import kotlinx.cinterop.ptr 9 | 10 | @Throws(GeneralSecurityException::class) 11 | actual fun AeadConfig.Companion.register(): Unit = 12 | memScopedInstance( 13 | block = { TINKConfig.registerConfig(config = TINKAeadConfig(it.ptr), error = it.ptr) }, 14 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 15 | ) 16 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/config/TinkConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.config 2 | 3 | import com.google.crypto.tink.TINKAllConfig 4 | import com.google.crypto.tink.TINKConfig 5 | import io.github.ryunen344.tink.exception.GeneralSecurityException 6 | import io.github.ryunen344.tink.util.asThrowable 7 | import io.github.ryunen344.tink.util.memScopedInstance 8 | import kotlinx.cinterop.ptr 9 | 10 | @Throws(GeneralSecurityException::class) 11 | actual fun TinkConfig.Companion.register(): Unit = 12 | memScopedInstance( 13 | block = { TINKConfig.registerConfig(config = TINKAllConfig(it.ptr), error = it.ptr) }, 14 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 15 | ) 16 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/hybrid/AndroidHybridDecrypt.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.hybrid 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeHybridDecrypt = com.google.crypto.tink.HybridDecrypt 6 | 7 | class AndroidHybridDecrypt(private val native: NativeHybridDecrypt) : HybridDecrypt, NativeHybridDecrypt by native { 8 | constructor(handle: com.google.crypto.tink.KeysetHandle) : 9 | this(handle.getPrimitive(NativeHybridDecrypt::class.java)) 10 | 11 | @Throws(GeneralSecurityException::class) 12 | override fun decrypt(ciphertext: ByteArray, contextInfo: ByteArray): ByteArray = 13 | native.decrypt(ciphertext, contextInfo) 14 | } 15 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/hybrid/HybridConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.hybrid 2 | 3 | import com.google.crypto.tink.TINKConfig 4 | import com.google.crypto.tink.TINKHybridConfig 5 | import io.github.ryunen344.tink.exception.GeneralSecurityException 6 | import io.github.ryunen344.tink.util.asThrowable 7 | import io.github.ryunen344.tink.util.memScopedInstance 8 | import kotlinx.cinterop.ptr 9 | 10 | @Throws(GeneralSecurityException::class) 11 | actual fun HybridConfig.Companion.register(): Unit = 12 | memScopedInstance( 13 | block = { TINKConfig.registerConfig(config = TINKHybridConfig(it.ptr), error = it.ptr) }, 14 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 15 | ) 16 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/BinaryKeysetReader.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import com.google.crypto.tink.TINKBinaryKeysetReader 4 | import io.github.ryunen344.tink.exception.IOException 5 | import io.github.ryunen344.tink.util.asThrowable 6 | import io.github.ryunen344.tink.util.memScopedInstance 7 | import io.github.ryunen344.tink.util.toNSData 8 | import kotlinx.cinterop.ptr 9 | 10 | actual class BinaryKeysetReader actual constructor(bytes: ByteArray) : 11 | KeysetReader( 12 | native = memScopedInstance( 13 | block = { TINKBinaryKeysetReader(serializedKeyset = bytes.toNSData(), error = it.ptr) }, 14 | onError = { throw IOException(cause = it.asThrowable()) } 15 | ) 16 | ) 17 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/signature/AndroidPublicKeyVerify.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.signature 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativePublicKeyVerify = com.google.crypto.tink.PublicKeyVerify 6 | 7 | class AndroidPublicKeyVerify( 8 | private val native: NativePublicKeyVerify, 9 | ) : PublicKeyVerify, NativePublicKeyVerify by native { 10 | 11 | constructor(handle: com.google.crypto.tink.KeysetHandle) : 12 | this(handle.getPrimitive(NativePublicKeyVerify::class.java)) 13 | 14 | @Throws(GeneralSecurityException::class) 15 | override fun verify(signature: ByteArray, data: ByteArray) = 16 | native.verify(signature, data) 17 | } 18 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/signature/SignatureConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.signature 2 | 3 | import com.google.crypto.tink.TINKConfig 4 | import com.google.crypto.tink.TINKSignatureConfig 5 | import io.github.ryunen344.tink.exception.GeneralSecurityException 6 | import io.github.ryunen344.tink.util.asThrowable 7 | import io.github.ryunen344.tink.util.memScopedInstance 8 | import kotlinx.cinterop.ptr 9 | 10 | @Throws(GeneralSecurityException::class) 11 | actual fun SignatureConfig.Companion.register(): Unit = 12 | memScopedInstance( 13 | block = { TINKConfig.registerConfig(config = TINKSignatureConfig(it.ptr), error = it.ptr) }, 14 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 15 | ) 16 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/mac/AndroidMac.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.mac 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeMac = com.google.crypto.tink.Mac 6 | 7 | class AndroidMac(private val native: NativeMac) : Mac, NativeMac by native { 8 | constructor(handle: com.google.crypto.tink.KeysetHandle) : 9 | this(handle.getPrimitive(NativeMac::class.java)) 10 | 11 | @Throws(GeneralSecurityException::class) 12 | override fun computeMac(data: ByteArray): ByteArray = 13 | native.computeMac(data) 14 | 15 | @Throws(GeneralSecurityException::class) 16 | override fun verifyMac(mac: ByteArray, data: ByteArray) = 17 | native.verifyMac(mac, data) 18 | } 19 | -------------------------------------------------------------------------------- /tink/src/commonTest/kotlin/io/github/ryunen344/tink/KeyTemplateTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import io.github.ryunen344.tink.daead.DeterministicAeadConfig 4 | import io.github.ryunen344.tink.daead.register 5 | import io.github.ryunen344.tink.hybrid.HybridConfig 6 | import io.github.ryunen344.tink.hybrid.register 7 | import io.github.ryunen344.tink.signature.SignatureConfig 8 | import io.github.ryunen344.tink.signature.register 9 | import kotlin.test.Test 10 | 11 | class KeyTemplateTest { 12 | @Test 13 | fun test_KeyTemplateSet() { 14 | HybridConfig.register() 15 | DeterministicAeadConfig.register() 16 | SignatureConfig.register() 17 | KeyTemplateSet.values().map(KeyTemplateSet::template).forEach(::println) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/daead/DeterministicAeadConfig.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.daead 2 | 3 | import com.google.crypto.tink.TINKConfig 4 | import com.google.crypto.tink.TINKDeterministicAeadConfig 5 | import io.github.ryunen344.tink.exception.GeneralSecurityException 6 | import io.github.ryunen344.tink.util.asThrowable 7 | import io.github.ryunen344.tink.util.memScopedInstance 8 | import kotlinx.cinterop.ptr 9 | 10 | @Throws(GeneralSecurityException::class) 11 | actual fun DeterministicAeadConfig.Companion.register(): Unit = 12 | memScopedInstance( 13 | block = { TINKConfig.registerConfig(config = TINKDeterministicAeadConfig(it.ptr), error = it.ptr) }, 14 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 15 | ) 16 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/KeysetHandle.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | import io.github.ryunen344.tink.exception.IOException 5 | import kotlin.reflect.KClass 6 | 7 | expect class KeysetHandle 8 | 9 | @Throws(GeneralSecurityException::class, IOException::class) 10 | expect fun KeysetHandle.writeNoSecret(writer: KeysetWriter) 11 | 12 | @Throws(GeneralSecurityException::class, IOException::class) 13 | expect fun KeysetHandle.writeCleartext(writer: KeysetWriter) 14 | 15 | @Throws(GeneralSecurityException::class) 16 | expect fun

KeysetHandle.getPrimitive(kClass: KClass

): P 17 | 18 | @Throws(GeneralSecurityException::class) 19 | expect fun KeysetHandle.publicKeysetHandle(): KeysetHandle 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # general 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # intellij 7 | *.iml 8 | /.idea/.gitignore 9 | /.idea/.name 10 | /.idea/caches 11 | /.idea/libraries 12 | /.idea/modules.xml 13 | /.idea/workspace.xml 14 | /.idea/navEditor.xml 15 | /.idea/assetWizardSettings.xml 16 | /.idea/compiler.xml 17 | /.idea/git_toolbox_prj.xml 18 | /.idea/gradle.xml 19 | /.idea/kotlinc.xml 20 | /.idea/misc.xml 21 | /.idea/vcs.xml 22 | /.idea/shelf/ 23 | /.idea/jarRepositories.xml 24 | /.idea/markdown.xml 25 | /.idea/deploymentTargetDropDown.xml 26 | /.idea/androidTestResultsUserPreferences.xml 27 | 28 | # gradle 29 | .gradle 30 | /local.properties 31 | 32 | # xcode 33 | xcuserdata/ 34 | DerivedData/ 35 | 36 | # bundler 37 | .bundle/vendor/ 38 | 39 | # Tink 40 | Framework/Pods 41 | Framework/Tink.xcframework 42 | 43 | # build 44 | build/ 45 | .build/ 46 | releases/ 47 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/aead/AndroidAead.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.aead 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeAead = com.google.crypto.tink.Aead 6 | 7 | class AndroidAead(private val native: NativeAead) : Aead, NativeAead by native { 8 | constructor(handle: com.google.crypto.tink.KeysetHandle) : 9 | this(handle.getPrimitive(NativeAead::class.java)) 10 | 11 | @Throws(GeneralSecurityException::class) 12 | override fun encrypt(plaintext: ByteArray, associatedData: ByteArray): ByteArray = 13 | native.encrypt(plaintext, associatedData) 14 | 15 | @Throws(GeneralSecurityException::class) 16 | override fun decrypt(ciphertext: ByteArray, associatedData: ByteArray): ByteArray = 17 | native.decrypt(ciphertext, associatedData) 18 | } 19 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | #Gradle 2 | org.gradle.jvmargs=-Xmx4096M -XX:+UseParallelGC -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx4096M" 3 | org.gradle.parallel=true 4 | org.gradle.caching=true 5 | 6 | #Kotlin 7 | kotlin.code.style=official 8 | 9 | #Android 10 | android.useAndroidX=true 11 | android.enableJetifier=false 12 | android.nonTransitiveRClass=true 13 | android.defaults.buildfeatures.aidl=false 14 | android.defaults.buildfeatures.buildconfig=true 15 | android.defaults.buildfeatures.databinding"=false 16 | android.defaults.buildfeatures.renderscript=false 17 | android.defaults.buildfeatures.resvalues=false 18 | android.defaults.buildfeatures.shaders=false 19 | android.defaults.buildfeatures.viewbinding=false 20 | android.library.defaults.buildfeatures.androidresources=false 21 | 22 | #MPP 23 | kotlin.mpp.enableCInteropCommonization=true 24 | kotlin.native.cacheKind=none 25 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/JsonKeysetReader.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import com.google.crypto.tink.TINKJSONKeysetReader 4 | import io.github.ryunen344.tink.exception.JsonException 5 | import io.github.ryunen344.tink.util.asThrowable 6 | import io.github.ryunen344.tink.util.memScopedInstance 7 | import io.github.ryunen344.tink.util.toNSData 8 | import kotlinx.cinterop.ptr 9 | 10 | actual class JsonKeysetReader 11 | @Throws(JsonException::class) 12 | actual constructor(bytes: ByteArray) : KeysetReader( 13 | native = memScopedInstance( 14 | block = { TINKJSONKeysetReader(serializedKeyset = bytes.toNSData(), error = it.ptr) }, 15 | onError = { throw JsonException(cause = it.asThrowable()) } 16 | ) 17 | ) { 18 | @Throws(JsonException::class) 19 | actual constructor(json: String) : this(json.encodeToByteArray()) 20 | } 21 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/KeysetHandleGenerator.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import io.github.ryunen344.tink.aead.Aead 4 | import io.github.ryunen344.tink.exception.GeneralSecurityException 5 | 6 | class KeysetHandleGenerator { 7 | companion object 8 | } 9 | 10 | @Throws(GeneralSecurityException::class) 11 | expect fun KeysetHandleGenerator.Companion.generateNew(keyTemplate: KeyTemplate): KeysetHandle 12 | 13 | @Throws(GeneralSecurityException::class) 14 | expect fun KeysetHandleGenerator.Companion.read(reader: KeysetReader, aead: Aead): KeysetHandle 15 | 16 | @Throws(GeneralSecurityException::class) 17 | expect fun KeysetHandleGenerator.Companion.readClearText(reader: KeysetReader): KeysetHandle 18 | 19 | @Throws(GeneralSecurityException::class) 20 | expect fun KeysetHandleGenerator.Companion.readNoSecret(keyset: ByteArray): KeysetHandle 21 | -------------------------------------------------------------------------------- /iosApp/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.openbakery.xcode-plugin") 3 | } 4 | 5 | xcodebuild { 6 | version = File(rootDir, ".xcode-version").readText().trim() 7 | scheme = "iosApp" 8 | target = "iosAppTests" 9 | setProjectFile("iosApp.xcodeproj") 10 | destination( 11 | closureOf { 12 | platform = "iOS Simulator" 13 | name = "iPhone 14 Pro" 14 | os = "16.4" 15 | } 16 | ) 17 | 18 | // xcode-pluginがSYMROOTをいじるためCONFIGURATION_BUILD_DIRをSYMROOTと揃えることで帳尻を合わせる 19 | additionalParameters = listOf( 20 | "CONFIGURATION_BUILD_DIR=\$SYMROOT", 21 | ) 22 | } 23 | 24 | tasks.withType().configureEach { 25 | dependsOn(":tink:assembleTinKMMDebugXCFramework") 26 | } 27 | 28 | tasks.withType().configureEach { 29 | dependsOn(":tink:assembleTinKMMDebugXCFramework") 30 | } 31 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/daead/AndroidDeterministicAead.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.daead 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | internal typealias NativeDeterministicAead = com.google.crypto.tink.DeterministicAead 6 | 7 | class AndroidDeterministicAead( 8 | private val native: NativeDeterministicAead, 9 | ) : DeterministicAead, NativeDeterministicAead by native { 10 | 11 | constructor(handle: com.google.crypto.tink.KeysetHandle) : 12 | this(handle.getPrimitive(NativeDeterministicAead::class.java)) 13 | 14 | @Throws(GeneralSecurityException::class) 15 | override fun encryptDeterministically(plaintext: ByteArray, associatedData: ByteArray): ByteArray = 16 | native.encryptDeterministically(plaintext, associatedData) 17 | 18 | @Throws(GeneralSecurityException::class) 19 | override fun decryptDeterministically(ciphertext: ByteArray, associatedData: ByteArray): ByteArray = 20 | native.decryptDeterministically(ciphertext, associatedData) 21 | } 22 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/TinkPrimitive.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import io.github.ryunen344.tink.aead.Aead 4 | import io.github.ryunen344.tink.daead.DeterministicAead 5 | import io.github.ryunen344.tink.hybrid.HybridDecrypt 6 | import io.github.ryunen344.tink.hybrid.HybridEncrypt 7 | import io.github.ryunen344.tink.mac.Mac 8 | import io.github.ryunen344.tink.signature.PublicKeySign 9 | import io.github.ryunen344.tink.signature.PublicKeyVerify 10 | import kotlin.reflect.KClass 11 | 12 | val aead: KClass 13 | get() = Aead::class 14 | 15 | val deterministicAead: KClass 16 | get() = DeterministicAead::class 17 | 18 | val hybridDecrypt: KClass 19 | get() = HybridDecrypt::class 20 | 21 | val hybridEncrypt: KClass 22 | get() = HybridEncrypt::class 23 | 24 | val mac: KClass 25 | get() = Mac::class 26 | 27 | val publicKeySign: KClass 28 | get() = PublicKeySign::class 29 | 30 | val publicKeyVerify: KClass 31 | get() = PublicKeyVerify::class 32 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/KeysetHandleGenerator.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import com.google.crypto.tink.CleartextKeysetHandle 4 | import io.github.ryunen344.tink.aead.Aead 5 | import io.github.ryunen344.tink.aead.NativeAead 6 | import io.github.ryunen344.tink.exception.GeneralSecurityException 7 | 8 | @Throws(GeneralSecurityException::class) 9 | actual fun KeysetHandleGenerator.Companion.generateNew(keyTemplate: KeyTemplate): KeysetHandle = 10 | KeysetHandle.generateNew(keyTemplate) 11 | 12 | @Throws(GeneralSecurityException::class) 13 | actual fun KeysetHandleGenerator.Companion.read( 14 | reader: KeysetReader, 15 | aead: Aead, 16 | ): KeysetHandle = KeysetHandle.read(reader, aead as NativeAead) 17 | 18 | @Throws(GeneralSecurityException::class) 19 | actual fun KeysetHandleGenerator.Companion.readClearText(reader: KeysetReader): KeysetHandle = 20 | CleartextKeysetHandle.read(reader) 21 | 22 | @Throws(GeneralSecurityException::class) 23 | actual fun KeysetHandleGenerator.Companion.readNoSecret(keyset: ByteArray): KeysetHandle = 24 | KeysetHandle.readNoSecret(keyset) 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 RyuNen344 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /scripts/utilities: -------------------------------------------------------------------------------- 1 | readonly _ESCAPE_="$(printf '\033')" 2 | readonly _WARNING_="$(printf '\U26A0')" 3 | readonly _CHECK_MARK_="$(printf '\U2705')" 4 | readonly _TADA_="$(printf '\U1F389')" 5 | readonly _REPO_ROOT_ABS_PATH_="$(git rev-parse --show-toplevel)" 6 | 7 | checking_command() { 8 | local -r cmd="$1" 9 | 10 | sleep 1 11 | 12 | if type "$cmd" >/dev/null 2>&1; then 13 | info "$_CHECK_MARK_ ${_ESCAPE_}[32m$cmd${_ESCAPE_}[m is found" 14 | return 0 15 | elif type "$cmd.bat" >/dev/null 2>&1; then 16 | info "$_CHECK_MARK_ ${_ESCAPE_}[32m$cmd${_ESCAPE_}[m is found" 17 | return 0 18 | else 19 | warn "$_WARNING_ ${_ESCAPE_}[33m$cmd${_ESCAPE_}[m is not found" 20 | return 1 21 | fi 22 | } 23 | 24 | fatal() { 25 | err "$@" 26 | exit 1 27 | } 28 | 29 | err() { 30 | echo "${_ESCAPE_}[31m[ERROR]${_ESCAPE_}[m $@" 1>&2 31 | } 32 | 33 | warn() { 34 | echo "${_ESCAPE_}[33m[WARN]${_ESCAPE_}[m $@" 1>&2 35 | } 36 | 37 | info() { 38 | echo "${_ESCAPE_}[32m[INFO]${_ESCAPE_}[m $@" 1>&2 39 | } 40 | 41 | run() { 42 | echo "Executing... $@" 1>&2 43 | "$@" 44 | } 45 | 46 | go_to_repo_root() { 47 | cd "$_REPO_ROOT_ABS_PATH_" 48 | } 49 | -------------------------------------------------------------------------------- /iosApp/iosAppTests/iosAppTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | final class iosAppTests: XCTestCase { 4 | 5 | override func setUpWithError() throws { 6 | // Put setup code here. This method is called before the invocation of each test method in the class. 7 | } 8 | 9 | override func tearDownWithError() throws { 10 | // Put teardown code here. This method is called after the invocation of each test method in the class. 11 | } 12 | 13 | func testExample() throws { 14 | // This is an example of a functional test case. 15 | // Use XCTAssert and related functions to verify your tests produce the correct results. 16 | // Any test you write for XCTest can be annotated as throws and async. 17 | // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. 18 | // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. 19 | } 20 | 21 | func testPerformanceExample() throws { 22 | // This is an example of a performance test case. 23 | measure { 24 | // Put the code you want to measure the time of here. 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /.github/actions/sdkman/action.yml: -------------------------------------------------------------------------------- 1 | name: "install sdkman" 2 | description: "setup sdkman and install via .sdkmanrc" 3 | runs: 4 | using: "composite" 5 | steps: 6 | - uses: actions/cache/restore@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4 7 | id: cache-sdkman 8 | with: 9 | path: | 10 | ~/.sdkman 11 | key: v1-sdkman-${{ runner.os }}-${{ hashFiles('.sdkmanrc') }} 12 | 13 | - if: ${{ steps.cache-sdkman.outputs.cache-hit != 'true' }} 14 | name: install sdkman 15 | shell: bash 16 | run: | 17 | export SDKMAN_DIR="$HOME/.sdkman" && curl -s "https://get.sdkman.io" | bash 18 | 19 | - name: setup sdkman 20 | shell: bash 21 | run: | 22 | source "$HOME/.sdkman/bin/sdkman-init.sh" 23 | sdkman_auto_answer=true 24 | sdkman_selfupdate_enable=false 25 | sdk env install 26 | echo "JAVA_HOME=$HOME/.sdkman/candidates/java/current" >> $GITHUB_ENV 27 | 28 | - if: ${{ steps.cache-sdkman.outputs.cache-hit != 'true' }} 29 | uses: actions/cache/save@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4 30 | with: 31 | path: | 32 | ~/.sdkman 33 | key: v1-sdkman-${{ runner.os }}-${{ hashFiles('.sdkmanrc') }} 34 | -------------------------------------------------------------------------------- /renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: "https://docs.renovatebot.com/renovate-schema.json", 3 | extends: [ 4 | "config:base", 5 | // https://github.com/whitesource/merge-confidence 6 | "github>whitesource/merge-confidence:beta" 7 | ], 8 | "labels": [ 9 | "dependencies" 10 | ], 11 | // https://docs.renovatebot.com/configuration-options/#automergestrategy 12 | "automergeStrategy": "squash", 13 | packageRules: [ 14 | { 15 | "groupName": "android gradle plugin", 16 | "matchPackageNames": [ 17 | "com.android.application", 18 | "com.android.library", 19 | "com.android.settings", 20 | "com.android.tools.build:gradle" 21 | ], 22 | }, 23 | { 24 | "groupName": "detekt", 25 | "matchPackagePatterns": [ 26 | "^io\\.gitlab\\.arturbosch.detekt" 27 | ], 28 | }, 29 | { 30 | groupName: "gh-actions", 31 | matchManagers: [ 32 | "github-actions" 33 | ], 34 | matchDatasources: [ 35 | "github-tags" 36 | ], 37 | matchUpdateTypes: [ 38 | "minor", 39 | "patch" 40 | ], 41 | automerge: true, 42 | platformAutomerge: true, 43 | pinDigests: true, 44 | }, 45 | ], 46 | } 47 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 2 | pluginManagement { 3 | resolutionStrategy { 4 | eachPlugin { 5 | if (requested.id.id == "org.openbakery.xcode-plugin") { 6 | useModule("org.openbakery:xcode-plugin:0.23.1.30") 7 | } 8 | } 9 | } 10 | repositories { 11 | google() 12 | mavenCentral() 13 | maven(url = "https://openbakery.org/repository/") { 14 | content { 15 | includeGroup("org.openbakery") 16 | } 17 | } 18 | gradlePluginPortal() 19 | } 20 | } 21 | 22 | dependencyResolutionManagement { 23 | // https://youtrack.jetbrains.com/issue/KT-51379 24 | repositoriesMode.set(RepositoriesMode.PREFER_PROJECT) 25 | repositories { 26 | google() 27 | mavenCentral() 28 | } 29 | } 30 | 31 | plugins { 32 | id("com.gradle.enterprise").version("3.18.1") 33 | } 34 | 35 | gradleEnterprise { 36 | if (System.getenv("CI") != null) { 37 | buildScan { 38 | termsOfServiceUrl = "https://gradle.com/terms-of-service" 39 | termsOfServiceAgree = "yes" 40 | } 41 | } 42 | } 43 | 44 | rootProject.name = "Tink-KMM" 45 | include(":iosApp") 46 | include(":tink") 47 | -------------------------------------------------------------------------------- /tink/src/androidUnitTest/kotlin/io/github/ryunen344/tink/KeysetReaderTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import io.github.ryunen344.tink.aead.AeadConfig 4 | import io.github.ryunen344.tink.aead.register 5 | import io.github.ryunen344.tink.signature.SignatureConfig 6 | import io.github.ryunen344.tink.signature.register 7 | import kotlin.test.Test 8 | 9 | class KeysetReaderTest { 10 | @Test 11 | fun test_read() { 12 | runCatching { 13 | AeadConfig.register() 14 | val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_GCM.template()) 15 | val writer = JsonKeysetWriter() 16 | handle.writeCleartext(writer) 17 | println(writer.write().decodeToString()) 18 | }.onFailure { 19 | it.printStackTrace() 20 | } 21 | } 22 | 23 | @Test 24 | fun test_signature() { 25 | SignatureConfig.register() 26 | 27 | val privateHandle = KeysetHandleGenerator.generateNew(KeyTemplateSet.ECDSA_P256.template()) 28 | val publicHandle = privateHandle.publicKeysetHandle() 29 | 30 | JsonKeysetWriter().run { 31 | privateHandle.writeCleartext(this) 32 | println(write().decodeToString()) 33 | } 34 | 35 | JsonKeysetWriter().run { 36 | publicHandle.writeNoSecret(this) 37 | println(write().decodeToString()) 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /scripts/doctor: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | . "$(git rev-parse --show-toplevel)/scripts/utilities" 5 | 6 | go_to_repo_root 7 | 8 | declare -a missing_required_components=() 9 | info 'check command...' 10 | 11 | if ! checking_command 'java'; then 12 | missing_required_components+=('java') 13 | warn "Please install JDK and export it to PATH" 14 | fi 15 | 16 | # until release Tink 1.7.0 at CocoaPods 17 | if ! checking_command 'bazel'; then 18 | missing_required_components+=('bazel') 19 | warn "Please install bazel and export it to PATH" 20 | fi 21 | 22 | if ! checking_command 'ruby'; then 23 | missing_required_components+=('ruby') 24 | warn "Please install ruby" 25 | fi 26 | 27 | if ! checking_command 'bundler'; then 28 | missing_required_components+=('bundler') 29 | warn "Please gem install bundler" 30 | fi 31 | 32 | if ! checking_command 'go'; then 33 | missing_required_components+=('go') 34 | warn "Please install go" 35 | fi 36 | 37 | if ! checking_command 'reviewdog'; then 38 | missing_required_components+=('reviewdog') 39 | warn "Please go install github.com/reviewdog/reviewdog/cmd/reviewdog@latest" 40 | fi 41 | 42 | sleep 1 43 | 44 | if ((0 < ${#missing_required_components[@]})); then 45 | err '---------' 46 | err "${missing_required_components[*]} are required. Please install them to complete setup." 47 | fatal '---------' 48 | fi 49 | 50 | info "Found all required commands. ${_TADA_}" 51 | -------------------------------------------------------------------------------- /Framework/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_ROOT = $(cd $(dirname $0); cd ..; pwd) 2 | PODS_ROOT = ./Pods 3 | PODS_PROJECT = $(PODS_ROOT)/Pods.xcodeproj 4 | SYMROOT = $(PODS_ROOT)/Build 5 | IPHONEOS_DEPLOYMENT_TARGET = 9.0 6 | 7 | .PHONY: clean 8 | clean: 9 | @rm -rf Pods 10 | @rm -rf Tink.xcframework 11 | 12 | .PHONY: bootstrap-cocoapods 13 | bootstrap-cocoapods: clean 14 | @bundle install 15 | @bundle exec pod install 16 | 17 | .PHONY: build-cocoapods 18 | build-cocoapods: bootstrap-cocoapods 19 | @xcodebuild -project "$(PODS_PROJECT)" \ 20 | -sdk iphoneos \ 21 | -configuration Release \ 22 | -alltargets \ 23 | ONLY_ACTIVE_ARCH=NO \ 24 | ENABLE_TESTABILITY=NO \ 25 | SYMROOT="$(SYMROOT)" \ 26 | CLANG_ENABLE_MODULE_DEBUGGING=NO \ 27 | BITCODE_GENERATION_MODE=bitcode \ 28 | IPHONEOS_DEPLOYMENT_TARGET="$(IPHONEOS_DEPLOYMENT_TARGET)" | bundle exec xcpretty -c 29 | @xcodebuild -project "$(PODS_PROJECT)" \ 30 | -sdk iphonesimulator \ 31 | -configuration Release \ 32 | -alltargets \ 33 | ONLY_ACTIVE_ARCH=NO \ 34 | ENABLE_TESTABILITY=NO \ 35 | SYMROOT="$(SYMROOT)" \ 36 | CLANG_ENABLE_MODULE_DEBUGGING=NO \ 37 | BITCODE_GENERATION_MODE=bitcode \ 38 | IPHONEOS_DEPLOYMENT_TARGET="$(IPHONEOS_DEPLOYMENT_TARGET)" | bundle exec xcpretty -c 39 | 40 | .PHONY: archive 41 | archive: build-cocoapods 42 | @xcodebuild -create-xcframework \ 43 | -framework Pods/Pods/Build/Release-iphonesimulator/Tink/Tink.framework \ 44 | -framework Pods/Pods/Build/Release-iphoneos/Tink/Tink.framework \ 45 | -output Tink.xcframework | bundle exec xcpretty -c 46 | 47 | .PHONY: check 48 | check: 49 | xcrun lipo -info Pods/Tink/Frameworks/Tink.framework/Tink 50 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/signature/DarwinPublicKeyVerify.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.signature 2 | 3 | import com.google.crypto.tink.TINKKeysetHandle 4 | import com.google.crypto.tink.TINKPublicKeyVerifyFactory 5 | import com.google.crypto.tink.TINKPublicKeyVerifyProtocol 6 | import io.github.ryunen344.tink.exception.GeneralSecurityException 7 | import io.github.ryunen344.tink.util.asThrowable 8 | import io.github.ryunen344.tink.util.memScopedInstance 9 | import io.github.ryunen344.tink.util.toNSData 10 | import kotlinx.cinterop.ptr 11 | import kotlinx.cinterop.value 12 | 13 | class DarwinPublicKeyVerify(private val native: TINKPublicKeyVerifyProtocol) : PublicKeyVerify { 14 | 15 | @Throws(GeneralSecurityException::class) 16 | constructor(handle: TINKKeysetHandle) : this( 17 | memScopedInstance( 18 | block = { 19 | TINKPublicKeyVerifyFactory.primitiveWithKeysetHandle(handle, it.ptr) ?: throw GeneralSecurityException( 20 | cause = it.value?.asThrowable() 21 | ) 22 | }, 23 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 24 | ) 25 | ) 26 | 27 | @Throws(GeneralSecurityException::class) 28 | override fun verify(signature: ByteArray, data: ByteArray) = memScopedInstance( 29 | block = { 30 | val verified = native.verifySignature(signature.toNSData(), data.toNSData(), it.ptr) 31 | if (!verified) throw GeneralSecurityException("Invalid signature") 32 | }, 33 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/signature/DarwinPublicKeySign.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.signature 2 | 3 | import com.google.crypto.tink.TINKKeysetHandle 4 | import com.google.crypto.tink.TINKPublicKeySignFactory 5 | import com.google.crypto.tink.TINKPublicKeySignProtocol 6 | import io.github.ryunen344.tink.exception.GeneralSecurityException 7 | import io.github.ryunen344.tink.util.asThrowable 8 | import io.github.ryunen344.tink.util.memScopedInstance 9 | import io.github.ryunen344.tink.util.toByteArray 10 | import io.github.ryunen344.tink.util.toNSData 11 | import kotlinx.cinterop.ptr 12 | import kotlinx.cinterop.value 13 | 14 | class DarwinPublicKeySign(private val native: TINKPublicKeySignProtocol) : PublicKeySign { 15 | 16 | @Throws(GeneralSecurityException::class) 17 | constructor(handle: TINKKeysetHandle) : this( 18 | memScopedInstance( 19 | block = { 20 | TINKPublicKeySignFactory.primitiveWithKeysetHandle(handle, it.ptr) ?: throw GeneralSecurityException( 21 | cause = it.value?.asThrowable() 22 | ) 23 | }, 24 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 25 | ) 26 | ) 27 | 28 | @Throws(GeneralSecurityException::class) 29 | override fun sign(data: ByteArray): ByteArray = memScopedInstance( 30 | block = { 31 | native.signatureForData(data.toNSData(), it.ptr)?.toByteArray() 32 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 33 | }, 34 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/hybrid/DarwinHybridEncrypt.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.hybrid 2 | 3 | import com.google.crypto.tink.TINKHybridEncryptFactory 4 | import com.google.crypto.tink.TINKHybridEncryptProtocol 5 | import com.google.crypto.tink.TINKKeysetHandle 6 | import io.github.ryunen344.tink.exception.GeneralSecurityException 7 | import io.github.ryunen344.tink.util.asThrowable 8 | import io.github.ryunen344.tink.util.memScopedInstance 9 | import io.github.ryunen344.tink.util.toByteArray 10 | import io.github.ryunen344.tink.util.toNSData 11 | import kotlinx.cinterop.ptr 12 | import kotlinx.cinterop.value 13 | 14 | class DarwinHybridEncrypt(private val native: TINKHybridEncryptProtocol) : HybridEncrypt { 15 | 16 | @Throws(GeneralSecurityException::class) 17 | constructor(handle: TINKKeysetHandle) : this( 18 | memScopedInstance( 19 | block = { 20 | TINKHybridEncryptFactory.primitiveWithKeysetHandle(handle, it.ptr) 21 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 22 | }, 23 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 24 | ) 25 | ) 26 | 27 | @Throws(GeneralSecurityException::class) 28 | override fun encrypt(plaintext: ByteArray, contextInfo: ByteArray): ByteArray = memScopedInstance( 29 | block = { 30 | native.encrypt(plaintext.toNSData(), contextInfo.toNSData(), it.ptr)?.toByteArray() 31 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 32 | }, 33 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/hybrid/DarwinHybridDecrypt.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.hybrid 2 | 3 | import com.google.crypto.tink.TINKHybridDecryptFactory 4 | import com.google.crypto.tink.TINKHybridDecryptProtocol 5 | import com.google.crypto.tink.TINKKeysetHandle 6 | import io.github.ryunen344.tink.exception.GeneralSecurityException 7 | import io.github.ryunen344.tink.util.asThrowable 8 | import io.github.ryunen344.tink.util.memScopedInstance 9 | import io.github.ryunen344.tink.util.toByteArray 10 | import io.github.ryunen344.tink.util.toNSData 11 | import kotlinx.cinterop.ptr 12 | import kotlinx.cinterop.value 13 | 14 | class DarwinHybridDecrypt(private val native: TINKHybridDecryptProtocol) : HybridDecrypt { 15 | 16 | @Throws(GeneralSecurityException::class) 17 | constructor(handle: TINKKeysetHandle) : this( 18 | memScopedInstance( 19 | block = { 20 | TINKHybridDecryptFactory.primitiveWithKeysetHandle(handle, it.ptr) ?: throw GeneralSecurityException( 21 | cause = it.value?.asThrowable() 22 | ) 23 | }, 24 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 25 | ) 26 | ) 27 | 28 | @Throws(GeneralSecurityException::class) 29 | override fun decrypt(ciphertext: ByteArray, contextInfo: ByteArray): ByteArray = memScopedInstance( 30 | block = { 31 | native.decrypt(ciphertext.toNSData(), contextInfo.toNSData(), it.ptr)?.toByteArray() 32 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 33 | }, 34 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /iosApp/iosApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | 28 | UILaunchScreen 29 | 30 | UIRequiredDeviceCapabilities 31 | 32 | armv7 33 | 34 | UISupportedInterfaceOrientations 35 | 36 | UIInterfaceOrientationPortrait 37 | UIInterfaceOrientationLandscapeLeft 38 | UIInterfaceOrientationLandscapeRight 39 | 40 | UISupportedInterfaceOrientations~ipad 41 | 42 | UIInterfaceOrientationPortrait 43 | UIInterfaceOrientationPortraitUpsideDown 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | types: 9 | - opened 10 | - synchronize 11 | - reopened 12 | schedule: 13 | - cron: "0 1 * * 0" 14 | 15 | concurrency: 16 | group: ${{ github.workflow }}-${{ github.ref }} 17 | cancel-in-progress: true 18 | 19 | permissions: 20 | actions: read 21 | contents: read 22 | security-events: write 23 | 24 | jobs: 25 | analyze: 26 | runs-on: macos-14 27 | steps: 28 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 29 | - uses: ./.github/actions/sdkman 30 | - uses: ./.github/actions/konan 31 | - uses: ./.github/actions/xcode-select 32 | - uses: github/codeql-action/init@662472033e021d55d94146f66f6058822b0b39fd # v3 33 | with: 34 | config-file: ./.github/codeql/codeql-config.yml 35 | - uses: ruby/setup-ruby@217c988b8c2bf2bacb2d5c78a7e7b18f8c34daed # v1.200.0 36 | with: 37 | bundler-cache: true 38 | - uses: bazelbuild/setup-bazelisk@b39c379c82683a5f25d34f0d062761f62693e0b2 # v3 39 | - run: make bootstrap-submodule 40 | - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4 41 | with: 42 | path: | 43 | build/bazel 44 | Framework/Tink.xcframework 45 | key: v2-bazel-${{ runner.os }}-${{ hashFiles('.git/modules/TinkStub/HEAD') }} 46 | - uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3 47 | id: framework 48 | with: 49 | files: "Framework/Tink.xcframework" 50 | - uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3 51 | with: 52 | gradle-home-cache-cleanup: true 53 | arguments: assemble --scan 54 | - uses: github/codeql-action/analyze@662472033e021d55d94146f66f6058822b0b39fd # v3 55 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/mac/DarwinMac.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.mac 2 | 3 | import com.google.crypto.tink.TINKKeysetHandle 4 | import com.google.crypto.tink.TINKMacFactory 5 | import com.google.crypto.tink.TINKMacProtocol 6 | import io.github.ryunen344.tink.exception.GeneralSecurityException 7 | import io.github.ryunen344.tink.util.asThrowable 8 | import io.github.ryunen344.tink.util.memScopedInstance 9 | import io.github.ryunen344.tink.util.toByteArray 10 | import io.github.ryunen344.tink.util.toNSData 11 | import kotlinx.cinterop.ptr 12 | import kotlinx.cinterop.value 13 | 14 | class DarwinMac(private val native: TINKMacProtocol) : Mac { 15 | 16 | @Throws(GeneralSecurityException::class) 17 | constructor(handle: TINKKeysetHandle) : this( 18 | memScopedInstance( 19 | block = { 20 | TINKMacFactory.primitiveWithKeysetHandle(handle, it.ptr) 21 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 22 | }, 23 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 24 | ) 25 | ) 26 | 27 | @Throws(GeneralSecurityException::class) 28 | override fun computeMac(data: ByteArray): ByteArray = memScopedInstance( 29 | block = { 30 | native.computeMacForData(data.toNSData(), it.ptr)?.toByteArray() 31 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 32 | }, 33 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 34 | ) 35 | 36 | @Throws(GeneralSecurityException::class) 37 | override fun verifyMac(mac: ByteArray, data: ByteArray): Unit = memScopedInstance( 38 | block = { 39 | val verified = native.verifyMac(mac.toNSData(), data.toNSData(), it.ptr) 40 | if (!verified) throw GeneralSecurityException("invalid MAC") 41 | }, 42 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /tink/src/commonMain/kotlin/io/github/ryunen344/tink/KeyTemplateSet.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import io.github.ryunen344.tink.exception.GeneralSecurityException 4 | 5 | enum class KeyTemplateSet(val value: String) { 6 | // AEAD 7 | AES128_GCM("AES128_GCM"), 8 | AES128_GCM_RAW("AES128_GCM_RAW"), 9 | AES256_GCM("AES256_GCM"), 10 | AES256_GCM_RAW("AES256_GCM_RAW"), 11 | AES128_CTR_HMAC_SHA256("AES128_CTR_HMAC_SHA256"), 12 | AES256_CTR_HMAC_SHA256("AES256_CTR_HMAC_SHA256"), 13 | AES128_EAX("AES128_EAX"), 14 | AES256_EAX("AES256_EAX"), 15 | XCHACHA20_POLY1305("XCHACHA20_POLY1305"), 16 | 17 | // Deterministic AEAD 18 | AES256_SIV("AES256_SIV"), 19 | 20 | // MAC 21 | HMAC_SHA256_128BITTAG("HMAC_SHA256_128BITTAG"), 22 | HMAC_SHA256_256BITTAG("HMAC_SHA256_256BITTAG"), 23 | HMAC_SHA512_256BITTAG("HMAC_SHA512_256BITTAG"), 24 | HMAC_SHA512_512BITTAG("HMAC_SHA512_512BITTAG"), 25 | AES_CMAC("AES_CMAC"), 26 | 27 | // Digital Signatures 28 | ECDSA_P256("ECDSA_P256"), 29 | ECDSA_P384("ECDSA_P384"), 30 | ECDSA_P384_SHA384("ECDSA_P384_SHA384"), 31 | ECDSA_P384_SHA512("ECDSA_P384_SHA512"), 32 | ECDSA_P521("ECDSA_P521"), 33 | ECDSA_P256_IEEE_P1363("ECDSA_P256_IEEE_P1363"), 34 | ECDSA_P384_IEEE_P1363("ECDSA_P384_IEEE_P1363"), 35 | ECDSA_P521_IEEE_P1363("ECDSA_P521_IEEE_P1363"), 36 | ED25519("ED25519"), 37 | RSA_SSA_PKCS1_3072_SHA256_F4("RSA_SSA_PKCS1_3072_SHA256_F4"), 38 | RSA_SSA_PKCS1_4096_SHA512_F4("RSA_SSA_PKCS1_4096_SHA512_F4"), 39 | RSA_SSA_PSS_3072_SHA256_SHA256_32_F4("RSA_SSA_PSS_3072_SHA256_SHA256_32_F4"), 40 | RSA_SSA_PSS_4096_SHA512_SHA512_64_F4("RSA_SSA_PSS_4096_SHA512_SHA512_64_F4"), 41 | 42 | // Hybrid Encryption 43 | ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM("ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM"), 44 | ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256("ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256"), 45 | ; 46 | } 47 | 48 | @Throws(GeneralSecurityException::class) 49 | expect fun KeyTemplateSet.template(): KeyTemplate 50 | -------------------------------------------------------------------------------- /iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/aead/DarwinAead.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.aead 2 | 3 | import com.google.crypto.tink.TINKAeadFactory 4 | import com.google.crypto.tink.TINKAeadProtocol 5 | import com.google.crypto.tink.TINKKeysetHandle 6 | import io.github.ryunen344.tink.exception.GeneralSecurityException 7 | import io.github.ryunen344.tink.util.asThrowable 8 | import io.github.ryunen344.tink.util.memScopedInstance 9 | import io.github.ryunen344.tink.util.toByteArray 10 | import io.github.ryunen344.tink.util.toNSData 11 | import kotlinx.cinterop.ptr 12 | import kotlinx.cinterop.value 13 | 14 | class DarwinAead(val native: TINKAeadProtocol) : Aead { 15 | 16 | @Throws(GeneralSecurityException::class) 17 | constructor(handle: TINKKeysetHandle) : this( 18 | memScopedInstance( 19 | block = { 20 | TINKAeadFactory.primitiveWithKeysetHandle(handle, it.ptr) 21 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 22 | }, 23 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 24 | ) 25 | ) 26 | 27 | @Throws(GeneralSecurityException::class) 28 | override fun encrypt(plaintext: ByteArray, associatedData: ByteArray): ByteArray = memScopedInstance( 29 | block = { 30 | native.encrypt(plaintext.toNSData(), associatedData.toNSData(), it.ptr)?.toByteArray() 31 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 32 | }, 33 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 34 | ) 35 | 36 | @Throws(GeneralSecurityException::class) 37 | override fun decrypt(ciphertext: ByteArray, associatedData: ByteArray): ByteArray = memScopedInstance( 38 | block = { 39 | native.decrypt(ciphertext.toNSData(), associatedData.toNSData(), it.ptr)?.toByteArray() 40 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 41 | }, 42 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 41 | 42 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/daead/DarwinDeterministicAead.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.daead 2 | 3 | import com.google.crypto.tink.TINKDeterministicAeadFactory 4 | import com.google.crypto.tink.TINKDeterministicAeadProtocol 5 | import com.google.crypto.tink.TINKKeysetHandle 6 | import io.github.ryunen344.tink.exception.GeneralSecurityException 7 | import io.github.ryunen344.tink.util.asThrowable 8 | import io.github.ryunen344.tink.util.memScopedInstance 9 | import io.github.ryunen344.tink.util.toByteArray 10 | import io.github.ryunen344.tink.util.toNSData 11 | import kotlinx.cinterop.ptr 12 | import kotlinx.cinterop.value 13 | 14 | class DarwinDeterministicAead(private val native: TINKDeterministicAeadProtocol) : DeterministicAead { 15 | 16 | @Throws(GeneralSecurityException::class) 17 | constructor(handle: TINKKeysetHandle) : this( 18 | memScopedInstance( 19 | block = { 20 | TINKDeterministicAeadFactory.primitiveWithKeysetHandle(handle, it.ptr) 21 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 22 | }, 23 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 24 | ) 25 | ) 26 | 27 | @Throws(GeneralSecurityException::class) 28 | override fun encryptDeterministically(plaintext: ByteArray, associatedData: ByteArray): ByteArray = 29 | memScopedInstance( 30 | block = { 31 | native.encryptDeterministically(plaintext.toNSData(), associatedData.toNSData(), it.ptr)?.toByteArray() 32 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 33 | }, 34 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 35 | ) 36 | 37 | @Throws(GeneralSecurityException::class) 38 | override fun decryptDeterministically(ciphertext: ByteArray, associatedData: ByteArray): ByteArray = 39 | memScopedInstance( 40 | block = { 41 | native.decryptDeterministically(ciphertext.toNSData(), associatedData.toNSData(), it.ptr)?.toByteArray() 42 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 43 | }, 44 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) }, 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - synchronize 8 | - reopened 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | jobs: 15 | lint-docs: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 19 | - uses: reviewdog/action-actionlint@7eeec1dd160c2301eb28e1568721837d084558ad # v1 20 | with: 21 | github_token: ${{ secrets.GITHUB_TOKEN }} 22 | reporter: github-pr-review 23 | - uses: reviewdog/action-yamllint@e09f07780388032a624e9eb44a23fd1bbb4052cc # v1 24 | with: 25 | github_token: ${{ secrets.GITHUB_TOKEN }} 26 | reporter: github-pr-review 27 | - uses: reviewdog/action-markdownlint@28fb4224271253fedd5079b61de820d6228041fd # v0 28 | with: 29 | github_token: ${{ secrets.GITHUB_TOKEN }} 30 | reporter: github-pr-review 31 | 32 | lint-android: 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 36 | - uses: reviewdog/action-setup@3f401fe1d58fe77e10d665ab713057375e39b887 # v1 37 | - uses: ./.github/actions/sdkman 38 | - uses: ./.github/actions/konan 39 | - uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3 40 | with: 41 | gradle-home-cache-cleanup: true 42 | arguments: lint --scan 43 | - uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3 44 | with: 45 | gradle-home-cache-cleanup: true 46 | arguments: detekt --scan 47 | - uses: yutailang0119/action-android-lint@bd0b5a7d2cc453d16080b90e2a975d4af4aa9588 # v4 48 | with: 49 | report-path: "**/build/reports/lint-results*.xml" 50 | - run: < ./build/reports/detekt/detekt.xml reviewdog -f=checkstyle -name="detekt" -reporter="github-pr-review" 51 | env: 52 | REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} 53 | 54 | lint-ios: 55 | runs-on: ubuntu-latest 56 | steps: 57 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 58 | - uses: reviewdog/action-setup@3f401fe1d58fe77e10d665ab713057375e39b887 # v1 59 | - uses: ./.github/actions/sdkman 60 | - uses: ./.github/actions/konan 61 | -------------------------------------------------------------------------------- /tink/src/androidMain/kotlin/io/github/ryunen344/tink/KeysetHandle.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import com.google.crypto.tink.CleartextKeysetHandle 4 | import io.github.ryunen344.tink.aead.Aead 5 | import io.github.ryunen344.tink.aead.AndroidAead 6 | import io.github.ryunen344.tink.daead.AndroidDeterministicAead 7 | import io.github.ryunen344.tink.daead.DeterministicAead 8 | import io.github.ryunen344.tink.exception.GeneralSecurityException 9 | import io.github.ryunen344.tink.exception.IOException 10 | import io.github.ryunen344.tink.hybrid.AndroidHybridDecrypt 11 | import io.github.ryunen344.tink.hybrid.AndroidHybridEncrypt 12 | import io.github.ryunen344.tink.hybrid.HybridDecrypt 13 | import io.github.ryunen344.tink.hybrid.HybridEncrypt 14 | import io.github.ryunen344.tink.mac.AndroidMac 15 | import io.github.ryunen344.tink.mac.Mac 16 | import io.github.ryunen344.tink.signature.AndroidPublicKeySign 17 | import io.github.ryunen344.tink.signature.AndroidPublicKeyVerify 18 | import io.github.ryunen344.tink.signature.PublicKeySign 19 | import io.github.ryunen344.tink.signature.PublicKeyVerify 20 | import kotlin.reflect.KClass 21 | 22 | actual typealias KeysetHandle = com.google.crypto.tink.KeysetHandle 23 | 24 | @Suppress("EXTENSION_SHADOWED_BY_MEMBER") 25 | @Throws(GeneralSecurityException::class, IOException::class) 26 | actual fun KeysetHandle.writeNoSecret(writer: KeysetWriter) = writeNoSecret(writer) 27 | 28 | @Throws(GeneralSecurityException::class, IOException::class) 29 | actual fun KeysetHandle.writeCleartext(writer: KeysetWriter) = CleartextKeysetHandle.write(this, writer) 30 | 31 | @Suppress("UNCHECKED_CAST") 32 | @Throws(GeneralSecurityException::class) 33 | actual fun

KeysetHandle.getPrimitive(kClass: KClass

): P { 34 | val primitive = when (kClass) { 35 | Aead::class -> AndroidAead(this) 36 | DeterministicAead::class -> AndroidDeterministicAead(this) 37 | Mac::class -> AndroidMac(this) 38 | PublicKeySign::class -> AndroidPublicKeySign(this) 39 | PublicKeyVerify::class -> AndroidPublicKeyVerify(this) 40 | HybridEncrypt::class -> AndroidHybridEncrypt(this) 41 | HybridDecrypt::class -> AndroidHybridDecrypt(this) 42 | else -> throw GeneralSecurityException("not supported $kClass") 43 | } 44 | 45 | return primitive as P 46 | } 47 | 48 | @Throws(GeneralSecurityException::class) 49 | actual fun KeysetHandle.publicKeysetHandle(): KeysetHandle = publicKeysetHandle 50 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yml: -------------------------------------------------------------------------------- 1 | name: release-please 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: write 10 | pull-requests: write 11 | 12 | jobs: 13 | release-please: 14 | runs-on: macos-14 15 | steps: 16 | - uses: google-github-actions/release-please-action@a37ac6e4f6449ce8b3f7607e4d97d0146028dc0b # v4 17 | id: release 18 | with: 19 | default-branch: main 20 | release-type: simple 21 | package-name: release-please-action 22 | include-v-in-tag: false 23 | bump-minor-pre-major: true 24 | bump-patch-for-minor-pre-major: true 25 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 26 | if: ${{ steps.release.outputs.release_created }} 27 | - uses: ./.github/actions/sdkman 28 | if: ${{ steps.release.outputs.release_created }} 29 | - uses: ./.github/actions/konan 30 | if: ${{ steps.release.outputs.release_created }} 31 | - uses: ./.github/actions/xcode-select 32 | if: ${{ steps.release.outputs.release_created }} 33 | - uses: ruby/setup-ruby@217c988b8c2bf2bacb2d5c78a7e7b18f8c34daed # v1.200.0 34 | if: ${{ steps.release.outputs.release_created }} 35 | with: 36 | bundler-cache: true 37 | - uses: bazelbuild/setup-bazelisk@b39c379c82683a5f25d34f0d062761f62693e0b2 # v3 38 | if: ${{ steps.release.outputs.release_created }} 39 | - run: make bootstrap-submodule 40 | if: ${{ steps.release.outputs.release_created }} 41 | - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4 42 | if: ${{ steps.release.outputs.release_created }} 43 | with: 44 | path: | 45 | build/bazel 46 | Framework/Tink.xcframework 47 | key: v2-bazel-${{ runner.os }}-${{ hashFiles('.git/modules/TinkStub/HEAD') }} 48 | - run: make archive 49 | if: ${{ steps.release.outputs.release_created }} 50 | - uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0 51 | if: ${{ steps.release.outputs.release_created }} 52 | env: 53 | SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} 54 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} 55 | PGP_KEY_ID: ${{ secrets.PGP_KEY_ID }} 56 | PGP_SIGNING_KEY: ${{ secrets.PGP_SIGNING_KEY }} 57 | PGP_SIGNING_PASSWORD: ${{ secrets.PGP_SIGNING_PASSWORD }} 58 | with: 59 | max_attempts: 3 60 | retry_on: error 61 | timeout_minutes: 40 62 | command: ./gradlew publishAllPublicationsToSonatypeRepository closeAndReleaseSonatypeStagingRepository --stacktrace 63 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/KeysetHandleGenerator.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import com.google.crypto.tink.TINKKeysetHandle 4 | import com.google.crypto.tink.create 5 | import io.github.ryunen344.tink.aead.Aead 6 | import io.github.ryunen344.tink.aead.DarwinAead 7 | import io.github.ryunen344.tink.exception.GeneralSecurityException 8 | import io.github.ryunen344.tink.util.asThrowable 9 | import io.github.ryunen344.tink.util.memScopedInstance 10 | import io.github.ryunen344.tink.util.toNSData 11 | import kotlinx.cinterop.ptr 12 | import kotlinx.cinterop.value 13 | 14 | @Throws(GeneralSecurityException::class) 15 | actual fun KeysetHandleGenerator.Companion.generateNew(keyTemplate: KeyTemplate): KeysetHandle = memScopedInstance( 16 | block = { 17 | runCatching { 18 | KeysetHandle(keyTemplate = keyTemplate, error = it.ptr) 19 | }.getOrElse { 20 | throw GeneralSecurityException( 21 | message = "No manager for type ${keyTemplate.description} has been registered.", 22 | cause = it 23 | ) 24 | } 25 | }, 26 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 27 | ) 28 | 29 | @Throws(GeneralSecurityException::class) 30 | actual fun KeysetHandleGenerator.Companion.read( 31 | reader: KeysetReader, 32 | aead: Aead, 33 | ): KeysetHandle = memScopedInstance( 34 | block = { 35 | runCatching { 36 | KeysetHandle(keysetReader = reader.native, andKey = (aead as DarwinAead).native, error = it.ptr) 37 | }.getOrElse { 38 | throw GeneralSecurityException( 39 | message = "No manager has been registered.", 40 | cause = it 41 | ) 42 | } 43 | }, 44 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 45 | ) 46 | 47 | @Throws(GeneralSecurityException::class) 48 | actual fun KeysetHandleGenerator.Companion.readClearText(reader: KeysetReader): KeysetHandle = memScopedInstance( 49 | block = { 50 | TINKKeysetHandle.create(cleartextKeysetHandleWithKeysetReader = reader.native, error = it.ptr) 51 | ?: throw GeneralSecurityException( 52 | message = "No manager has been registered.", 53 | cause = it.value?.asThrowable() 54 | ) 55 | }, 56 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 57 | ) 58 | 59 | @Throws(GeneralSecurityException::class) 60 | actual fun KeysetHandleGenerator.Companion.readNoSecret(keyset: ByteArray): KeysetHandle = memScopedInstance( 61 | block = { 62 | runCatching { 63 | KeysetHandle(noSecretKeyset = keyset.toNSData(), error = it.ptr) 64 | }.getOrElse { 65 | throw GeneralSecurityException( 66 | message = "No manager has been registered.", 67 | cause = it 68 | ) 69 | } 70 | }, 71 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 72 | ) 73 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.7) 5 | base64 6 | nkf 7 | rexml 8 | activesupport (7.2.2) 9 | base64 10 | benchmark (>= 0.3) 11 | bigdecimal 12 | concurrent-ruby (~> 1.0, >= 1.3.1) 13 | connection_pool (>= 2.2.5) 14 | drb 15 | i18n (>= 1.6, < 2) 16 | logger (>= 1.4.2) 17 | minitest (>= 5.1) 18 | securerandom (>= 0.3) 19 | tzinfo (~> 2.0, >= 2.0.5) 20 | addressable (2.8.7) 21 | public_suffix (>= 2.0.2, < 7.0) 22 | algoliasearch (1.27.5) 23 | httpclient (~> 2.8, >= 2.8.3) 24 | json (>= 1.5.1) 25 | atomos (0.1.3) 26 | base64 (0.2.0) 27 | benchmark (0.3.0) 28 | bigdecimal (3.1.8) 29 | claide (1.1.0) 30 | cocoapods (1.16.2) 31 | addressable (~> 2.8) 32 | claide (>= 1.0.2, < 2.0) 33 | cocoapods-core (= 1.16.2) 34 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 35 | cocoapods-downloader (>= 2.1, < 3.0) 36 | cocoapods-plugins (>= 1.0.0, < 2.0) 37 | cocoapods-search (>= 1.0.0, < 2.0) 38 | cocoapods-trunk (>= 1.6.0, < 2.0) 39 | cocoapods-try (>= 1.1.0, < 2.0) 40 | colored2 (~> 3.1) 41 | escape (~> 0.0.4) 42 | fourflusher (>= 2.3.0, < 3.0) 43 | gh_inspector (~> 1.0) 44 | molinillo (~> 0.8.0) 45 | nap (~> 1.0) 46 | ruby-macho (>= 2.3.0, < 3.0) 47 | xcodeproj (>= 1.27.0, < 2.0) 48 | cocoapods-core (1.16.2) 49 | activesupport (>= 5.0, < 8) 50 | addressable (~> 2.8) 51 | algoliasearch (~> 1.0) 52 | concurrent-ruby (~> 1.1) 53 | fuzzy_match (~> 2.0.4) 54 | nap (~> 1.0) 55 | netrc (~> 0.11) 56 | public_suffix (~> 4.0) 57 | typhoeus (~> 1.0) 58 | cocoapods-deintegrate (1.0.5) 59 | cocoapods-downloader (2.1) 60 | cocoapods-plugins (1.0.0) 61 | nap 62 | cocoapods-search (1.0.1) 63 | cocoapods-trunk (1.6.0) 64 | nap (>= 0.8, < 2.0) 65 | netrc (~> 0.11) 66 | cocoapods-try (1.2.0) 67 | colored2 (3.1.2) 68 | concurrent-ruby (1.3.4) 69 | connection_pool (2.4.1) 70 | drb (2.2.1) 71 | escape (0.0.4) 72 | ethon (0.16.0) 73 | ffi (>= 1.15.0) 74 | ffi (1.17.0) 75 | fourflusher (2.3.1) 76 | fuzzy_match (2.0.4) 77 | gh_inspector (1.1.3) 78 | httpclient (2.8.3) 79 | i18n (1.14.6) 80 | concurrent-ruby (~> 1.0) 81 | json (2.7.5) 82 | logger (1.6.1) 83 | minitest (5.25.1) 84 | molinillo (0.8.0) 85 | nanaimo (0.4.0) 86 | nap (1.1.0) 87 | netrc (0.11.0) 88 | nkf (0.2.0) 89 | public_suffix (4.0.7) 90 | rexml (3.3.9) 91 | rouge (3.28.0) 92 | ruby-macho (2.5.1) 93 | securerandom (0.3.1) 94 | typhoeus (1.4.1) 95 | ethon (>= 0.9.0) 96 | tzinfo (2.0.6) 97 | concurrent-ruby (~> 1.0) 98 | xcodeproj (1.27.0) 99 | CFPropertyList (>= 2.3.3, < 4.0) 100 | atomos (~> 0.1.3) 101 | claide (>= 1.0.2, < 2.0) 102 | colored2 (~> 3.1) 103 | nanaimo (~> 0.4.0) 104 | rexml (>= 3.3.6, < 4.0) 105 | xcpretty (0.4.0) 106 | rouge (~> 3.28.0) 107 | 108 | PLATFORMS 109 | ruby 110 | 111 | DEPENDENCIES 112 | cocoapods (= 1.16.2) 113 | xcpretty (= 0.4.0) 114 | 115 | BUNDLED WITH 116 | 2.4.19 117 | -------------------------------------------------------------------------------- /iosApp/iosApp.xcodeproj/xcshareddata/xcschemes/iosApp.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/KeysetHandle.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import com.google.crypto.tink.serializedKeyset 4 | import io.github.ryunen344.tink.aead.Aead 5 | import io.github.ryunen344.tink.aead.DarwinAead 6 | import io.github.ryunen344.tink.daead.DarwinDeterministicAead 7 | import io.github.ryunen344.tink.daead.DeterministicAead 8 | import io.github.ryunen344.tink.exception.GeneralSecurityException 9 | import io.github.ryunen344.tink.exception.IOException 10 | import io.github.ryunen344.tink.hybrid.DarwinHybridDecrypt 11 | import io.github.ryunen344.tink.hybrid.DarwinHybridEncrypt 12 | import io.github.ryunen344.tink.hybrid.HybridDecrypt 13 | import io.github.ryunen344.tink.hybrid.HybridEncrypt 14 | import io.github.ryunen344.tink.mac.DarwinMac 15 | import io.github.ryunen344.tink.mac.Mac 16 | import io.github.ryunen344.tink.signature.DarwinPublicKeySign 17 | import io.github.ryunen344.tink.signature.DarwinPublicKeyVerify 18 | import io.github.ryunen344.tink.signature.PublicKeySign 19 | import io.github.ryunen344.tink.signature.PublicKeyVerify 20 | import io.github.ryunen344.tink.util.asThrowable 21 | import io.github.ryunen344.tink.util.memScopedInstance 22 | import kotlinx.cinterop.ptr 23 | import kotlinx.cinterop.value 24 | import platform.Foundation.NSData 25 | import platform.Foundation.NSString 26 | import platform.Foundation.NSUTF8StringEncoding 27 | import platform.Foundation.create 28 | import platform.Foundation.dataUsingEncoding 29 | import kotlin.reflect.KClass 30 | 31 | actual typealias KeysetHandle = com.google.crypto.tink.TINKKeysetHandle 32 | 33 | @Throws(GeneralSecurityException::class, IOException::class) 34 | actual fun KeysetHandle.writeNoSecret(writer: KeysetWriter) = memScopedInstance( 35 | block = { writer.value = serializedKeysetNoSecret(it.ptr) }, 36 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 37 | ) 38 | 39 | @Throws(GeneralSecurityException::class, IOException::class) 40 | actual fun KeysetHandle.writeCleartext(writer: KeysetWriter) { 41 | writer.value = serializedKeyset() 42 | } 43 | 44 | @Suppress("CAST_NEVER_SUCCEEDS") 45 | inline fun String.toNSString() = this as NSString 46 | 47 | inline fun String.toNSData() = toNSString().toNSData() 48 | 49 | @Suppress("CAST_NEVER_SUCCEEDS") 50 | inline fun NSString.toKString() = this as String 51 | 52 | inline fun NSString.toNSData() = dataUsingEncoding(NSUTF8StringEncoding) 53 | 54 | inline fun NSData.toNSString() = NSString.create(data = this, encoding = NSUTF8StringEncoding) 55 | 56 | @Suppress("UNCHECKED_CAST") 57 | @Throws(GeneralSecurityException::class) 58 | actual fun

KeysetHandle.getPrimitive(kClass: KClass

): P { 59 | val primitive = when (kClass) { 60 | Aead::class -> DarwinAead(this) 61 | DeterministicAead::class -> DarwinDeterministicAead(this) 62 | Mac::class -> DarwinMac(this) 63 | PublicKeySign::class -> DarwinPublicKeySign(this) 64 | PublicKeyVerify::class -> DarwinPublicKeyVerify(this) 65 | HybridEncrypt::class -> DarwinHybridEncrypt(this) 66 | HybridDecrypt::class -> DarwinHybridDecrypt(this) 67 | else -> throw GeneralSecurityException("not supported $kClass") 68 | } 69 | return primitive as P 70 | } 71 | 72 | @Throws(GeneralSecurityException::class) 73 | actual fun KeysetHandle.publicKeysetHandle(): KeysetHandle = memScopedInstance( 74 | block = { 75 | KeysetHandle.publicKeysetHandleWithHandle(this@publicKeysetHandle, it.ptr) 76 | ?: throw GeneralSecurityException(cause = it.value?.asThrowable()) 77 | }, 78 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 79 | ) 80 | -------------------------------------------------------------------------------- /iosApp/iosApp/ContentView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import TinKMM 3 | import Tink 4 | 5 | struct ContentView: View { 6 | 7 | private var handle: TINKKeysetHandle 8 | 9 | private let aead: Aead 10 | 11 | @State private var input: String = "" 12 | @State private var encrypted: Data? = nil 13 | @State private var decrypted: String = "" 14 | 15 | var body: some View { 16 | VStack { 17 | Group { 18 | Text("input") 19 | TextField("target", text: $input) 20 | .textFieldStyle(RoundedBorderTextFieldStyle()) 21 | } 22 | 23 | Group { 24 | Text("encrypted") 25 | Text(encrypted?.string ?? "nil") 26 | } 27 | 28 | Group { 29 | Text("decrypted") 30 | Text(decrypted) 31 | } 32 | 33 | Group { 34 | Button("encrypt") { 35 | encrypted = try! aead.encrypt(plaintext: input.array, associatedData: "associatedData".array).data 36 | } 37 | Button("decrypt") { 38 | guard let data = encrypted else { return } 39 | var result: KotlinByteArray? = nil 40 | do { 41 | result = try aead.decrypt(ciphertext: data.array, associatedData: "associatedData".array) 42 | } catch let error { 43 | print(error) 44 | } 45 | decrypted = result?.string ?? "" 46 | } 47 | } 48 | } 49 | } 50 | 51 | init() { 52 | try! AeadConfig.companion.register() 53 | let template = try! KeyTemplateSet.aes256Gcm.template() 54 | handle = try! KeysetHandleGenerator.companion.generateNew(keyTemplate: template) 55 | aead = try! KeysetHandleKt.getPrimitive(handle, kClass: TinkPrimitiveKt.aead) as! Aead 56 | } 57 | } 58 | 59 | struct ContentView_Previews: PreviewProvider { 60 | static var previews: some View { 61 | ContentView() 62 | } 63 | } 64 | 65 | extension String { 66 | var array: KotlinByteArray { 67 | let data = Data(self.utf8) 68 | let result = KotlinByteArray(size: Int32(data.count)) 69 | for (idx, byte) in data.enumerated() { 70 | result.set(index: Int32(idx), value: Int8(bitPattern: byte)) 71 | } 72 | return result 73 | } 74 | } 75 | 76 | extension Data { 77 | var string: String { 78 | return String(decoding: self, as: UTF8.self) 79 | } 80 | 81 | var array: KotlinByteArray { 82 | let result = KotlinByteArray(size: Int32(self.count)) 83 | for (idx, byte) in self.enumerated() { 84 | result.set(index: Int32(idx), value: Int8(bitPattern: byte)) 85 | } 86 | return result 87 | } 88 | } 89 | 90 | extension KotlinByteArray { 91 | var data: Data { 92 | var data = Data(count: Int(size)) 93 | for idx in 0 ..< size { 94 | let byte: Int8 = self.get(index: idx) 95 | data[Int(idx)] = UInt8(bitPattern: byte) 96 | } 97 | return data 98 | } 99 | 100 | var string: String { 101 | let size = self.size 102 | var data = Data(count: Int(size)) 103 | for idx in 0 ..< size { 104 | let byte: Int8 = self.get(index: idx) 105 | data[Int(idx)] = UInt8(bitPattern: byte) 106 | } 107 | return String(decoding: data, as: UTF8.self) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /tink/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode 2 | import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType 3 | import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework 4 | import org.jetbrains.kotlin.konan.target.KonanTarget 5 | 6 | plugins { 7 | kotlin("multiplatform") 8 | id("com.android.library") 9 | id("jacoco") 10 | } 11 | 12 | kotlin { 13 | androidTarget { 14 | publishLibraryVariants("release") 15 | } 16 | 17 | val frameworkName = "TinKMM" 18 | val xcf = XCFramework(frameworkName) 19 | 20 | listOf( 21 | iosX64(), 22 | iosSimulatorArm64(), 23 | iosArm64(), 24 | ).forEach { 25 | it.compilations.named("main") { 26 | cinterops.create("Tink") { 27 | compilerOpts(tinkCompilerOption(it.konanTarget)) 28 | } 29 | } 30 | it.binaries { 31 | getTest(NativeBuildType.DEBUG).linkerOpts(tinkLinkerOption(it.konanTarget)) 32 | framework { 33 | baseName = frameworkName 34 | embedBitcode(BitcodeEmbeddingMode.DISABLE) 35 | binaryOption("bundleId", "io.github.ryunen344.tink") 36 | binaryOption("bundleVersion", version.toString()) 37 | binaryOption("bundleShortVersionString", version.toString()) 38 | linkerOpts(tinkLinkerOption(it.konanTarget)) 39 | xcf.add(this) 40 | } 41 | } 42 | } 43 | 44 | sourceSets { 45 | getByName("commonTest").dependencies { 46 | implementation(kotlin("test")) 47 | } 48 | getByName("androidMain").dependencies { 49 | implementation("com.google.crypto.tink:tink-android:1.7.0") 50 | } 51 | create("iosMain") { 52 | dependsOn(getByName("commonMain")) 53 | maybeCreate("iosX64Main").dependsOn(this) 54 | maybeCreate("iosSimulatorArm64Main").dependsOn(this) 55 | maybeCreate("iosArm64Main").dependsOn(this) 56 | } 57 | create("iosTest") { 58 | dependsOn(getByName("commonTest")) 59 | maybeCreate("iosX64Test").dependsOn(this) 60 | maybeCreate("iosSimulatorArm64Test").dependsOn(this) 61 | maybeCreate("iosArm64Test").dependsOn(this) 62 | } 63 | } 64 | 65 | compilerOptions { 66 | freeCompilerArgs.set( 67 | freeCompilerArgs.get() + listOf( 68 | // for Kotlin/Native interop 69 | "-opt-in=kotlinx.cinterop.BetaInteropApi", 70 | "-opt-in=kotlinx.cinterop.ExperimentalForeignApi", 71 | "-Xexpect-actual-classes", 72 | ) 73 | ) 74 | } 75 | } 76 | 77 | android { 78 | namespace = "io.github.ryunen344.tink" 79 | compileSdk = 33 80 | defaultConfig { 81 | minSdk = 24 82 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 83 | } 84 | compileOptions { 85 | sourceCompatibility = JavaVersion.VERSION_17 86 | targetCompatibility = JavaVersion.VERSION_17 87 | } 88 | testOptions { 89 | unitTests.isIncludeAndroidResources = true 90 | unitTests.all { test -> 91 | test.testLogging.showStandardStreams = true 92 | jacoco.jacocoVersion = "0.8.9" 93 | test.extensions.configure { 94 | isIncludeNoLocationClasses = true 95 | excludes = listOf("jdk.internal.*") 96 | } 97 | } 98 | } 99 | buildTypes.getByName("debug") { 100 | enableUnitTestCoverage = true 101 | enableAndroidTestCoverage = true 102 | } 103 | lint { 104 | abortOnError = false 105 | } 106 | with(sourceSets["main"]) { 107 | java.srcDirs("src/androidMain/kotlin", "src/commonMain/kotlin") 108 | res.srcDirs("src/androidMain/res") 109 | } 110 | with(sourceSets["test"]) { 111 | java.srcDirs("src/androidUnitTest/kotlin", "src/commonTest/kotlin") 112 | res.srcDirs("src/androidUnitTest/res") 113 | } 114 | } 115 | 116 | fun Project.xcfPath(target: KonanTarget): String { 117 | return "$rootDir/Framework/Tink.xcframework/" + 118 | if (target is KonanTarget.IOS_ARM64) "ios-arm64" else "ios-arm64_x86_64-simulator" 119 | } 120 | 121 | fun Project.tinkCompilerOption(target: KonanTarget): List { 122 | return listOf( 123 | "-framework", 124 | "Tink", 125 | "-F${xcfPath(target)}", 126 | ) 127 | } 128 | 129 | fun Project.tinkLinkerOption(target: KonanTarget): List { 130 | return tinkCompilerOption(target) + listOf( 131 | "-rpath", 132 | xcfPath(target), 133 | "-ObjC", 134 | ) 135 | } 136 | -------------------------------------------------------------------------------- /tink/src/commonTest/kotlin/io/github/ryunen344/tink/KeysetWriterTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import io.github.ryunen344.tink.daead.DeterministicAeadConfig 4 | import io.github.ryunen344.tink.daead.register 5 | import io.github.ryunen344.tink.exception.GeneralSecurityException 6 | import io.github.ryunen344.tink.signature.SignatureConfig 7 | import io.github.ryunen344.tink.signature.register 8 | import kotlin.test.Test 9 | import kotlin.test.assertEquals 10 | import kotlin.test.assertFailsWith 11 | 12 | class KeysetWriterTest { 13 | @Test 14 | fun test_write() { 15 | DeterministicAeadConfig.register() 16 | val handle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_DAEAD_KEYSET)) 17 | val writer = BinaryKeysetWriter() 18 | handle.writeCleartext(writer) 19 | assertEquals( 20 | DAEAD_KEYSET_CONTENT, 21 | writer.write().contentToString() 22 | ) 23 | } 24 | 25 | @Test 26 | fun test_write_public_handle() { 27 | SignatureConfig.register() 28 | val handle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_PUBLIC_KEYSET)) 29 | val writer = BinaryKeysetWriter() 30 | handle.writeNoSecret(writer) 31 | assertEquals( 32 | PUBLIC_KEYSET_CONTENT, 33 | writer.write().contentToString() 34 | ) 35 | } 36 | 37 | @Test 38 | fun test_write_private_handle_then_throw_error() { 39 | DeterministicAeadConfig.register() 40 | val handle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_DAEAD_KEYSET)) 41 | val writer = BinaryKeysetWriter() 42 | 43 | assertFailsWith { 44 | handle.writeNoSecret(writer) 45 | } 46 | } 47 | 48 | private companion object { 49 | val JSON_DAEAD_KEYSET = """ 50 | { 51 | "primaryKeyId": 961932622, 52 | "key": [ 53 | { 54 | "keyData": { 55 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesSivKey", 56 | "keyMaterialType": "SYMMETRIC", 57 | "value": "EkCJ9r5iwc5uxq5ugFyrHXh5dijTa7qalWUgZ8Gf08RxNd545FjtLMYL7ObcaFtCSkvV2+7u6F2DN+kqUjAfkf2W" 58 | }, 59 | "outputPrefixType": "TINK", 60 | "keyId": 961932622, 61 | "status": "ENABLED" 62 | } 63 | ] 64 | } 65 | """.trimIndent() 66 | 67 | @Suppress("MaxLineLength") 68 | const val DAEAD_KEYSET_CONTENT = 69 | "[8, -50, -38, -41, -54, 3, 18, -124, 1, 10, 120, 10, 48, 116, 121, 112, 101, 46, 103, 111, 111, 103, 108, 101, 97, 112, 105, 115, 46, 99, 111, 109, 47, 103, 111, 111, 103, 108, 101, 46, 99, 114, 121, 112, 116, 111, 46, 116, 105, 110, 107, 46, 65, 101, 115, 83, 105, 118, 75, 101, 121, 18, 66, 18, 64, -119, -10, -66, 98, -63, -50, 110, -58, -82, 110, -128, 92, -85, 29, 120, 121, 118, 40, -45, 107, -70, -102, -107, 101, 32, 103, -63, -97, -45, -60, 113, 53, -34, 120, -28, 88, -19, 44, -58, 11, -20, -26, -36, 104, 91, 66, 74, 75, -43, -37, -18, -18, -24, 93, -125, 55, -23, 42, 82, 48, 31, -111, -3, -106, 24, 1, 16, 1, 24, -50, -38, -41, -54, 3, 32, 1]" 70 | 71 | val JSON_PUBLIC_KEYSET = """ 72 | { 73 | "primaryKeyId": 775870498, 74 | "key": [ 75 | { 76 | "keyData": { 77 | "typeUrl": "type.googleapis.com/google.crypto.tink.EcdsaPublicKey", 78 | "value": "IiApA+NmYivxRfhMuvTKZAwqETmn+WagBP/reucEjEvXkRog1AJ5GBzf+n27xnj9KcoGllF9NIFfQrDEP99FNH+Cne4SBhgCEAIIAw==", 79 | "keyMaterialType": "ASYMMETRIC_PUBLIC" 80 | }, 81 | "status": "ENABLED", 82 | "keyId": 775870498, 83 | "outputPrefixType": "TINK" 84 | } 85 | ] 86 | } 87 | """.trimIndent() 88 | 89 | @Suppress("MaxLineLength") 90 | const val PUBLIC_KEYSET_CONTENT = 91 | "[8, -94, -80, -5, -15, 2, 18, -108, 1, 10, -121, 1, 10, 53, 116, 121, 112, 101, 46, 103, 111, 111, 103, 108, 101, 97, 112, 105, 115, 46, 99, 111, 109, 47, 103, 111, 111, 103, 108, 101, 46, 99, 114, 121, 112, 116, 111, 46, 116, 105, 110, 107, 46, 69, 99, 100, 115, 97, 80, 117, 98, 108, 105, 99, 75, 101, 121, 18, 76, 34, 32, 41, 3, -29, 102, 98, 43, -15, 69, -8, 76, -70, -12, -54, 100, 12, 42, 17, 57, -89, -7, 102, -96, 4, -1, -21, 122, -25, 4, -116, 75, -41, -111, 26, 32, -44, 2, 121, 24, 28, -33, -6, 125, -69, -58, 120, -3, 41, -54, 6, -106, 81, 125, 52, -127, 95, 66, -80, -60, 63, -33, 69, 52, 127, -126, -99, -18, 18, 6, 24, 2, 16, 2, 8, 3, 24, 3, 16, 1, 24, -94, -80, -5, -15, 2, 32, 1]" 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | types: 9 | - opened 10 | - synchronize 11 | - reopened 12 | 13 | concurrency: 14 | group: ${{ github.workflow }}-${{ github.ref }} 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | unit-test-android: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 22 | - uses: ./.github/actions/sdkman 23 | - uses: ./.github/actions/konan 24 | - uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3 25 | with: 26 | gradle-home-cache-cleanup: true 27 | arguments: testDebugUnitTest --scan 28 | - uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3 29 | with: 30 | gradle-home-cache-cleanup: true 31 | arguments: jacocoMergedReport 32 | - uses: EnricoMi/publish-unit-test-result-action@170bf24d20d201b842d7a52403b73ed297e6645b # v2 33 | if: ${{ !cancelled() && (success() || failure()) }} 34 | with: 35 | check_name: Test Results android 36 | files: | 37 | **/test-results/**/*.xml 38 | - uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4 39 | with: 40 | token: ${{ secrets.CODECOV_TOKEN }} 41 | 42 | unit-test-ios: 43 | runs-on: macos-14 44 | steps: 45 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 46 | - uses: ./.github/actions/sdkman 47 | - uses: ./.github/actions/konan 48 | - uses: ./.github/actions/xcode-select 49 | - uses: ruby/setup-ruby@217c988b8c2bf2bacb2d5c78a7e7b18f8c34daed # v1.200.0 50 | with: 51 | bundler-cache: true 52 | - uses: bazelbuild/setup-bazelisk@b39c379c82683a5f25d34f0d062761f62693e0b2 # v3 53 | - run: make bootstrap-submodule 54 | - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4 55 | with: 56 | path: | 57 | build/bazel 58 | Framework/Tink.xcframework 59 | key: v2-bazel-${{ runner.os }}-${{ hashFiles('.git/modules/TinkStub/HEAD') }} 60 | - uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3 61 | id: framework 62 | with: 63 | files: "Framework/Tink.xcframework" 64 | - run: make archive 65 | if: steps.framework.outputs.files_exists != 'true' 66 | - uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3 67 | with: 68 | gradle-home-cache-cleanup: true 69 | arguments: iosX64Test --scan 70 | - uses: EnricoMi/publish-unit-test-result-action/composite@170bf24d20d201b842d7a52403b73ed297e6645b # v2 71 | if: ${{ !cancelled() && (success() || failure()) }} 72 | with: 73 | check_name: Unit Test Results iosX64 74 | files: | 75 | **/test-results/**/*.xml 76 | 77 | instrumented-test-ios: 78 | runs-on: macos-14 79 | steps: 80 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 81 | - uses: ./.github/actions/sdkman 82 | - uses: ./.github/actions/konan 83 | - uses: ./.github/actions/xcode-select 84 | - uses: ruby/setup-ruby@217c988b8c2bf2bacb2d5c78a7e7b18f8c34daed # v1.200.0 85 | with: 86 | bundler-cache: true 87 | - uses: bazelbuild/setup-bazelisk@b39c379c82683a5f25d34f0d062761f62693e0b2 # v3 88 | - run: make bootstrap-submodule 89 | - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4 90 | with: 91 | path: | 92 | build/bazel 93 | Framework/Tink.xcframework 94 | key: v2-bazel-${{ runner.os }}-${{ hashFiles('.git/modules/TinkStub/HEAD') }} 95 | - uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3 96 | id: framework 97 | with: 98 | files: "Framework/Tink.xcframework" 99 | - run: make archive 100 | if: steps.framework.outputs.files_exists != 'true' 101 | - uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3 102 | with: 103 | gradle-home-cache-cleanup: true 104 | arguments: :iosApp:simulatorsList 105 | - uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # v3 106 | with: 107 | gradle-home-cache-cleanup: true 108 | arguments: :iosApp:xcodetest --scan --info 109 | - uses: EnricoMi/publish-unit-test-result-action/composite@170bf24d20d201b842d7a52403b73ed297e6645b # v2 110 | if: ${{ !cancelled() && (success() || failure()) }} 111 | with: 112 | check_name: Instrumented Test Results iosX64 113 | files: | 114 | **/test-results.xml 115 | -------------------------------------------------------------------------------- /tink/src/iosMain/kotlin/io/github/ryunen344/tink/KeyTemplateSet.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink 2 | 3 | import com.google.crypto.tink.TINKAeadKeyTemplate 4 | import com.google.crypto.tink.TINKAes128CtrHmacSha256 5 | import com.google.crypto.tink.TINKAes128Eax 6 | import com.google.crypto.tink.TINKAes128Gcm 7 | import com.google.crypto.tink.TINKAes128GcmNoPrefix 8 | import com.google.crypto.tink.TINKAes256CtrHmacSha256 9 | import com.google.crypto.tink.TINKAes256Eax 10 | import com.google.crypto.tink.TINKAes256Gcm 11 | import com.google.crypto.tink.TINKAes256GcmNoPrefix 12 | import com.google.crypto.tink.TINKAes256Siv 13 | import com.google.crypto.tink.TINKAesCmac 14 | import com.google.crypto.tink.TINKDeterministicAeadKeyTemplate 15 | import com.google.crypto.tink.TINKEcdsaP256 16 | import com.google.crypto.tink.TINKEcdsaP256Ieee 17 | import com.google.crypto.tink.TINKEcdsaP384 18 | import com.google.crypto.tink.TINKEcdsaP384Ieee 19 | import com.google.crypto.tink.TINKEcdsaP384Sha384 20 | import com.google.crypto.tink.TINKEcdsaP384Sha512 21 | import com.google.crypto.tink.TINKEcdsaP521 22 | import com.google.crypto.tink.TINKEcdsaP521Ieee 23 | import com.google.crypto.tink.TINKEciesP256HkdfHmacSha256Aes128CtrHmacSha256 24 | import com.google.crypto.tink.TINKEciesP256HkdfHmacSha256Aes128Gcm 25 | import com.google.crypto.tink.TINKEd25519 26 | import com.google.crypto.tink.TINKHmacSha256 27 | import com.google.crypto.tink.TINKHmacSha256HalfSizeTag 28 | import com.google.crypto.tink.TINKHmacSha512 29 | import com.google.crypto.tink.TINKHmacSha512HalfSizeTag 30 | import com.google.crypto.tink.TINKHybridKeyTemplate 31 | import com.google.crypto.tink.TINKMacKeyTemplate 32 | import com.google.crypto.tink.TINKRsaSsaPkcs13072Sha256F4 33 | import com.google.crypto.tink.TINKRsaSsaPkcs14096Sha512F4 34 | import com.google.crypto.tink.TINKRsaSsaPss3072Sha256Sha256F4 35 | import com.google.crypto.tink.TINKRsaSsaPss4096Sha512Sha512F4 36 | import com.google.crypto.tink.TINKSignatureKeyTemplate 37 | import com.google.crypto.tink.TINKXChaCha20Poly1305 38 | import io.github.ryunen344.tink.exception.GeneralSecurityException 39 | import io.github.ryunen344.tink.util.asThrowable 40 | import io.github.ryunen344.tink.util.memScopedInstance 41 | import kotlinx.cinterop.ptr 42 | 43 | @Suppress("CyclomaticComplexMethod") 44 | @Throws(GeneralSecurityException::class) 45 | actual fun KeyTemplateSet.template(): KeyTemplate = memScopedInstance( 46 | block = { 47 | when (this@template) { 48 | // AEAD 49 | KeyTemplateSet.AES128_GCM -> TINKAeadKeyTemplate(TINKAes128Gcm, it.ptr) 50 | KeyTemplateSet.AES128_GCM_RAW -> TINKAeadKeyTemplate(TINKAes128GcmNoPrefix, it.ptr) 51 | KeyTemplateSet.AES256_GCM -> TINKAeadKeyTemplate(TINKAes256Gcm, it.ptr) 52 | KeyTemplateSet.AES256_GCM_RAW -> TINKAeadKeyTemplate(TINKAes256GcmNoPrefix, it.ptr) 53 | KeyTemplateSet.AES128_CTR_HMAC_SHA256 -> TINKAeadKeyTemplate(TINKAes128CtrHmacSha256, it.ptr) 54 | KeyTemplateSet.AES256_CTR_HMAC_SHA256 -> TINKAeadKeyTemplate(TINKAes256CtrHmacSha256, it.ptr) 55 | KeyTemplateSet.AES128_EAX -> TINKAeadKeyTemplate(TINKAes128Eax, it.ptr) 56 | KeyTemplateSet.AES256_EAX -> TINKAeadKeyTemplate(TINKAes256Eax, it.ptr) 57 | KeyTemplateSet.XCHACHA20_POLY1305 -> TINKAeadKeyTemplate(TINKXChaCha20Poly1305, it.ptr) 58 | 59 | // Deterministic AEAD 60 | KeyTemplateSet.AES256_SIV -> TINKDeterministicAeadKeyTemplate(TINKAes256Siv, it.ptr) 61 | 62 | // MAC 63 | KeyTemplateSet.HMAC_SHA256_128BITTAG -> TINKMacKeyTemplate(TINKHmacSha256HalfSizeTag, it.ptr) 64 | KeyTemplateSet.HMAC_SHA256_256BITTAG -> TINKMacKeyTemplate(TINKHmacSha256, it.ptr) 65 | KeyTemplateSet.HMAC_SHA512_256BITTAG -> TINKMacKeyTemplate(TINKHmacSha512HalfSizeTag, it.ptr) 66 | KeyTemplateSet.HMAC_SHA512_512BITTAG -> TINKMacKeyTemplate(TINKHmacSha512, it.ptr) 67 | KeyTemplateSet.AES_CMAC -> TINKMacKeyTemplate(TINKAesCmac, it.ptr) 68 | 69 | // Digital Signatures 70 | KeyTemplateSet.ECDSA_P256 -> TINKSignatureKeyTemplate(TINKEcdsaP256, it.ptr) 71 | KeyTemplateSet.ECDSA_P384 -> TINKSignatureKeyTemplate(TINKEcdsaP384, it.ptr) 72 | KeyTemplateSet.ECDSA_P384_SHA384 -> TINKSignatureKeyTemplate(TINKEcdsaP384Sha384, it.ptr) 73 | KeyTemplateSet.ECDSA_P384_SHA512 -> TINKSignatureKeyTemplate(TINKEcdsaP384Sha512, it.ptr) 74 | KeyTemplateSet.ECDSA_P521 -> TINKSignatureKeyTemplate(TINKEcdsaP521, it.ptr) 75 | KeyTemplateSet.ECDSA_P256_IEEE_P1363 -> TINKSignatureKeyTemplate(TINKEcdsaP256Ieee, it.ptr) 76 | KeyTemplateSet.ECDSA_P384_IEEE_P1363 -> TINKSignatureKeyTemplate(TINKEcdsaP384Ieee, it.ptr) 77 | KeyTemplateSet.ECDSA_P521_IEEE_P1363 -> TINKSignatureKeyTemplate(TINKEcdsaP521Ieee, it.ptr) 78 | KeyTemplateSet.ED25519 -> TINKSignatureKeyTemplate(TINKEd25519, it.ptr) 79 | KeyTemplateSet.RSA_SSA_PKCS1_3072_SHA256_F4 -> TINKSignatureKeyTemplate(TINKRsaSsaPkcs13072Sha256F4, it.ptr) 80 | KeyTemplateSet.RSA_SSA_PKCS1_4096_SHA512_F4 -> TINKSignatureKeyTemplate(TINKRsaSsaPkcs14096Sha512F4, it.ptr) 81 | 82 | KeyTemplateSet.RSA_SSA_PSS_3072_SHA256_SHA256_32_F4 -> TINKSignatureKeyTemplate( 83 | TINKRsaSsaPss3072Sha256Sha256F4, 84 | it.ptr 85 | ) 86 | 87 | KeyTemplateSet.RSA_SSA_PSS_4096_SHA512_SHA512_64_F4 -> TINKSignatureKeyTemplate( 88 | TINKRsaSsaPss4096Sha512Sha512F4, 89 | it.ptr 90 | ) 91 | 92 | // Hybrid Encryption 93 | KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM -> TINKHybridKeyTemplate( 94 | TINKEciesP256HkdfHmacSha256Aes128Gcm, 95 | it.ptr 96 | ) 97 | 98 | KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256 -> TINKHybridKeyTemplate( 99 | TINKEciesP256HkdfHmacSha256Aes128CtrHmacSha256, 100 | it.ptr 101 | ) 102 | } 103 | }, 104 | onError = { throw GeneralSecurityException(cause = it.asThrowable()) } 105 | ) 106 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [0.0.7](https://github.com/RyuNen344/tink-kmm/compare/0.0.6...0.0.7) (2023-11-30) 4 | 5 | 6 | ### Bug Fixes 7 | 8 | * **deps:** update detekt to v1.23.2 ([#166](https://github.com/RyuNen344/tink-kmm/issues/166)) ([f58757b](https://github.com/RyuNen344/tink-kmm/commit/f58757bc4c797832dcb85afb9a26295515fc5a9e)) 9 | * **deps:** update detekt to v1.23.3 ([#168](https://github.com/RyuNen344/tink-kmm/issues/168)) ([77ee74c](https://github.com/RyuNen344/tink-kmm/commit/77ee74c6816cf5b0d2a63514600fdf02ee1ee0ed)) 10 | * **deps:** update detekt to v1.23.4 ([#177](https://github.com/RyuNen344/tink-kmm/issues/177)) ([d090399](https://github.com/RyuNen344/tink-kmm/commit/d090399c610df06a54810ee8e64ec8a3d4ae717b)) 11 | 12 | ## [0.0.6](https://github.com/RyuNen344/tink-kmm/compare/0.0.5...0.0.6) (2023-09-17) 13 | 14 | 15 | ### Bug Fixes 16 | 17 | * **deps:** update detekt to v1.23.1 ([#114](https://github.com/RyuNen344/tink-kmm/issues/114)) ([6d7c1fc](https://github.com/RyuNen344/tink-kmm/commit/6d7c1fc3e704901951975dda2ec4f6d6d1399e72)) 18 | 19 | ## [0.0.5](https://github.com/RyuNen344/tink-kmm/compare/0.0.4...0.0.5) (2023-07-23) 20 | 21 | 22 | ### Features 23 | 24 | * **deps:** update kotlin monorepo to v1.9.0 ([#76](https://github.com/RyuNen344/tink-kmm/issues/76)) ([08b94c0](https://github.com/RyuNen344/tink-kmm/commit/08b94c06cf1ef4a91ddafbfd1e8f08282f0f8940)) 25 | 26 | ## [0.0.4](https://github.com/RyuNen344/tink-kmm/compare/0.0.3...0.0.4) (2023-07-15) 27 | 28 | 29 | ### Features 30 | 31 | * bump kotlin version to 1.8.22 ([#99](https://github.com/RyuNen344/tink-kmm/issues/99)) ([fa2280f](https://github.com/RyuNen344/tink-kmm/commit/fa2280f11f4f75d1c02237ed45aa9bcd111118d0)) 32 | 33 | 34 | ### Bug Fixes 35 | 36 | * **deps:** update detekt to v1.23.0 ([#70](https://github.com/RyuNen344/tink-kmm/issues/70)) ([746b8b7](https://github.com/RyuNen344/tink-kmm/commit/746b8b7535e074a751e93d07469195f25ba959f9)) 37 | 38 | ## [0.0.3](https://github.com/RyuNen344/tink-kmm/compare/0.0.2...0.0.3) (2023-05-07) 39 | 40 | 41 | ### Features 42 | 43 | * **ci:** automate maven release ([b1e1d1d](https://github.com/RyuNen344/tink-kmm/commit/b1e1d1d972e5b899e6b10bc8c5658a243d38d189)) 44 | 45 | 46 | ### Deps 47 | 48 | * **deps:** update android gradle plugin to v8 (major) ([#64](https://github.com/RyuNen344/tink-kmm/pull/64)) ([64bae51](https://github.com/RyuNen344/tink-kmm/commit/64bae514929d44939fcaa9705fea3f5c5c732297)) 49 | * **deps:** update dependency gradle to v8 ([#62](https://github.com/RyuNen344/tink-kmm/pull/62)) ([01fe6c6](https://github.com/RyuNen344/tink-kmm/commit/01fe6c6695671e85ece8b513d94191fed559adc1)) 50 | 51 | 52 | ### Bug Fixes 53 | 54 | * **deps:** update detekt to v1.23.0-rc3 ([#59](https://github.com/RyuNen344/tink-kmm/issues/59)) ([5de6564](https://github.com/RyuNen344/tink-kmm/commit/5de6564ceb26cba3c41315ce912b0f8746e42bd1)) 55 | 56 | ## [0.0.2](https://github.com/RyuNen344/tink-kmm/compare/0.0.1...0.0.2) (2023-05-06) 57 | 58 | 59 | ### Miscellaneous Chores 60 | 61 | * release 0.0.2 ([2c0d0aa](https://github.com/RyuNen344/tink-kmm/commit/2c0d0aa7d481e5746612035d2b5cd8218090d387)) 62 | * update kotlin to 1.8.21 63 | 64 | ## [0.0.1](https://github.com/RyuNen344/tink-kmm/compare/0.0.1-rc03...0.0.1) (2023-05-04) 65 | 66 | 67 | ### Miscellaneous Chores 68 | 69 | * release 0.0.1 ([8df0fe4](https://github.com/RyuNen344/tink-kmm/commit/8df0fe4df1cb7a866f85614639d8e233bf3ac6ee)) 70 | 71 | ## [0.0.1-rc03](https://github.com/RyuNen344/tink-kmm/compare/0.0.1-rc02...0.0.1-rc03) (2023-05-04) 72 | 73 | 74 | ### Bug Fixes 75 | 76 | * invalid pom file ([e8c611b](https://github.com/RyuNen344/tink-kmm/commit/e8c611b175961306791c6be01fe8a0a23f437194)) 77 | 78 | 79 | ### Miscellaneous Chores 80 | 81 | * release 0.0.1-rc03 ([89acd48](https://github.com/RyuNen344/tink-kmm/commit/89acd48b3cbf876095a921929d44884d53531d56)) 82 | 83 | ## [0.0.1-rc02](https://github.com/RyuNen344/tink-kmm/compare/0.0.1-rc01...0.0.1-rc02) (2023-05-04) 84 | 85 | 86 | ### Miscellaneous Chores 87 | 88 | * release 0.0.1-rc02 ([0f48dbf](https://github.com/RyuNen344/tink-kmm/commit/0f48dbff7298330da50e633af3385b5e4bc62af0)) 89 | 90 | ## 0.0.1-rc01 (2023-05-04) 91 | 92 | 93 | ### Features 94 | 95 | * **aead config:** impl AEADConfig ailas ([f816121](https://github.com/RyuNen344/tink-kmm/commit/f8161213d81aa51c357a3853a37cefaa4608f967)) 96 | * **configs:** computed property to function, to append throws annotation ([b0b150c](https://github.com/RyuNen344/tink-kmm/commit/b0b150cba3a67ffacb21c076df9b07abef9ac906)) 97 | * **configs:** fix imports ([6cf435a](https://github.com/RyuNen344/tink-kmm/commit/6cf435a1a257aa82b32b17d35e322fabb5447e25)) 98 | * **configs:** fix initialization error ([4898211](https://github.com/RyuNen344/tink-kmm/commit/4898211274a663a8f06ae6d514d237260e138669)) 99 | * **configs:** impl HybridConfig ailas ([c040f94](https://github.com/RyuNen344/tink-kmm/commit/c040f942f32e7fd8cd6266dd724cd2dd9ebf96c7)) 100 | * **configs:** impl KeyTemplateSet, and configs ([fb6c84d](https://github.com/RyuNen344/tink-kmm/commit/fb6c84dcf610f4f6eeac8e882fd41ad35ac7454f)) 101 | * **configs:** move files ([49201b0](https://github.com/RyuNen344/tink-kmm/commit/49201b0e755c16336f533d47307af4b9a8ba4a3f)) 102 | * **generator:** impl KeysetHandleGenerator and Reader ([fbffd8c](https://github.com/RyuNen344/tink-kmm/commit/fbffd8c17b5d37ff3ec31eba85267927f21f42a5)) 103 | * **KClass:** fix interface ([84c8052](https://github.com/RyuNen344/tink-kmm/commit/84c8052b8ef06a9ebfc92b75753b5572a2190d5f)) 104 | * **KClass:** handle when constructor throws NullPointException ([5543917](https://github.com/RyuNen344/tink-kmm/commit/5543917de24b5f795c26ce15b2cfd357ba81b7a7)) 105 | * **KClass:** support KClass interface ([722466c](https://github.com/RyuNen344/tink-kmm/commit/722466cfb58699a1bbedd09a889fc9642ec57d03)) 106 | * **keyset reader:** add clear text keyset reader if ([b1a3902](https://github.com/RyuNen344/tink-kmm/commit/b1a3902c57f069759b36ba303fbd5122c592a80e)) 107 | * **keyset reader:** impl BinaryKeysetReader ([2650f69](https://github.com/RyuNen344/tink-kmm/commit/2650f69d7bc7f88196875da020c1a184b7d05efe)) 108 | * **keyset reader:** impl ClearTextKeysetReader ([46d3edc](https://github.com/RyuNen344/tink-kmm/commit/46d3edc4e3a32dba0da4d2d46eef2f95adda25aa)) 109 | * **keyset reader:** impl JsonKeysetReader ([09e3ab2](https://github.com/RyuNen344/tink-kmm/commit/09e3ab281a030dc7943baf98e676ab36bd865727)) 110 | * **primitives:** impl Basic Primitive Encryption ([ca3f745](https://github.com/RyuNen344/tink-kmm/commit/ca3f745e405fbb47f9bc8fb3f817be37a24893f8)) 111 | * **writer:** remove unavailable interfaces ([e93a7b3](https://github.com/RyuNen344/tink-kmm/commit/e93a7b384a0bddc4523a72a280bd0c28a6c3d108)) 112 | 113 | 114 | ### Bug Fixes 115 | 116 | * action ([b1901c9](https://github.com/RyuNen344/tink-kmm/commit/b1901c9a37da707b19ca91bd5fcd8db6f2e55108)) 117 | * action id ([d9a417b](https://github.com/RyuNen344/tink-kmm/commit/d9a417bba6ddbc721b05fbe85148f4996ab07993)) 118 | * actions ([2fecbd3](https://github.com/RyuNen344/tink-kmm/commit/2fecbd339a92b980ffbb7664eb81039c58b9be4f)) 119 | * actions ([97ef06f](https://github.com/RyuNen344/tink-kmm/commit/97ef06f0f9c4fa366a678ec04d5b5e1d654a7e0e)) 120 | * bazel command ([2bff396](https://github.com/RyuNen344/tink-kmm/commit/2bff3967b0de450bfe87b0185783c8981ae96db3)) 121 | * codecov token ([2517fe4](https://github.com/RyuNen344/tink-kmm/commit/2517fe48abef921e43c4ecd9b1aaa3e4441ab6c2)) 122 | * command option order ([e070b76](https://github.com/RyuNen344/tink-kmm/commit/e070b763a59912f51dcba4968860412dde0e0dc9)) 123 | * command option order ([45bd4c8](https://github.com/RyuNen344/tink-kmm/commit/45bd4c8e34915ff7c00b3050859ff66ade633b55)) 124 | * coverage config ([9d2c019](https://github.com/RyuNen344/tink-kmm/commit/9d2c0196390ee9b536ab7963122863ada344c236)) 125 | * java home ([baf7954](https://github.com/RyuNen344/tink-kmm/commit/baf7954262293f42e7e8a39221605a12f7c6ac66)) 126 | * path ([fa3b2ca](https://github.com/RyuNen344/tink-kmm/commit/fa3b2ca8477ae7b7247ee0bf4d2595c373ab12d4)) 127 | * path ([8a08bc6](https://github.com/RyuNen344/tink-kmm/commit/8a08bc6bf9d4dd3e16eb2ddb21e87f5d6ef60e4c)) 128 | * sdkman cache ([fe76d78](https://github.com/RyuNen344/tink-kmm/commit/fe76d78c89083ede0c006e2f582c3be7d0c14174)) 129 | * shell ([e6a50d8](https://github.com/RyuNen344/tink-kmm/commit/e6a50d8b5bb14f0f7cd9f99094c31ba6e00e2d02)) 130 | * shellcheck ([a52ddb5](https://github.com/RyuNen344/tink-kmm/commit/a52ddb513e265b84bb02795eaa8d611b7c138e40)) 131 | * space ([aa02d10](https://github.com/RyuNen344/tink-kmm/commit/aa02d10c82ae7f32a5dadae75aa7e88d98b2807a)) 132 | * submodule init timing ([47807db](https://github.com/RyuNen344/tink-kmm/commit/47807db35d83c23b931030160625dcf99bcfed96)) 133 | 134 | 135 | ### Miscellaneous Chores 136 | 137 | * release 0.0.1-rc01 ([951bcb4](https://github.com/RyuNen344/tink-kmm/commit/951bcb40635ef35090ecd387d97bc3bf21f5b9b5)) 138 | * update config ([95f81ee](https://github.com/RyuNen344/tink-kmm/commit/95f81ee3e8a5d0c5cf48b0889f36124c02aac56b)) 139 | * update config ([075b18b](https://github.com/RyuNen344/tink-kmm/commit/075b18b264c055ae06466c19bd49a43326d3ccaf)) 140 | -------------------------------------------------------------------------------- /tink/src/commonTest/kotlin/io/github/ryunen344/tink/daead/DeterministicAeadTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.daead 2 | 3 | import io.github.ryunen344.tink.JsonKeysetReader 4 | import io.github.ryunen344.tink.KeyTemplateSet 5 | import io.github.ryunen344.tink.KeysetHandleGenerator 6 | import io.github.ryunen344.tink.exception.GeneralSecurityException 7 | import io.github.ryunen344.tink.generateNew 8 | import io.github.ryunen344.tink.getPrimitive 9 | import io.github.ryunen344.tink.readClearText 10 | import io.github.ryunen344.tink.template 11 | import kotlin.test.BeforeTest 12 | import kotlin.test.Test 13 | import kotlin.test.assertContentEquals 14 | import kotlin.test.assertFailsWith 15 | 16 | class DeterministicAeadTest { 17 | 18 | @BeforeTest 19 | fun setup() { 20 | DeterministicAeadConfig.register() 21 | } 22 | 23 | @Test 24 | fun test_encrypt_then_success() { 25 | val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_SIV.template()) 26 | val daead = handle.getPrimitive(DeterministicAead::class) 27 | val plaintext = "plaintext".encodeToByteArray() 28 | val associatedData = "associatedData".encodeToByteArray() 29 | val ciphertext = daead.encryptDeterministically(plaintext, associatedData) 30 | val decrypted = daead.decryptDeterministically(ciphertext, associatedData) 31 | 32 | assertContentEquals(plaintext, decrypted) 33 | assertContentEquals(ciphertext, daead.encryptDeterministically(plaintext, associatedData)) 34 | } 35 | 36 | @Test 37 | fun test_encrypt_given_empty_then_success() { 38 | val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_SIV.template()) 39 | val daead = handle.getPrimitive(DeterministicAead::class) 40 | val plaintext = "plaintext".encodeToByteArray() 41 | val associatedData = "associatedData".encodeToByteArray() 42 | val empty = "".encodeToByteArray() 43 | 44 | assertContentEquals( 45 | empty, 46 | daead.decryptDeterministically(daead.encryptDeterministically(empty, associatedData), associatedData) 47 | ) 48 | assertContentEquals( 49 | plaintext, 50 | daead.decryptDeterministically(daead.encryptDeterministically(plaintext, empty), empty) 51 | ) 52 | } 53 | 54 | @Test 55 | fun test_decrypt_given_invalid_associate_data_then_throws_error() { 56 | val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_SIV.template()) 57 | val daead = handle.getPrimitive(DeterministicAead::class) 58 | val plaintext = "plaintext".encodeToByteArray() 59 | val associatedData = "associatedData".encodeToByteArray() 60 | val ciphertext = daead.encryptDeterministically(plaintext, associatedData) 61 | val invalid = "invalid".encodeToByteArray() 62 | 63 | assertFailsWith { 64 | daead.decryptDeterministically(ciphertext, invalid) 65 | } 66 | } 67 | 68 | @Test 69 | fun test_decrypt_given_invalid_data_then_throws_error() { 70 | val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_SIV.template()) 71 | val daead = handle.getPrimitive(DeterministicAead::class) 72 | val associatedData = "associatedData".encodeToByteArray() 73 | val invalid = "invalid".encodeToByteArray() 74 | 75 | assertFailsWith { 76 | daead.decryptDeterministically(invalid, associatedData) 77 | } 78 | } 79 | 80 | @Test 81 | fun test_decrypt_given_empty_data_then_throws_error() { 82 | val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_SIV.template()) 83 | val daead = handle.getPrimitive(DeterministicAead::class) 84 | val associatedData = "associatedData".encodeToByteArray() 85 | val empty = "".encodeToByteArray() 86 | 87 | assertFailsWith { 88 | daead.decryptDeterministically(empty, associatedData) 89 | } 90 | } 91 | 92 | @Test 93 | fun test_decrypt_given_other_daead_then_throws_error() { 94 | val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_SIV.template()) 95 | val daead = handle.getPrimitive(DeterministicAead::class) 96 | val plaintext = "plaintext".encodeToByteArray() 97 | val associatedData = "associatedData".encodeToByteArray() 98 | val ciphertext = daead.encryptDeterministically(plaintext, associatedData) 99 | 100 | val otherHandle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_SIV.template()) 101 | val otherDaead = otherHandle.getPrimitive(DeterministicAead::class) 102 | 103 | assertFailsWith { 104 | otherDaead.decryptDeterministically(ciphertext, associatedData) 105 | } 106 | } 107 | 108 | @Test 109 | fun test_encrypt_given_json_keyset_then_success() { 110 | val handle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_DAEAD_KEYSET)) 111 | val daead = handle.getPrimitive(DeterministicAead::class) 112 | val plaintext: ByteArray = "plaintext".encodeToByteArray() 113 | val associatedData: ByteArray = "associatedData".encodeToByteArray() 114 | val ciphertext = daead.encryptDeterministically(plaintext, associatedData) 115 | val decrypted = daead.decryptDeterministically(ciphertext, associatedData) 116 | assertContentEquals(plaintext, decrypted) 117 | } 118 | 119 | @Test 120 | fun test_encrypt_given_multiple_keyset_then_success() { 121 | val plaintext: ByteArray = "plaintext".encodeToByteArray() 122 | val associatedData: ByteArray = "associatedData".encodeToByteArray() 123 | 124 | val primaryHandle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_DAEAD_KEYSET_WITH_MULTIPLE_KEYS)) 125 | val primaryDaead = primaryHandle.getPrimitive(DeterministicAead::class) 126 | assertContentEquals( 127 | plaintext, 128 | primaryDaead.decryptDeterministically( 129 | primaryDaead.encryptDeterministically(plaintext, associatedData), 130 | associatedData 131 | ) 132 | ) 133 | 134 | // Also test that daead can decrypt ciphertexts encrypted with a non-primary key. We use 135 | // JSON_DAEAD_KEYSET to encrypt with the first key. 136 | val secondaryHandle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_DAEAD_KEYSET)) 137 | val secondaryDaead = secondaryHandle.getPrimitive(DeterministicAead::class) 138 | assertContentEquals( 139 | plaintext, 140 | secondaryDaead.decryptDeterministically( 141 | secondaryDaead.encryptDeterministically(plaintext, associatedData), 142 | associatedData 143 | ) 144 | ) 145 | } 146 | 147 | private companion object { 148 | val JSON_DAEAD_KEYSET = """ 149 | { 150 | "primaryKeyId": 961932622, 151 | "key": [ 152 | { 153 | "keyData": { 154 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesSivKey", 155 | "keyMaterialType": "SYMMETRIC", 156 | "value": "EkCJ9r5iwc5uxq5ugFyrHXh5dijTa7qalWUgZ8Gf08RxNd545FjtLMYL7ObcaFtCSkvV2+7u6F2DN+kqUjAfkf2W" 157 | }, 158 | "outputPrefixType": "TINK", 159 | "keyId": 961932622, 160 | "status": "ENABLED" 161 | } 162 | ] 163 | } 164 | """.trimIndent() 165 | 166 | val JSON_DAEAD_KEYSET_WITH_MULTIPLE_KEYS = """ 167 | { 168 | "primaryKeyId": 385749617, 169 | "key": [ 170 | { 171 | "keyData": { 172 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesSivKey", 173 | "keyMaterialType": "SYMMETRIC", 174 | "value": "EkCJ9r5iwc5uxq5ugFyrHXh5dijTa7qalWUgZ8Gf08RxNd545FjtLMYL7ObcaFtCSkvV2+7u6F2DN+kqUjAfkf2W" 175 | }, 176 | "outputPrefixType": "TINK", 177 | "keyId": 961932622, 178 | "status": "ENABLED" 179 | }, 180 | { 181 | "keyData": { 182 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesSivKey", 183 | "value": "EkCGjyLCW8IOilSjFtkBOvpQoOA8ZsCAsFnCawU9ySiii3KefQkY4pGZcdlwJypOZem1/L+wPthYeCo4xmdq68hl", 184 | "keyMaterialType": "SYMMETRIC" 185 | }, 186 | "status": "ENABLED", 187 | "keyId": 385749617, 188 | "outputPrefixType": "RAW" 189 | }, 190 | { 191 | "keyData": { 192 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesSivKey", 193 | "value": "EkCCo6EJBokVl3uTcZMA5iCtQArJliOlBBBfjmZ+IHdLGCatgWJ/tsUi2cmpw0o3yXyJaJbyT06kUCEP+GvFIjCQ", 194 | "keyMaterialType": "SYMMETRIC" 195 | }, 196 | "status": "ENABLED", 197 | "keyId": 919668303, 198 | "outputPrefixType": "LEGACY" 199 | } 200 | ] 201 | } 202 | """.trimIndent() 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s 90 | ' "$PWD" ) || exit 91 | 92 | # Use the maximum available, or set MAX_FD != -1 to use that value. 93 | MAX_FD=maximum 94 | 95 | warn () { 96 | echo "$*" 97 | } >&2 98 | 99 | die () { 100 | echo 101 | echo "$*" 102 | echo 103 | exit 1 104 | } >&2 105 | 106 | # OS specific support (must be 'true' or 'false'). 107 | cygwin=false 108 | msys=false 109 | darwin=false 110 | nonstop=false 111 | case "$( uname )" in #( 112 | CYGWIN* ) cygwin=true ;; #( 113 | Darwin* ) darwin=true ;; #( 114 | MSYS* | MINGW* ) msys=true ;; #( 115 | NONSTOP* ) nonstop=true ;; 116 | esac 117 | 118 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 119 | 120 | 121 | # Determine the Java command to use to start the JVM. 122 | if [ -n "$JAVA_HOME" ] ; then 123 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 124 | # IBM's JDK on AIX uses strange locations for the executables 125 | JAVACMD=$JAVA_HOME/jre/sh/java 126 | else 127 | JAVACMD=$JAVA_HOME/bin/java 128 | fi 129 | if [ ! -x "$JAVACMD" ] ; then 130 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 131 | 132 | Please set the JAVA_HOME variable in your environment to match the 133 | location of your Java installation." 134 | fi 135 | else 136 | JAVACMD=java 137 | if ! command -v java >/dev/null 2>&1 138 | then 139 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 140 | 141 | Please set the JAVA_HOME variable in your environment to match the 142 | location of your Java installation." 143 | fi 144 | fi 145 | 146 | # Increase the maximum file descriptors if we can. 147 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 148 | case $MAX_FD in #( 149 | max*) 150 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 151 | # shellcheck disable=SC2039,SC3045 152 | MAX_FD=$( ulimit -H -n ) || 153 | warn "Could not query maximum file descriptor limit" 154 | esac 155 | case $MAX_FD in #( 156 | '' | soft) :;; #( 157 | *) 158 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 159 | # shellcheck disable=SC2039,SC3045 160 | ulimit -n "$MAX_FD" || 161 | warn "Could not set maximum file descriptor limit to $MAX_FD" 162 | esac 163 | fi 164 | 165 | # Collect all arguments for the java command, stacking in reverse order: 166 | # * args from the command line 167 | # * the main class name 168 | # * -classpath 169 | # * -D...appname settings 170 | # * --module-path (only if needed) 171 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 172 | 173 | # For Cygwin or MSYS, switch paths to Windows format before running java 174 | if "$cygwin" || "$msys" ; then 175 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 176 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 177 | 178 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 179 | 180 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 181 | for arg do 182 | if 183 | case $arg in #( 184 | -*) false ;; # don't mess with options #( 185 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 186 | [ -e "$t" ] ;; #( 187 | *) false ;; 188 | esac 189 | then 190 | arg=$( cygpath --path --ignore --mixed "$arg" ) 191 | fi 192 | # Roll the args list around exactly as many times as the number of 193 | # args, so each arg winds up back in the position where it started, but 194 | # possibly modified. 195 | # 196 | # NB: a `for` loop captures its iteration list before it begins, so 197 | # changing the positional parameters here affects neither the number of 198 | # iterations, nor the values presented in `arg`. 199 | shift # remove old arg 200 | set -- "$@" "$arg" # push replacement arg 201 | done 202 | fi 203 | 204 | 205 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 206 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 207 | 208 | # Collect all arguments for the java command: 209 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 210 | # and any embedded shellness will be escaped. 211 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 212 | # treated as '${Hostname}' itself on the command line. 213 | 214 | set -- \ 215 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 216 | -classpath "$CLASSPATH" \ 217 | org.gradle.wrapper.GradleWrapperMain \ 218 | "$@" 219 | 220 | # Stop when "xargs" is not available. 221 | if ! command -v xargs >/dev/null 2>&1 222 | then 223 | die "xargs is not available" 224 | fi 225 | 226 | # Use "xargs" to parse quoted args. 227 | # 228 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 229 | # 230 | # In Bash we could simply go: 231 | # 232 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 233 | # set -- "${ARGS[@]}" "$@" 234 | # 235 | # but POSIX shell has neither arrays nor command substitution, so instead we 236 | # post-process each arg (as a line of input to sed) to backslash-escape any 237 | # character that might be a shell metacharacter, then use eval to reverse 238 | # that process (while maintaining the separation between arguments), and wrap 239 | # the whole thing up as a single "set" statement. 240 | # 241 | # This will of course break if any of these variables contains a newline or 242 | # an unmatched quote. 243 | # 244 | 245 | eval "set -- $( 246 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 247 | xargs -n1 | 248 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 249 | tr '\n' ' ' 250 | )" '"$@"' 251 | 252 | exec "$JAVACMD" "$@" 253 | -------------------------------------------------------------------------------- /tink/src/commonTest/kotlin/io/github/ryunen344/tink/mac/MacTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.mac 2 | 3 | import io.github.ryunen344.tink.JsonKeysetReader 4 | import io.github.ryunen344.tink.KeyTemplateSet 5 | import io.github.ryunen344.tink.KeysetHandleGenerator 6 | import io.github.ryunen344.tink.daead.DeterministicAeadConfig 7 | import io.github.ryunen344.tink.daead.register 8 | import io.github.ryunen344.tink.exception.GeneralSecurityException 9 | import io.github.ryunen344.tink.generateNew 10 | import io.github.ryunen344.tink.getPrimitive 11 | import io.github.ryunen344.tink.readClearText 12 | import io.github.ryunen344.tink.template 13 | import kotlin.test.BeforeTest 14 | import kotlin.test.Test 15 | import kotlin.test.assertFailsWith 16 | 17 | class MacTest { 18 | 19 | private fun verify( 20 | set: KeyTemplateSet, 21 | data: ByteArray = "data".encodeToByteArray(), 22 | ) { 23 | val handle = KeysetHandleGenerator.generateNew(set.template()) 24 | val mac = handle.getPrimitive(Mac::class) 25 | val tag = mac.computeMac(data) 26 | mac.verifyMac(tag, data) 27 | } 28 | 29 | private fun invalid( 30 | set: KeyTemplateSet, 31 | ) { 32 | val handle = KeysetHandleGenerator.generateNew(set.template()) 33 | val mac = handle.getPrimitive(Mac::class) 34 | val data = "data".encodeToByteArray() 35 | val tag = mac.computeMac(data) 36 | 37 | val invalid = "invalid".encodeToByteArray() 38 | val empty = "".encodeToByteArray() 39 | 40 | assertFailsWith { mac.verifyMac(invalid, data) } 41 | assertFailsWith { mac.verifyMac(tag, invalid) } 42 | assertFailsWith { mac.verifyMac(empty, data) } 43 | assertFailsWith { mac.verifyMac(tag, empty) } 44 | } 45 | 46 | private fun other( 47 | set: KeyTemplateSet, 48 | ) { 49 | val handle = KeysetHandleGenerator.generateNew(set.template()) 50 | val mac = handle.getPrimitive(Mac::class) 51 | val data = "data".encodeToByteArray() 52 | val tag = mac.computeMac(data) 53 | 54 | val otherHandle = KeysetHandleGenerator.generateNew(set.template()) 55 | val otherMac = otherHandle.getPrimitive(Mac::class) 56 | 57 | assertFailsWith { otherMac.verifyMac(tag, data) } 58 | } 59 | 60 | @BeforeTest 61 | fun setup() { 62 | MacConfig.register() 63 | } 64 | 65 | @Test 66 | fun test_verify_HMAC_SHA256_128BITTAG_then_success() = verify(KeyTemplateSet.HMAC_SHA256_128BITTAG) 67 | 68 | @Test 69 | fun test_verify_HMAC_SHA256_128BITTAG_given_empty_data_then_success() = 70 | verify(KeyTemplateSet.HMAC_SHA256_128BITTAG, "".encodeToByteArray()) 71 | 72 | @Test 73 | fun test_verify_HMAC_SHA256_128BITTAG_given_invalid_data_then_throw_error() = 74 | invalid(KeyTemplateSet.HMAC_SHA256_128BITTAG) 75 | 76 | @Test 77 | fun test_verify_HMAC_SHA256_128BITTAG_when_verify_other_keyset_then_throw_error() = 78 | other(KeyTemplateSet.HMAC_SHA256_128BITTAG) 79 | 80 | @Test 81 | fun test_verify_HMAC_SHA256_256BITTAG_then_success() = verify(KeyTemplateSet.HMAC_SHA256_256BITTAG) 82 | 83 | @Test 84 | fun test_verify_HMAC_SHA256_256BITTAG_then_given_empty_data_then_success() = 85 | verify(KeyTemplateSet.HMAC_SHA256_256BITTAG, "".encodeToByteArray()) 86 | 87 | @Test 88 | fun test_verify_HMAC_SHA256_256BITTAG_then_given_invalid_data_then_throw_error() = 89 | invalid(KeyTemplateSet.HMAC_SHA256_256BITTAG) 90 | 91 | @Test 92 | fun test_verify_HMAC_SHA256_256BITTAG_then_when_verify_other_keyset_then_throw_error() = 93 | other(KeyTemplateSet.HMAC_SHA256_256BITTAG) 94 | 95 | @Test 96 | fun test_verify_HMAC_SHA512_256BITTAG_then_success() = verify(KeyTemplateSet.HMAC_SHA512_256BITTAG) 97 | 98 | @Test 99 | fun test_verify_HMAC_SHA512_256BITTAG_then_given_empty_data_then_success() = 100 | verify(KeyTemplateSet.HMAC_SHA512_256BITTAG, "".encodeToByteArray()) 101 | 102 | @Test 103 | fun test_verify_HMAC_SHA512_256BITTAG_then_given_invalid_data_then_throw_error() = 104 | invalid(KeyTemplateSet.HMAC_SHA512_256BITTAG) 105 | 106 | @Test 107 | fun test_verify_HMAC_SHA512_256BITTAG_when_verify_other_keyset_then_throw_error() = 108 | other(KeyTemplateSet.HMAC_SHA512_256BITTAG) 109 | 110 | @Test 111 | fun test_verify_HMAC_SHA512_512BITTAG_then_success() = verify(KeyTemplateSet.HMAC_SHA512_512BITTAG) 112 | 113 | @Test 114 | fun test_verify_HMAC_SHA512_512BITTAG_then_given_empty_data_then_success() = 115 | verify(KeyTemplateSet.HMAC_SHA512_512BITTAG, "".encodeToByteArray()) 116 | 117 | @Test 118 | fun test_verify_HMAC_SHA512_512BITTAG_then_given_invalid_data_then_throw_error() = 119 | invalid(KeyTemplateSet.HMAC_SHA512_512BITTAG) 120 | 121 | @Test 122 | fun test_verify_HMAC_SHA512_512BITTAG_when_verify_other_keyset_then_throw_error() = 123 | other(KeyTemplateSet.HMAC_SHA512_512BITTAG) 124 | 125 | @Test 126 | fun test_verify_AES_CMAC_then_success() = verify(KeyTemplateSet.AES_CMAC) 127 | 128 | @Test 129 | fun test_verify_AES_CMAC_then_given_empty_data_then_success() = 130 | verify(KeyTemplateSet.AES_CMAC, "".encodeToByteArray()) 131 | 132 | @Test 133 | fun test_verify_AES_CMAC_then_given_invalid_data_then_throw_error() = invalid(KeyTemplateSet.AES_CMAC) 134 | 135 | @Test 136 | fun test_verify_AES_CMAC_when_verify_other_keyset_then_throw_error() = other(KeyTemplateSet.AES_CMAC) 137 | 138 | @Test 139 | fun test_verify_given_json_keyset_then_success() { 140 | val handle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_MAC_KEYSET)) 141 | val mac = handle.getPrimitive(Mac::class) 142 | val data = "data".encodeToByteArray() 143 | val tag = mac.computeMac(data) 144 | mac.verifyMac(tag, data) 145 | } 146 | 147 | @Test 148 | fun test_verify_given_multiple_keyset_then_success() { 149 | val primaryHandle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_MAC_KEYSET_WITH_MULTIPLE_KEYS)) 150 | val primaryMac = primaryHandle.getPrimitive(Mac::class) 151 | val data = "data".encodeToByteArray() 152 | val tag = primaryMac.computeMac(data) 153 | primaryMac.verifyMac(tag, data) 154 | 155 | // Also test that mac can verify tags computed with a non-primary key. We use 156 | // JSON_MAC_KEYSET to compute a tag with the first key. 157 | val secondaryHandle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_MAC_KEYSET)) 158 | val secondaryMac = secondaryHandle.getPrimitive(Mac::class) 159 | val secondaryTag = secondaryMac.computeMac(data) 160 | primaryMac.verifyMac(secondaryTag, data) 161 | } 162 | 163 | @Test 164 | fun test_getPrimitive_given_NonMacKeyset_then_throws_error() { 165 | DeterministicAeadConfig.register() 166 | val handle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_DAEAD_KEYSET)) 167 | assertFailsWith { 168 | handle.getPrimitive(Mac::class) 169 | } 170 | } 171 | 172 | private companion object { 173 | val JSON_MAC_KEYSET = """ 174 | { 175 | "primaryKeyId": 207420876, 176 | "key": [ 177 | { 178 | "keyData": { 179 | "typeUrl": "type.googleapis.com/google.crypto.tink.HmacKey", 180 | "value": "GiAPii+kxtLpvCARQpftFLt4R+O6ARsyhTR7SkCCGt0bHRIEEBAIAw==", 181 | "keyMaterialType": "SYMMETRIC" 182 | }, 183 | "status": "ENABLED", 184 | "keyId": 207420876, 185 | "outputPrefixType": "TINK" 186 | } 187 | ] 188 | } 189 | """.trimIndent() 190 | 191 | val JSON_MAC_KEYSET_WITH_MULTIPLE_KEYS = """ 192 | { 193 | "primaryKeyId": 2054715504, 194 | "key": [ 195 | { 196 | "keyData": { 197 | "typeUrl": "type.googleapis.com/google.crypto.tink.HmacKey", 198 | "value": "GiAPii+kxtLpvCARQpftFLt4R+O6ARsyhTR7SkCCGt0bHRIEEBAIAw==", 199 | "keyMaterialType": "SYMMETRIC" 200 | }, 201 | "status": "ENABLED", 202 | "keyId": 207420876, 203 | "outputPrefixType": "TINK" 204 | }, 205 | { 206 | "keyData": { 207 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesCmacKey", 208 | "value": "GgIIEBIgLaZ/6QXYeqZB8F4zHTRJU5k6TF5xvlSX9ZVLVA09UY0=", 209 | "keyMaterialType": "SYMMETRIC" 210 | }, 211 | "status": "ENABLED", 212 | "keyId": 2054715504, 213 | "outputPrefixType": "RAW" 214 | }, 215 | { 216 | "keyData": { 217 | "typeUrl": "type.googleapis.com/google.crypto.tink.HmacKey", 218 | "value": "GkCCIGYpFz3mj8wnTH3Ca81F1sQ7JEMxoE8B2nKiND7LrKfbaUx+/qqDXUPVjkzC9XdbjsaEqc9yI+RKyITef+eUEgQQQAgE", 219 | "keyMaterialType": "SYMMETRIC" 220 | }, 221 | "status": "ENABLED", 222 | "keyId": 1540103625, 223 | "outputPrefixType": "LEGACY" 224 | }, 225 | { 226 | "keyData": { 227 | "typeUrl": "type.googleapis.com/google.crypto.tink.HmacKey", 228 | "value": "GkA8u6JKtInsySJDZO4j6TLoIvLuGAeAZHDZoTlST0aZZ8gZZViHogzWTqti2Vlp3ccy+OdN6lhMxSiphcPaR5OiEgQQIAgE", 229 | "keyMaterialType": "SYMMETRIC" 230 | }, 231 | "status": "ENABLED", 232 | "keyId": 570162478, 233 | "outputPrefixType": "CRUNCHY" 234 | } 235 | ] 236 | } 237 | """.trimIndent() 238 | 239 | val JSON_DAEAD_KEYSET = """ 240 | { 241 | "primaryKeyId": 961932622, 242 | "key": [ 243 | { 244 | "keyData": { 245 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesSivKey", 246 | "keyMaterialType": "SYMMETRIC", 247 | "value": "EkCJ9r5iwc5uxq5ugFyrHXh5dijTa7qalWUgZ8Gf08RxNd545FjtLMYL7ObcaFtCSkvV2+7u6F2DN+kqUjAfkf2W" 248 | }, 249 | "outputPrefixType": "TINK", 250 | "keyId": 961932622, 251 | "status": "ENABLED" 252 | } 253 | ] 254 | } 255 | """.trimIndent() 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /tink/src/commonTest/kotlin/io/github/ryunen344/tink/aead/AeadTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.aead 2 | 3 | import io.github.ryunen344.tink.JsonKeysetReader 4 | import io.github.ryunen344.tink.KeyTemplate 5 | import io.github.ryunen344.tink.KeyTemplateSet 6 | import io.github.ryunen344.tink.KeysetHandleGenerator 7 | import io.github.ryunen344.tink.daead.DeterministicAead 8 | import io.github.ryunen344.tink.daead.DeterministicAeadConfig 9 | import io.github.ryunen344.tink.daead.register 10 | import io.github.ryunen344.tink.exception.GeneralSecurityException 11 | import io.github.ryunen344.tink.generateNew 12 | import io.github.ryunen344.tink.getPrimitive 13 | import io.github.ryunen344.tink.readClearText 14 | import io.github.ryunen344.tink.template 15 | import kotlin.test.BeforeTest 16 | import kotlin.test.Test 17 | import kotlin.test.assertContentEquals 18 | import kotlin.test.assertFailsWith 19 | 20 | class AeadTest { 21 | 22 | @BeforeTest 23 | fun setup() { 24 | AeadConfig.register() 25 | } 26 | 27 | private fun encrypt( 28 | template: KeyTemplate, 29 | plaintext: ByteArray = "plaintext".encodeToByteArray(), 30 | associatedData: ByteArray = "associatedData".encodeToByteArray(), 31 | ) { 32 | val handle = KeysetHandleGenerator.generateNew(template) 33 | val aead = handle.getPrimitive(Aead::class) 34 | 35 | val ciphertext = aead.encrypt(plaintext, associatedData) 36 | val decrypted = aead.decrypt(ciphertext, associatedData) 37 | 38 | assertContentEquals(plaintext, decrypted) 39 | } 40 | 41 | private fun decryptInvalidAssociateData( 42 | template: KeyTemplate, 43 | ) { 44 | val handle = KeysetHandleGenerator.generateNew(template) 45 | val aead = handle.getPrimitive(Aead::class) 46 | val plaintext = "plaintext".encodeToByteArray() 47 | val invalid = "invalid".encodeToByteArray() 48 | 49 | assertFailsWith { 50 | aead.decrypt(plaintext, invalid) 51 | } 52 | } 53 | 54 | private fun decryptInvalidData( 55 | template: KeyTemplate, 56 | ) { 57 | val handle = KeysetHandleGenerator.generateNew(template) 58 | val aead = handle.getPrimitive(Aead::class) 59 | val associatedData = "associatedData".encodeToByteArray() 60 | val invalid = "invalid".encodeToByteArray() 61 | 62 | assertFailsWith { 63 | aead.decrypt(invalid, associatedData) 64 | } 65 | } 66 | 67 | @Test 68 | fun test_encrypt_AES128_GCM_then_success() = encrypt(KeyTemplateSet.AES128_GCM.template()) 69 | 70 | @Test 71 | fun test_encrypt_AES128_GCM_given_empty_then_success() = 72 | encrypt(KeyTemplateSet.AES128_GCM.template(), "".encodeToByteArray()) 73 | 74 | @Test 75 | fun test_encrypt_AES128_GCM_given_invalid_associate_data_then_throw_error() = 76 | decryptInvalidAssociateData(KeyTemplateSet.AES128_GCM.template()) 77 | 78 | @Test 79 | fun test_encrypt_AES128_GCM_given_invalid_data_then_throw_error() = 80 | decryptInvalidData(KeyTemplateSet.AES128_GCM.template()) 81 | 82 | @Test 83 | fun test_encrypt_AES128_GCM_RAW_then_success() = encrypt(KeyTemplateSet.AES128_GCM_RAW.template()) 84 | 85 | @Test 86 | fun test_encrypt_AES128_GCM_RAW_given_empty_then_success() = 87 | encrypt(KeyTemplateSet.AES128_GCM_RAW.template(), "".encodeToByteArray()) 88 | 89 | @Test 90 | fun test_encrypt_AES128_GCM_RAW_given_invalid_associate_data_then_throw_error() = 91 | decryptInvalidAssociateData(KeyTemplateSet.AES128_GCM_RAW.template()) 92 | 93 | @Test 94 | fun test_encrypt_AES128_GCM_RAW_given_invalid_data_then_throw_error() = 95 | decryptInvalidData(KeyTemplateSet.AES128_GCM_RAW.template()) 96 | 97 | @Test 98 | fun test_encrypt_AES256_GCM_then_success() = encrypt(KeyTemplateSet.AES256_GCM.template()) 99 | 100 | @Test 101 | fun test_encrypt_AES256_GCM_given_empty_then_success() = 102 | encrypt(KeyTemplateSet.AES256_GCM.template(), "".encodeToByteArray()) 103 | 104 | @Test 105 | fun test_encrypt_AES256_GCM_given_invalid_associate_data_then_throw_error() = 106 | decryptInvalidAssociateData(KeyTemplateSet.AES256_GCM.template()) 107 | 108 | @Test 109 | fun test_encrypt_AES256_GCM_given_invalid_data_then_throw_error() = 110 | decryptInvalidData(KeyTemplateSet.AES256_GCM.template()) 111 | 112 | @Test 113 | fun test_encrypt_AES256_GCM_RAW_then_success() = encrypt(KeyTemplateSet.AES256_GCM_RAW.template()) 114 | 115 | @Test 116 | fun test_encrypt_AES256_GCM_RAW_given_empty_then_success() = 117 | encrypt(KeyTemplateSet.AES256_GCM_RAW.template(), "".encodeToByteArray()) 118 | 119 | @Test 120 | fun test_encrypt_AES256_GCM_RAW_given_invalid_associate_data_then_throw_error() = 121 | decryptInvalidAssociateData(KeyTemplateSet.AES256_GCM_RAW.template()) 122 | 123 | @Test 124 | fun test_encrypt_AES256_GCM_RAW_given_invalid_data_then_throw_error() = 125 | decryptInvalidData(KeyTemplateSet.AES256_GCM_RAW.template()) 126 | 127 | @Test 128 | fun test_encrypt_AES128_CTR_HMAC_SHA256_then_success() = encrypt(KeyTemplateSet.AES128_CTR_HMAC_SHA256.template()) 129 | 130 | @Test 131 | fun test_encrypt_AES128_CTR_HMAC_SHA256_given_empty_then_success() = 132 | encrypt(KeyTemplateSet.AES128_CTR_HMAC_SHA256.template(), "".encodeToByteArray()) 133 | 134 | @Test 135 | fun test_encrypt_AES128_CTR_HMAC_SHA256_given_invalid_associate_data_then_throw_error() = 136 | decryptInvalidAssociateData(KeyTemplateSet.AES128_CTR_HMAC_SHA256.template()) 137 | 138 | @Test 139 | fun test_encrypt_AES128_CTR_HMAC_SHA256_given_invalid_data_then_throw_error() = 140 | decryptInvalidData(KeyTemplateSet.AES128_CTR_HMAC_SHA256.template()) 141 | 142 | @Test 143 | fun test_encrypt_AES256_CTR_HMAC_SHA256_then_success() = encrypt(KeyTemplateSet.AES256_CTR_HMAC_SHA256.template()) 144 | 145 | @Test 146 | fun test_encrypt_AES256_CTR_HMAC_SHA256_given_empty_then_success() = 147 | encrypt(KeyTemplateSet.AES256_CTR_HMAC_SHA256.template(), "".encodeToByteArray()) 148 | 149 | @Test 150 | fun test_encrypt_AES256_CTR_HMAC_SHA256_given_invalid_associate_data_then_throw_error() = 151 | decryptInvalidAssociateData(KeyTemplateSet.AES256_CTR_HMAC_SHA256.template()) 152 | 153 | @Test 154 | fun test_encrypt_AES256_CTR_HMAC_SHA256_given_invalid_data_then_throw_error() = 155 | decryptInvalidData(KeyTemplateSet.AES256_CTR_HMAC_SHA256.template()) 156 | 157 | @Test 158 | fun test_encrypt_AES128_EAX_then_success() = encrypt(KeyTemplateSet.AES128_EAX.template()) 159 | 160 | @Test 161 | fun test_encrypt_AES128_EAX_then_given_empty_success() = 162 | encrypt(KeyTemplateSet.AES128_EAX.template(), "".encodeToByteArray()) 163 | 164 | @Test 165 | fun test_encrypt_AES128_EAX_given_invalid_associate_data_then_throw_error() = 166 | decryptInvalidAssociateData(KeyTemplateSet.AES128_EAX.template()) 167 | 168 | @Test 169 | fun test_encrypt_AES128_EAX_given_invalid_data_then_throw_error() = 170 | decryptInvalidData(KeyTemplateSet.AES128_EAX.template()) 171 | 172 | @Test 173 | fun test_encrypt_AES256_EAX_then_success() = encrypt(KeyTemplateSet.AES256_EAX.template()) 174 | 175 | @Test 176 | fun test_encrypt_AES256_EAX_then_given_empty_success() = 177 | encrypt(KeyTemplateSet.AES256_EAX.template(), "".encodeToByteArray()) 178 | 179 | @Test 180 | fun test_encrypt_AES256_EAX_given_invalid_associate_data_then_throw_error() = 181 | decryptInvalidAssociateData(KeyTemplateSet.AES256_EAX.template()) 182 | 183 | @Test 184 | fun test_encrypt_AES256_EAX_given_invalid_data_then_throw_error() = 185 | decryptInvalidData(KeyTemplateSet.AES256_EAX.template()) 186 | 187 | @Test 188 | fun test_encrypt_XCHACHA20_POLY1305_then_success() = encrypt(KeyTemplateSet.XCHACHA20_POLY1305.template()) 189 | 190 | @Test 191 | fun test_encrypt_XCHACHA20_POLY1305_given_empty_then_success() = 192 | encrypt(KeyTemplateSet.XCHACHA20_POLY1305.template(), "".encodeToByteArray()) 193 | 194 | @Test 195 | fun test_encrypt_XCHACHA20_POLY1305_given_invalid_associate_data_then_throw_error() = 196 | decryptInvalidAssociateData(KeyTemplateSet.XCHACHA20_POLY1305.template()) 197 | 198 | @Test 199 | fun test_encrypt_XCHACHA20_POLY1305_given_invalid_data_then_throw_error() = 200 | decryptInvalidData(KeyTemplateSet.XCHACHA20_POLY1305.template()) 201 | 202 | @Test 203 | fun test_encrypt_given_json_keyset_then_success() { 204 | val handle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_AEAD_KEYSET)) 205 | val aead = handle.getPrimitive(Aead::class) 206 | val plaintext: ByteArray = "plaintext".encodeToByteArray() 207 | val associatedData: ByteArray = "associatedData".encodeToByteArray() 208 | val ciphertext = aead.encrypt(plaintext, associatedData) 209 | val decrypted = aead.decrypt(ciphertext, associatedData) 210 | assertContentEquals(plaintext, decrypted) 211 | } 212 | 213 | @Test 214 | fun test_encrypt_given_multiple_keyset_then_success() { 215 | val plaintext: ByteArray = "plaintext".encodeToByteArray() 216 | val associatedData: ByteArray = "associatedData".encodeToByteArray() 217 | 218 | val primaryHandle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_AEAD_KEYSET_WITH_MULTIPLE_KEYS)) 219 | val primaryAead = primaryHandle.getPrimitive(Aead::class) 220 | assertContentEquals( 221 | plaintext, 222 | primaryAead.decrypt( 223 | primaryAead.encrypt(plaintext, associatedData), 224 | associatedData 225 | ) 226 | ) 227 | 228 | // Also test that aead can decrypt ciphertexts encrypted with a non-primary key. We use 229 | // JSON_AEAD_KEYSET to encrypt with the first key. 230 | val subHandle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_AEAD_KEYSET)) 231 | val subAead = subHandle.getPrimitive(Aead::class) 232 | assertContentEquals( 233 | plaintext, 234 | subAead.decrypt( 235 | subAead.encrypt(plaintext, associatedData), 236 | associatedData 237 | ) 238 | ) 239 | } 240 | 241 | @Test 242 | fun test_getPrimitive_given_NonAeadKeyset_then_throws_error() { 243 | DeterministicAeadConfig.register() 244 | val handle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_DAEAD_KEYSET)) 245 | handle.getPrimitive(DeterministicAead::class) 246 | 247 | assertFailsWith { 248 | handle.getPrimitive(Aead::class) 249 | } 250 | } 251 | 252 | private companion object { 253 | val JSON_AEAD_KEYSET = """ 254 | { 255 | "primaryKeyId": 42818733, 256 | "key": [ 257 | { 258 | "keyData": { 259 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey", 260 | "keyMaterialType": "SYMMETRIC", 261 | "value": "GhCC74uJ+2f4qlpaHwR4ylNQ" 262 | }, 263 | "outputPrefixType": "TINK", 264 | "keyId": 42818733, 265 | "status": "ENABLED" 266 | } 267 | ] 268 | } 269 | """.trimIndent() 270 | 271 | val JSON_AEAD_KEYSET_WITH_MULTIPLE_KEYS = """ 272 | { 273 | "primaryKeyId": 365202604, 274 | "key": [ 275 | { 276 | "keyData": { 277 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey", 278 | "keyMaterialType": "SYMMETRIC", 279 | "value": "GhCC74uJ+2f4qlpaHwR4ylNQ" 280 | }, 281 | "outputPrefixType": "TINK", 282 | "keyId": 42818733, 283 | "status": "ENABLED" 284 | }, 285 | { 286 | "keyData": { 287 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesEaxKey", 288 | "keyMaterialType": "SYMMETRIC", 289 | "value": "EgIIEBogU4nieBfIeJHBrhC+TjezFgxkkuhQHbyWkUMH+7atLxI=" 290 | }, 291 | "outputPrefixType": "RAW", 292 | "keyId": 365202604, 293 | "status": "ENABLED" 294 | }, 295 | { 296 | "keyData": { 297 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey", 298 | "keyMaterialType": "SYMMETRIC", 299 | "value": "GigaIMttlipP/JvQOpIB0NYhDPoLgWBiIxmtaWbSPa2TeQOmEgQQEAgDEhYaEPcCMmPLgRGhmMmSC4AJ1CESAggQ" 300 | }, 301 | "outputPrefixType": "LEGACY", 302 | "keyId": 277095770, 303 | "status": "ENABLED" 304 | } 305 | ] 306 | } 307 | """.trimIndent() 308 | 309 | val JSON_DAEAD_KEYSET = """ 310 | { 311 | "primaryKeyId": 961932622, 312 | "key": [ 313 | { 314 | "keyData": { 315 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesSivKey", 316 | "keyMaterialType": "SYMMETRIC", 317 | "value": "EkCJ9r5iwc5uxq5ugFyrHXh5dijTa7qalWUgZ8Gf08RxNd545FjtLMYL7ObcaFtCSkvV2+7u6F2DN+kqUjAfkf2W" 318 | }, 319 | "outputPrefixType": "TINK", 320 | "keyId": 961932622, 321 | "status": "ENABLED" 322 | } 323 | ] 324 | } 325 | """.trimIndent() 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tink-KMM 2 | 3 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.ryunen344.tink/tink/badge.svg?style=plastic&gav=true)](https://maven-badges.herokuapp.com/maven-central/io.github.ryunen344.tink/tink) 4 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 5 | [![test](https://github.com/RyuNen344/tink-kmm/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/RyuNen344/tink-kmm/actions/workflows/test.yml) 6 | [![codecov](https://codecov.io/gh/RyuNen344/tink-kmm/branch/main/graph/badge.svg?token=21Z06YR92T)](https://codecov.io/gh/RyuNen344/tink-kmm) 7 | ![badge-android](http://img.shields.io/badge/-android-6EDB8D.svg?style=flat) 8 | ![badge-ios](http://img.shields.io/badge/-ios-CDCDCD.svg?style=flat) 9 | ![badge-silicon](http://img.shields.io/badge/support-[AppleSilicon]-43BBFF.svg?style=flat) 10 | 11 | This is a repositoy of [Google/Tink](https://github.com/google/tink) Mapper for KMM(Kotlin Multiplatform Mobile)
12 | This wrapper library allows you to use Tink Primitive Encryption in your Kotlin Multiplatform Mobile project.
13 | 14 | ## Why this library? 15 | 16 | KMM currently does not have a Crypto Library that can be used as a de facto standard.
17 | Of course, we can implement encryption using the expect/actual modifier.
18 | But, CCCrypto has a limitation of supported algorithm.(e.g, it can not be use AES-GCM)
19 | 20 | ## Tink Primitives 21 | 22 | | **Primitive** | **Interfaces** | 23 | | ---------------------------------------------------- | ------------------------------ | 24 | | Authenticated Encryption with Associated Data (AEAD) | AEAD | 25 | | _Streaming_ AEAD | StreamingAEAD | 26 | | _Deterministic_ AEAD | DeterministicAEAD | 27 | | Message Authentication Code (MAC) | MAC | 28 | | Pseudo Random Function Family (PRF) | Prf, PrfSet | 29 | | Hybrid encryption | HybridEncrypt, HybridDecrypt | 30 | | Digital signatures | PublicKeySign, PublicKeyVerify | 31 | 32 | ### Supported primitives and their implementations 33 | 34 | #### Primitives supported by language 35 | 36 | | **Primitive** | **Java** | **Objective-C** | **Tink-KMM** | 37 | | ------------------ | :------: | :-------------: | :----------: | 38 | | AEAD | yes | yes | yes | 39 | | Streaming AEAD | yes | **no** | **no** | 40 | | Deterministic AEAD | yes | yes | yes | 41 | | MAC | yes | yes | yes | 42 | | PRF | yes | **no** | **no** | 43 | | Digital signatures | yes | yes | yes | 44 | | Hybrid encryption | yes | yes | yes | 45 | 46 | #### Primitive implementations supported by language 47 | 48 | | **Primitive** | **Implementation** | **Java** | **Objective-C** | **Tink-KMM** | 49 | | ------------------ | ------------------------------------- | :------: | :-------------: | :----------: | 50 | | AEAD | AES-GCM | yes | yes | yes | 51 | | | AES-GCM-SIV | yes | **no** | **no** | 52 | | | AES-CTR-HMAC | yes | yes | yes | 53 | | | AES-EAX | yes | yes | yes | 54 | | | KMS Envelope | yes | **no** | **no** | 55 | | | CHACHA20-POLY1305 | yes | **no** | **no** | 56 | | | XCHACHA20-POLY1305 | yes | yes | yes | 57 | | Streaming AEAD | AES-GCM-HKDF-STREAMING | yes | **no** | **no** | 58 | | | AES-CTR-HMAC-STREAMING | yes | **no** | **no** | 59 | | Deterministic AEAD | AES-SIV | yes | yes | yes | 60 | | MAC | HMAC-SHA2 | yes | yes | yes | 61 | | | AES-CMAC | yes | yes | yes | 62 | | PRF | HKDF-SHA2 | yes | **no** | **no** | 63 | | | HMAC-SHA2 | yes | **no** | **no** | 64 | | | AES-CMAC | yes | **no** | **no** | 65 | | Digital Signatures | ECDSA over NIST curves | yes | yes | yes | 66 | | | Ed25519 | yes | yes | yes | 67 | | | RSA-SSA-PKCS1 | yes | yes | yes | 68 | | | RSA-SSA-PSS | yes | yes | yes | 69 | | Hybrid Encryption | HPKE | yes | **no** | **no** | 70 | | | ECIES with AEAD and HKDF | yes | yes | yes | 71 | | | ECIES with DeterministicAEAD and HKDF | yes | **no** | **no** | 72 | 73 | ## Compatibility 74 | 75 | | **Version** | **Kotlin** | **Tink-android** | **Tink-ObjC** | 76 | |---------------|:----------:| :--------------: | :-----------: | 77 | | 0.0.1 | 1.8.20 | 1.7.0 | 1.7.0 | 78 | | 0.0.2 ~ 0.0.3 | 1.8.21 | 1.7.0 | 1.7.0 | 79 | | 0.0.4 | 1.8.22 | 1.7.0 | 1.7.0 | 80 | | 0.0.5 | 1.9.0 | 1.7.0 | 1.7.0 | 81 | | 0.0.6 | 1.9.10 | 1.7.0 | 1.7.0 | 82 | | 0.0.7 | 1.9.21 | 1.7.0 | 1.7.0 | 83 | 84 | > **Warning**
85 | > Tink-ObjC 1.7.0 has not been released to CocoaPods yet.


86 | > so, you need to build Tink-ObjC 1.7.0 by yourself.
87 | > you can use my fork [RyuNen344/tink](https://github.com/RyuNen344/tink), and [Makefile](Makefile) can be used as a reference about how to build Tink-ObjC 1.7.0.
88 | 89 | ## Installation 90 | 91 | add the following to your `settings.gradle` and `build.gradle` file: 92 | 93 | ```kotlin:settings.gradle 94 | repositories { 95 | mavenCentral() 96 | } 97 | ``` 98 | 99 | ```kotlin:build.gradle 100 | kotlin { 101 | // if you want to use without CocoaPods, you need to link with your Tink.framework like below. 102 | iosX64 { 103 | binaries { 104 | framework { 105 | linkerOpts( 106 | listOf( 107 | "-framework", 108 | "Tink", 109 | "-Fpath/to/Tink.framework", 110 | "-rpath", 111 | "path/to/Tink.framework", 112 | "-ObjC", 113 | ) 114 | ) 115 | } 116 | } 117 | } 118 | 119 | commonMain { 120 | dependencies { 121 | implementation "io.github.ryunen344.tink:tink:$tink_kmm_version" 122 | } 123 | } 124 | } 125 | ``` 126 | 127 | ## Usage 128 | 129 | you can use Tink-KMM like java Tink. 130 | 131 | ### Initialization 132 | 133 | ```kotlin 134 | import io.github.ryunen344.tink.aead.AeadConfig 135 | import io.github.ryunen344.tink.aead.register 136 | import io.github.ryunen344.tink.daead.DeterministicAeadConfig 137 | import io.github.ryunen344.tink.daead.register 138 | import io.github.ryunen344.tink.hybrid.HybridConfig 139 | import io.github.ryunen344.tink.hybrid.register 140 | import io.github.ryunen344.tink.mac.MacConfig 141 | import io.github.ryunen344.tink.mac.register 142 | import io.github.ryunen344.tink.signature.SignatureConfig 143 | import io.github.ryunen344.tink.signature.register 144 | 145 | AeadConfig.register() 146 | DeterministicAeadConfig.register() 147 | HybridConfig.register() 148 | MacConfig.register() 149 | SignatureConfig.register() 150 | ``` 151 | 152 | ### Generate new keys and keysets 153 | 154 | ```kotlin 155 | import io.github.ryunen344.tink.KeyTemplateSet 156 | import io.github.ryunen344.tink.KeysetHandleGenerator 157 | import io.github.ryunen344.tink.generateNew 158 | 159 | KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_GCM.template()) 160 | ``` 161 | 162 | > **Note** 163 | > Defined available key templates in [KeyTemplateSet](tink/src/commonMain/kotlin/io/github/ryunen344/tink/KeyTemplateSet.kt) 164 | 165 | ### Serialize and Deserialize 166 | 167 | #### Serialize with KeysetWriter 168 | 169 | ##### Cleartext 170 | 171 | ```kotlin:SerializeCleartext.kt 172 | val writer = BinaryKeysetWriter() 173 | 174 | // 1. write keyset to writer 175 | handle.writeCleartext(writer) 176 | 177 | // 2. get ByteArray from writer and save serialized somewhere 178 | val serialized = writer.write() 179 | ``` 180 | 181 | ##### NoSecret 182 | 183 | ```kotlin:SerializeNoSecret.kt 184 | val writer = BinaryKeysetWriter() 185 | 186 | // 1. write keyset to writer 187 | handle.writeNoSecret(writer) 188 | 189 | // 2. get ByteArray from writer(if keyset has secret key, throw exception) 190 | val serialized = writer.write() 191 | ``` 192 | 193 | #### Deserialize with KeysetReader 194 | 195 | ##### Binary 196 | 197 | ```kotlin:Deserialize.kt 198 | // read with AEAD 199 | val masterKey: AEAD 200 | KeysetHandleGenerator.read(serialized, masterKey) 201 | 202 | // read ByteArray from somewhere 203 | KeysetHandleGenerator.readClearText(BinaryKeysetReader(serialized)) 204 | 205 | // read json string from somewhere 206 | KeysetHandleGenerator.readClearText(JsonKeysetReader("json string")) 207 | 208 | // read ByteArray with secret key from somewhere 209 | KeysetHandleGenerator.readNoSecret(serialized) 210 | ``` 211 | 212 | ### Obtaining and using primitives 213 | 214 | #### AEAD 215 | 216 | ```kotlin:Aead.kt 217 | import io.github.ryunen344.tink.aead.Aead 218 | import io.github.ryunen344.tink.KeyTemplateSet 219 | import io.github.ryunen344.tink.KeysetHandleGenerator 220 | import io.github.ryunen344.tink.generateNew 221 | import io.github.ryunen344.tink.getPrimitive 222 | 223 | // 1. Generate the key material. 224 | val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_GCM.template()) 225 | 226 | // 2. Get the primitive. 227 | val aead = handle.getPrimitive(Aead::class) 228 | 229 | // 3. Use the primitive to encrypt a plaintext, 230 | val ciphertext = aead.encrypt(plaintext, associatedData) 231 | 232 | // ... or to decrypt a ciphertext. 233 | val decrypted = aead.decrypt(ciphertext, associatedData) 234 | ``` 235 | 236 | #### DeterministicAEAD 237 | 238 | ```kotlin:DeterministicAead.kt 239 | import io.github.ryunen344.tink.daead.DeterministicAead 240 | import io.github.ryunen344.tink.KeyTemplateSet 241 | import io.github.ryunen344.tink.KeysetHandleGenerator 242 | import io.github.ryunen344.tink.generateNew 243 | import io.github.ryunen344.tink.getPrimitive 244 | 245 | // 1. Generate the key material. 246 | val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.AES256_GCM.template()) 247 | 248 | // 2. Get the primitive. 249 | val daead = handle.getPrimitive(DeterministicAead::class) 250 | 251 | // 3. Use the primitive to encrypt a plaintext, 252 | val ciphertext = daead.encrypt(plaintext, associatedData) 253 | 254 | // ... or to decrypt a ciphertext. 255 | val decrypted = daead.decrypt(ciphertext, associatedData) 256 | ``` 257 | 258 | #### HybridAEAD 259 | 260 | ```kotlin:HybridAead.kt 261 | import io.github.ryunen344.tink.hybrid.HybridEncrypt 262 | import io.github.ryunen344.tink.hybrid.HybridDecrypt 263 | import io.github.ryunen344.tink.KeyTemplateSet 264 | import io.github.ryunen344.tink.KeysetHandleGenerator 265 | import io.github.ryunen344.tink.generateNew 266 | import io.github.ryunen344.tink.getPrimitive 267 | import io.github.ryunen344.tink.publicKeysetHandle 268 | 269 | // 1. Generate the key material. 270 | val privateKeysetHandle = KeysetHandleGenerator.generateNew(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM.template()) 271 | val publicKeysetHandle = privateKeysetHandle.publicKeysetHandle() 272 | 273 | // 2. Get the primitives. 274 | val hybridEncrypt = publicKeysetHandle.getPrimitive(HybridEncrypt::class) 275 | val hybridDecrypt = privateKeysetHandle.getPrimitive(HybridDecrypt::class) 276 | 277 | // 3. Use the primitives to encrypt and decrypt. 278 | val ciphertext = hybridEncrypt.encrypt(plaintext, contextInfo) 279 | val decrypted = hybridDecrypt.decrypt(ciphertext, contextInfo) 280 | ``` 281 | 282 | #### MAC 283 | 284 | ```kotlin:Mac.kt 285 | import io.github.ryunen344.tink.mac.Mac 286 | import io.github.ryunen344.tink.KeyTemplateSet 287 | import io.github.ryunen344.tink.KeysetHandleGenerator 288 | import io.github.ryunen344.tink.generateNew 289 | import io.github.ryunen344.tink.getPrimitive 290 | 291 | // 1. Generate the key material. 292 | val handle = KeysetHandleGenerator.generateNew(KeyTemplateSet.HMAC_SHA256_128BITTAG.template()) 293 | 294 | // 2. Get the primitive. 295 | val mac = handle.getPrimitive(Mac::class) 296 | 297 | // 3. Use the primitive to compute a tag. 298 | val tag = mac.computeMac(plaintext) 299 | 300 | // ... or to verify a tag. 301 | mac.verifyMac(tag, plaintext) 302 | ``` 303 | 304 | #### Signature 305 | 306 | ```kotlin:Signature.kt 307 | import io.github.ryunen344.tink.signature.PublicKeySign 308 | import io.github.ryunen344.tink.signature.PublicKeyVerify 309 | import io.github.ryunen344.tink.KeyTemplateSet 310 | import io.github.ryunen344.tink.KeysetHandleGenerator 311 | import io.github.ryunen344.tink.generateNew 312 | import io.github.ryunen344.tink.getPrimitive 313 | import io.github.ryunen344.tink.publicKeysetHandle 314 | 315 | // 1. Generate the key material. 316 | val privateHandle = KeysetHandleGenerator.generateNew(KeyTemplateSet.ECDSA_P256.template()) 317 | val publicHandle = privateHandle.publicKeysetHandle() 318 | 319 | // 2. Get the primitive. 320 | val signer = privateHandle.getPrimitive(PublicKeySign::class) 321 | val verifier = publicHandle.getPrimitive(PublicKeyVerify::class) 322 | 323 | // 3. Use the primitive to sign a message. 324 | val signature = signer.sign(message) 325 | 326 | // ... or to verify a signature. 327 | verifier.verify(signature, message) 328 | ``` 329 | 330 | #### Swift(Optional) 331 | 332 | This library also supports be used in Swift directory. 333 | 334 | ```swift 335 | try! AeadConfig.companion.register() 336 | let template = try! KeyTemplateSet.aes256Gcm.template() 337 | let handle = try! KeysetHandleGenerator.companion.generateNew(keyTemplate: template) 338 | let aead = try! KeysetHandleKt.getPrimitive(handle, kClass: TinkPrimitiveKt.aead) as! Aead 339 | let ciphertext = try! aead.encrypt(plaintext, with: associatedData) 340 | let decrypted = try! aead.decrypt(ciphertext, with: associatedData) 341 | ``` 342 | -------------------------------------------------------------------------------- /tink/src/commonTest/kotlin/io/github/ryunen344/tink/hybrid/HybridTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.ryunen344.tink.hybrid 2 | 3 | import io.github.ryunen344.tink.JsonKeysetReader 4 | import io.github.ryunen344.tink.KeyTemplateSet 5 | import io.github.ryunen344.tink.KeysetHandleGenerator 6 | import io.github.ryunen344.tink.daead.DeterministicAead 7 | import io.github.ryunen344.tink.daead.DeterministicAeadConfig 8 | import io.github.ryunen344.tink.daead.register 9 | import io.github.ryunen344.tink.exception.GeneralSecurityException 10 | import io.github.ryunen344.tink.generateNew 11 | import io.github.ryunen344.tink.getPrimitive 12 | import io.github.ryunen344.tink.publicKeysetHandle 13 | import io.github.ryunen344.tink.readClearText 14 | import io.github.ryunen344.tink.template 15 | import kotlin.test.BeforeTest 16 | import kotlin.test.Test 17 | import kotlin.test.assertContentEquals 18 | import kotlin.test.assertFailsWith 19 | 20 | class HybridTest { 21 | 22 | private fun verify( 23 | set: KeyTemplateSet, 24 | plaintext: ByteArray = "plaintext".encodeToByteArray(), 25 | contextInfo: ByteArray = "contextInfo".encodeToByteArray(), 26 | ) { 27 | val privateHandle = KeysetHandleGenerator.generateNew(set.template()) 28 | val publicHandle = privateHandle.publicKeysetHandle() 29 | val encryptor = publicHandle.getPrimitive(HybridEncrypt::class) 30 | val decryptor = privateHandle.getPrimitive(HybridDecrypt::class) 31 | 32 | val cipherText = encryptor.encrypt(plaintext, contextInfo) 33 | assertContentEquals( 34 | plaintext, 35 | decryptor.decrypt(cipherText, contextInfo) 36 | ) 37 | } 38 | 39 | private fun invalidData( 40 | set: KeyTemplateSet, 41 | ) { 42 | val privateHandle = KeysetHandleGenerator.generateNew(set.template()) 43 | val decryptor = privateHandle.getPrimitive(HybridDecrypt::class) 44 | 45 | val contextInfo = "contextInfo".encodeToByteArray() 46 | val invalid = "invalid".encodeToByteArray() 47 | 48 | assertFailsWith { 49 | decryptor.decrypt(invalid, contextInfo) 50 | } 51 | } 52 | 53 | private fun invalidContextInfo( 54 | set: KeyTemplateSet, 55 | ) { 56 | val privateHandle = KeysetHandleGenerator.generateNew(set.template()) 57 | val publicHandle = privateHandle.publicKeysetHandle() 58 | val encryptor = publicHandle.getPrimitive(HybridEncrypt::class) 59 | val decryptor = privateHandle.getPrimitive(HybridDecrypt::class) 60 | 61 | val plaintext = "plaintext".encodeToByteArray() 62 | val contextInfo = "contextInfo".encodeToByteArray() 63 | val invalid = "invalid".encodeToByteArray() 64 | val cipherText = encryptor.encrypt(plaintext, contextInfo) 65 | 66 | assertFailsWith { 67 | decryptor.decrypt(cipherText, invalid) 68 | } 69 | } 70 | 71 | private fun match( 72 | set: KeyTemplateSet, 73 | ) { 74 | val privateHandle = KeysetHandleGenerator.generateNew(set.template()) 75 | val publicHandle = privateHandle.publicKeysetHandle() 76 | val encryptor = publicHandle.getPrimitive(HybridEncrypt::class) 77 | 78 | val plaintext = "plaintext".encodeToByteArray() 79 | val contextInfo = "contextInfo".encodeToByteArray() 80 | val cipherText = encryptor.encrypt(plaintext, contextInfo) 81 | 82 | val otherHandle = KeysetHandleGenerator.generateNew(set.template()) 83 | val otherDecrypter = otherHandle.getPrimitive(HybridDecrypt::class) 84 | 85 | assertFailsWith { 86 | otherDecrypter.decrypt(cipherText, contextInfo) 87 | } 88 | } 89 | 90 | @BeforeTest 91 | fun setup() { 92 | HybridConfig.register() 93 | } 94 | 95 | @Test 96 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM_then_success() = 97 | verify(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM) 98 | 99 | @Test 100 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM_given_empty_data_then_success() = 101 | verify(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM, plaintext = "".encodeToByteArray()) 102 | 103 | @Test 104 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM_given_empty_context_info_then_success() = 105 | verify(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM, contextInfo = "".encodeToByteArray()) 106 | 107 | @Test 108 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM_given_invalid_data_then_throw_error() = 109 | invalidData(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM) 110 | 111 | @Test 112 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM_given_invalid_context_then_throw_error() = 113 | invalidContextInfo(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM) 114 | 115 | @Test 116 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM_when_not_match_keyset_then_throw_error() = 117 | match(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM) 118 | 119 | @Test 120 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256_then_success() = 121 | verify(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256) 122 | 123 | @Test 124 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256_given_empty_data_then_success() = 125 | verify(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256, plaintext = "".encodeToByteArray()) 126 | 127 | @Test 128 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256_given_empty_context_info_then_success() = 129 | verify(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256, contextInfo = "".encodeToByteArray()) 130 | 131 | @Test 132 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256_given_invalid_data_then_throw_error() = 133 | invalidData(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256) 134 | 135 | @Test 136 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256_given_invalid_context_then_throw_error() = 137 | invalidContextInfo(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256) 138 | 139 | @Test 140 | fun test_encrypt_ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256_when_not_match_keyset_then_throw_error() = 141 | match(KeyTemplateSet.ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256) 142 | 143 | @Test 144 | fun test_encrypt_given_json_keyset_then_success() { 145 | val privateHandle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_PRIVATE_KEYSET)) 146 | val publicHandle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_PUBLIC_KEYSET)) 147 | 148 | val encryptor = publicHandle.getPrimitive(HybridEncrypt::class) 149 | val decryptor = privateHandle.getPrimitive(HybridDecrypt::class) 150 | 151 | val plaintext = "plaintext".encodeToByteArray() 152 | val contextInfo = "contextInfo".encodeToByteArray() 153 | val ciphertext = encryptor.encrypt(plaintext, contextInfo) 154 | val decrypted = decryptor.decrypt(ciphertext, contextInfo) 155 | assertContentEquals(plaintext, decrypted) 156 | } 157 | 158 | @Test 159 | fun test_encrypt_given_multiple_json_keyset_then_success() { 160 | val privateHandle = 161 | KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_PRIVATE_KEYSET_WITH_MULTIPLE_KEYS)) 162 | val publicHandle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_PUBLIC_KEYSET_WITH_MULTIPLE_KEYS)) 163 | 164 | val encryptor = publicHandle.getPrimitive(HybridEncrypt::class) 165 | val decryptor = privateHandle.getPrimitive(HybridDecrypt::class) 166 | 167 | val plaintext = "plaintext".encodeToByteArray() 168 | val contextInfo = "contextInfo".encodeToByteArray() 169 | val ciphertext = encryptor.encrypt(plaintext, contextInfo) 170 | val decrypted = decryptor.decrypt(ciphertext, contextInfo) 171 | assertContentEquals(plaintext, decrypted) 172 | 173 | val otherPublicHandle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_PUBLIC_KEYSET)) 174 | val otherEncryptor = otherPublicHandle.getPrimitive(HybridEncrypt::class) 175 | val otherCiphertext = otherEncryptor.encrypt(plaintext, contextInfo) 176 | assertContentEquals( 177 | plaintext, 178 | decryptor.decrypt(otherCiphertext, contextInfo) 179 | ) 180 | } 181 | 182 | @Test 183 | fun test_getPrimitive_given_NonSignatureKeyset_then_throws_error() { 184 | DeterministicAeadConfig.register() 185 | val handle = KeysetHandleGenerator.readClearText(JsonKeysetReader(JSON_DAEAD_KEYSET)) 186 | handle.getPrimitive(DeterministicAead::class) 187 | 188 | assertFailsWith { 189 | handle.getPrimitive(HybridEncrypt::class) 190 | } 191 | assertFailsWith { 192 | handle.getPrimitive(HybridDecrypt::class) 193 | } 194 | } 195 | 196 | private companion object { 197 | val JSON_PRIVATE_KEYSET = """ 198 | { 199 | "primaryKeyId": 647048814, 200 | "key": [ 201 | { 202 | "keyData": { 203 | "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey", 204 | "value": "EosBEkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogI4P/E3HzF6GSRNM4XlRwKBjGw81REj8ovlBno2uNvc8iIQC7Zjep7K4nPGJljgg6GCOrovBJcJRGWMsg8XLDTh0CdxogOIDYp690Aa0r2+xWsdhEZzRS5MVg8y0BdwQwMuYR63s=", 205 | "keyMaterialType": "ASYMMETRIC_PRIVATE" 206 | }, 207 | "status": "ENABLED", 208 | "keyId": 647048814, 209 | "outputPrefixType": "TINK" 210 | } 211 | ] 212 | } 213 | """.trimIndent() 214 | 215 | val JSON_PUBLIC_KEYSET = """ 216 | { 217 | "primaryKeyId": 647048814, 218 | "key": [ 219 | { 220 | "keyData": { 221 | "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", 222 | "value": "EkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogI4P/E3HzF6GSRNM4XlRwKBjGw81REj8ovlBno2uNvc8iIQC7Zjep7K4nPGJljgg6GCOrovBJcJRGWMsg8XLDTh0Cdw==", 223 | "keyMaterialType": "ASYMMETRIC_PUBLIC" 224 | }, 225 | "status": "ENABLED", 226 | "keyId": 647048814, 227 | "outputPrefixType": "TINK" 228 | } 229 | ] 230 | } 231 | """.trimIndent() 232 | 233 | val JSON_PRIVATE_KEYSET_WITH_MULTIPLE_KEYS = """ 234 | { 235 | "primaryKeyId": 1013057693, 236 | "key": [ 237 | { 238 | "keyData": { 239 | "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey", 240 | "value": "EosBEkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogI4P/E3HzF6GSRNM4XlRwKBjGw81REj8ovlBno2uNvc8iIQC7Zjep7K4nPGJljgg6GCOrovBJcJRGWMsg8XLDTh0CdxogOIDYp690Aa0r2+xWsdhEZzRS5MVg8y0BdwQwMuYR63s=", 241 | "keyMaterialType": "ASYMMETRIC_PRIVATE" 242 | }, 243 | "status": "ENABLED", 244 | "keyId": 647048814, 245 | "outputPrefixType": "TINK" 246 | }, 247 | { 248 | "keyData": { 249 | "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey", 250 | "value": "EooBEkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogYDMh2pw+/IEZ5OTcWsnl3k8QunjsB1spu2Ex71L82WEiIECb/Un5ANDbIFdOpf+fxK0DJiTno1XVKuJym1WCqZTzGiBC8yu+DPjOz2Ut+oNkH73hxUcpgWmuJ+NPEqu5GbkLoQ==", 251 | "keyMaterialType": "ASYMMETRIC_PRIVATE" 252 | }, 253 | "status": "ENABLED", 254 | "keyId": 418995680, 255 | "outputPrefixType": "TINK" 256 | }, 257 | { 258 | "keyData": { 259 | "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPrivateKey", 260 | "value": "EowBEkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARohAMJtGycPgL1lcApnYiP3MbURUE5tkkOxdeiOUTxsclmLIiEA4aNiPurRhAnYMdpLS52MbOR+DWjxnvzOgRUPUTnYOeYaIH8YV8/5mBhN2GVpnHIWEYUKEpqcM6t+ZhGC5UJ1ZbYU", 261 | "keyMaterialType": "ASYMMETRIC_PRIVATE" 262 | }, 263 | "status": "ENABLED", 264 | "keyId": 1013057693, 265 | "outputPrefixType": "TINK" 266 | } 267 | ] 268 | } 269 | """.trimIndent() 270 | 271 | // Keyset with the public keys of the keys from JSON_PRIVATE_KEYSET_WITH_MULTIPLE_KEYS. 272 | val JSON_PUBLIC_KEYSET_WITH_MULTIPLE_KEYS = """ 273 | { 274 | "primaryKeyId": 1013057693, 275 | "key": [ 276 | { 277 | "keyData": { 278 | "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", 279 | "value": "EkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogI4P/E3HzF6GSRNM4XlRwKBjGw81REj8ovlBno2uNvc8iIQC7Zjep7K4nPGJljgg6GCOrovBJcJRGWMsg8XLDTh0Cdw==", 280 | "keyMaterialType": "ASYMMETRIC_PUBLIC" 281 | }, 282 | "status": "ENABLED", 283 | "keyId": 647048814, 284 | "outputPrefixType": "TINK" 285 | }, 286 | { 287 | "keyData": { 288 | "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", 289 | "value": "EkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARogYDMh2pw+/IEZ5OTcWsnl3k8QunjsB1spu2Ex71L82WEiIECb/Un5ANDbIFdOpf+fxK0DJiTno1XVKuJym1WCqZTz", 290 | "keyMaterialType": "ASYMMETRIC_PUBLIC" 291 | }, 292 | "status": "ENABLED", 293 | "keyId": 418995680, 294 | "outputPrefixType": "TINK" 295 | }, 296 | { 297 | "keyData": { 298 | "typeUrl": "type.googleapis.com/google.crypto.tink.EciesAeadHkdfPublicKey", 299 | "value": "EkQKBAgCEAMSOhI4CjB0eXBlLmdvb2dsZWFwaXMuY29tL2dvb2dsZS5jcnlwdG8udGluay5BZXNHY21LZXkSAhAQGAEYARohAMJtGycPgL1lcApnYiP3MbURUE5tkkOxdeiOUTxsclmLIiEA4aNiPurRhAnYMdpLS52MbOR+DWjxnvzOgRUPUTnYOeY=", 300 | "keyMaterialType": "ASYMMETRIC_PUBLIC" 301 | }, 302 | "status": "ENABLED", 303 | "keyId": 1013057693, 304 | "outputPrefixType": "TINK" 305 | } 306 | ] 307 | } 308 | """.trimIndent() 309 | 310 | val JSON_DAEAD_KEYSET = """ 311 | { 312 | "primaryKeyId": 961932622, 313 | "key": [ 314 | { 315 | "keyData": { 316 | "typeUrl": "type.googleapis.com/google.crypto.tink.AesSivKey", 317 | "keyMaterialType": "SYMMETRIC", 318 | "value": "EkCJ9r5iwc5uxq5ugFyrHXh5dijTa7qalWUgZ8Gf08RxNd545FjtLMYL7ObcaFtCSkvV2+7u6F2DN+kqUjAfkf2W" 319 | }, 320 | "outputPrefixType": "TINK", 321 | "keyId": 961932622, 322 | "status": "ENABLED" 323 | } 324 | ] 325 | } 326 | """.trimIndent() 327 | } 328 | } 329 | --------------------------------------------------------------------------------