From be4468785d8102bda936ee119916ceeb7f574a7f Mon Sep 17 00:00:00 2001 From: Ugljesa Jovanovic Date: Fri, 21 Aug 2020 18:55:17 +0200 Subject: [PATCH] Slow progress. --- .../LibsodiumSecretStreamDefinitions.kt | 27 ++++++++- .../generator/CommonLibsodiumGenerator.kt | 8 +-- .../generator/JvmLibsodiumGenerator.kt | 50 +++++++++++------ .../generator/NativeLibsodiumGenerator.kt | 56 +++++++++++++------ .../commonMain/kotlin/debug/test/DebugTest.kt | 9 ++- .../crypto/secretstream/SecretStreamTest.kt | 2 +- .../src/jsMain/kotlin/debug/test/DebugTest.kt | 10 ++-- .../jvmMain/kotlin/debug/test/DebugTest.kt | 7 ++- .../nativeMain/kotlin/debug/test/DebugTest.kt | 7 ++- 9 files changed, 122 insertions(+), 54 deletions(-) diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumSecretStreamDefinitions.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumSecretStreamDefinitions.kt index 76d7037..7e452bf 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumSecretStreamDefinitions.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/definitions/LibsodiumSecretStreamDefinitions.kt @@ -28,6 +28,27 @@ fun ClassDefinition.defineSecretStreamFunctions() { ) ) + + +dataClassDef( + "DecryptedDataAndTag", + """ + This data class wraps the decrypted data and tag returned when decrypting + """.trimIndent(), + listOf( + ParameterDefinition( + parameterName = "decrypted", + parameterType = TypeDefinition.ARRAY_OF_UBYTES + ), + ParameterDefinition( + parameterName = "tag", + parameterType = TypeDefinition.UBYTE + ) + + ) + + ) + + val jsSecretStreamInit = CodeBlockDefinition( """ val stateAndHeader = getSodium().crypto_secretstream_xchacha20poly1305_init_push(key.toUInt8Array()) @@ -148,7 +169,7 @@ fun ClassDefinition.defineSecretStreamFunctions() { codeDocumentation = """ Decrypt next block of data using the previously initialized state. Returns decrypted block. """.trimIndent(), - returnType = TypeDefinition.ARRAY_OF_UBYTES + returnType = CustomTypeDefinition(withPackageName("DecryptedDataAndTag")) ) { +ParameterDefinition( "state", @@ -167,7 +188,9 @@ fun ClassDefinition.defineSecretStreamFunctions() { ) +ParameterDefinition( "tag_p", - TypeDefinition.NULL + TypeDefinition.UBYTE, + dropParameterFromDefinition = true, + isActuallyAnOutputParam = true ) +ParameterDefinition( "c", diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt index 9027f38..53b5eed 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/CommonLibsodiumGenerator.kt @@ -53,7 +53,7 @@ object CommonLibsodiumGenerator { fun createCommonMethodSpec(methodDefinition: FunctionDefinition): FunSpec.Builder { val methodBuilder = FunSpec.builder(methodDefinition.name) - var actualReturnType : TypeName = Any::class.asTypeName() + val actualReturnTypes = mutableListOf() var actualReturnTypeFound : Boolean = false for (paramDefinition in methodDefinition.parameterList) { if ((paramDefinition.isStateType.not() || methodDefinition.isStateCreationFunction.not()) && paramDefinition.dropParameterFromDefinition.not()) { @@ -65,11 +65,11 @@ object CommonLibsodiumGenerator { } if (paramDefinition.isActuallyAnOutputParam) { actualReturnTypeFound = true - actualReturnType = paramDefinition.parameterType.typeName + actualReturnTypes += paramDefinition.parameterType.typeName } } - if (actualReturnTypeFound) { - methodBuilder.returns(actualReturnType) + if (actualReturnTypeFound && actualReturnTypes.size == 1) { + methodBuilder.returns(actualReturnTypes[0]) } else { methodBuilder.returns(methodDefinition.returnType.typeName) } diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt index 0096f83..10ddb0c 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/JvmLibsodiumGenerator.kt @@ -8,6 +8,7 @@ import com.squareup.kotlinpoet.FunSpec import com.squareup.kotlinpoet.ParameterSpec import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.TypeAliasSpec +import com.squareup.kotlinpoet.TypeName /** * Created by Ugljesa Jovanovic @@ -56,7 +57,7 @@ object JvmLibsodiumGenerator { methodBuilder.modifiers += MultiplatformModifier.ACTUAL.modifierList var returnModifierFound = false var returnModifierValue = "" - lateinit var actualReturnParameterDefinition: ParameterDefinition + val actualReturnTypes = mutableListOf() var actualReturnTypeFound: Boolean = false for (paramDefinition in methodDefinition.parameterList) { if (paramDefinition.isStateType && methodDefinition.isStateCreationFunction) { @@ -89,14 +90,14 @@ object JvmLibsodiumGenerator { } } if (paramDefinition.isActuallyAnOutputParam) { - actualReturnParameterDefinition = paramDefinition + actualReturnTypes += paramDefinition actualReturnTypeFound = true } } if (actualReturnTypeFound) { if (returnModifierFound) { createOutputParam( - actualReturnParameterDefinition, + actualReturnTypes, returnModifierValue, methodBuilder ) @@ -105,7 +106,7 @@ object JvmLibsodiumGenerator { throw RuntimeException("Function definition lacks a way to define output array length, function ${methodDefinition.name}") } createOutputParam( - actualReturnParameterDefinition, + actualReturnTypes, methodDefinition.outputLengthWhenArray.toString(), methodBuilder ) @@ -125,10 +126,18 @@ object JvmLibsodiumGenerator { methodBuilder.addStatement(constructJvmCall.toString()) methodBuilder.addStatement("return state") } else if (actualReturnTypeFound) { - constructJvmCall.append("sodium.${methodDefinition.nativeName}") - constructJvmCall.append(paramsToString(methodDefinition)) - methodBuilder.addStatement(constructJvmCall.toString()) - methodBuilder.addStatement("return ${actualReturnParameterDefinition.parameterName}") + if (actualReturnTypes.size == 1) { + constructJvmCall.append("sodium.${methodDefinition.nativeName}") + constructJvmCall.append(paramsToString(methodDefinition)) + methodBuilder.addStatement(constructJvmCall.toString()) + methodBuilder.addStatement("return ${actualReturnTypes[0].parameterName}") + } else { + constructJvmCall.append("sodium.${methodDefinition.nativeName}") + constructJvmCall.append(paramsToString(methodDefinition)) + methodBuilder.addStatement(constructJvmCall.toString()) + methodBuilder.addStatement( + "return ${methodDefinition.returnType.typeName}(${createTupleOutputParams(actualReturnTypes)})") + } } else { when (methodDefinition.returnType) { TypeDefinition.ARRAY_OF_UBYTES -> { @@ -161,24 +170,31 @@ object JvmLibsodiumGenerator { return methodBuilder } - fun createOutputParam(outputParam: ParameterDefinition, length: String?, methodBuilder: FunSpec.Builder) { + fun createOutputParam(outputParams: List, length: String?, methodBuilder: FunSpec.Builder) { /* val hashed = ByteArray(Sha256Properties.MAX_HASH_BYTES) sodium.crypto_hash_sha256_final(state, hashed) return hashed.asUByteArray() */ - when (outputParam.parameterType) { - TypeDefinition.ARRAY_OF_UBYTES, TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE, TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE -> { - methodBuilder.addStatement("val ${outputParam.parameterName} = UByteArray($length)") + for (outputParam in outputParams) { + when (outputParam.parameterType) { + TypeDefinition.ARRAY_OF_UBYTES, TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE, TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE -> { + methodBuilder.addStatement("val ${outputParam.parameterName} = UByteArray($length)") + } + TypeDefinition.UBYTE -> { + methodBuilder.addStatement("var ${outputParam.parameterName} : UByte = 0U") + } + else -> { + throw RuntimeException("Unhandled native output param type: ${outputParam.parameterType.typeName}") + } } - else -> { - throw RuntimeException("Unhandled native output param type: ${outputParam.parameterType.typeName}") - } - - } } + fun createTupleOutputParams(outputParams: List) : String { + return outputParams.map { it.parameterName }.joinToString (separator = ", ") + } + fun createStateParam(stateParameterDefinition: ParameterDefinition, methodBuilder: FunSpec.Builder) { /* val state = Hash.State256() diff --git a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/NativeLibsodiumGenerator.kt b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/NativeLibsodiumGenerator.kt index 14b9d0e..629db0e 100644 --- a/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/NativeLibsodiumGenerator.kt +++ b/kotlin-multiplatform-libsodium-generator/src/main/kotlin/com/ionspin/kotlin/crypto/generator/libsodium/generator/NativeLibsodiumGenerator.kt @@ -71,7 +71,7 @@ object NativeLibsodiumGenerator { methodBuilder.modifiers += MultiplatformModifier.ACTUAL.modifierList var returnModifierFound = false var returnModifierValue = "" - lateinit var actualReturnParameterDefinition: ParameterDefinition + val actualReturnTypes = mutableListOf() var actualReturnTypeFound: Boolean = false for (paramDefinition in methodDefinition.parameterList) { if (paramDefinition.isStateType && methodDefinition.isStateCreationFunction) { @@ -104,18 +104,18 @@ object NativeLibsodiumGenerator { } if (paramDefinition.isActuallyAnOutputParam) { - actualReturnParameterDefinition = paramDefinition + actualReturnTypes += paramDefinition actualReturnTypeFound = true } } if (actualReturnTypeFound) { if (returnModifierFound) { - createOutputParam(actualReturnParameterDefinition, returnModifierValue, methodBuilder) + createOutputParam(actualReturnTypes, returnModifierValue, methodBuilder) } else { if (methodDefinition.outputLengthWhenArray == -1) { throw RuntimeException("Function definition lacks a way to define output array length, function ${methodDefinition.name}") } - createOutputParam(actualReturnParameterDefinition, methodDefinition.outputLengthWhenArray.toString(), methodBuilder) + createOutputParam(actualReturnTypes, methodDefinition.outputLengthWhenArray.toString(), methodBuilder) } } methodBuilder.addStatement("println(\"Debug ${methodDefinition.name}\")") @@ -134,11 +134,24 @@ object NativeLibsodiumGenerator { unpinParams(methodDefinition, methodBuilder) methodBuilder.addStatement("return state") } else if (actualReturnTypeFound) { - constructNativeCall.append("libsodium.${methodDefinition.nativeName}") - constructNativeCall.append(paramsToString(methodDefinition)) - methodBuilder.addStatement(constructNativeCall.toString()) - unpinParams(methodDefinition, methodBuilder) - methodBuilder.addStatement("return ${actualReturnParameterDefinition.parameterName}") + if (actualReturnTypes.size == 1) { + constructNativeCall.append("libsodium.${methodDefinition.nativeName}") + constructNativeCall.append(paramsToString(methodDefinition)) + methodBuilder.addStatement(constructNativeCall.toString()) + unpinParams(methodDefinition, methodBuilder) + methodBuilder.addStatement("return ${actualReturnTypes[0].parameterName}") + } else { + constructNativeCall.append("libsodium.${methodDefinition.nativeName}") + constructNativeCall.append(paramsToString(methodDefinition)) + methodBuilder.addStatement(constructNativeCall.toString()) + unpinParams(methodDefinition, methodBuilder) + methodBuilder.addStatement( + "return ${methodDefinition.returnType.typeName}(${ + JvmLibsodiumGenerator.createTupleOutputParams( + actualReturnTypes + ) + })") + } } else { when (methodDefinition.returnType) { TypeDefinition.ARRAY_OF_UBYTES -> { @@ -188,7 +201,7 @@ object NativeLibsodiumGenerator { methodBuilder.addStatement("val state = allocated.reinterpret<${stateParameterDefinition.parameterType.typeName}>().pointed") } - fun createOutputParam(outputParam: ParameterDefinition, length: String?, methodBuilder: FunSpec.Builder) { + fun createOutputParam(outputParams: List, length: String?, methodBuilder: FunSpec.Builder) { /* val hashResult = UByteArray(Sha256Properties.MAX_HASH_BYTES) val hashResultPinned = hashResult.pin() @@ -196,18 +209,25 @@ object NativeLibsodiumGenerator { sodium_free(state.ptr) return hashResult */ - when (outputParam.parameterType) { - TypeDefinition.ARRAY_OF_UBYTES, TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE, TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE -> { - methodBuilder.addStatement("val ${outputParam.parameterName} = UByteArray($length)") + for (outputParam in outputParams) { + when (outputParam.parameterType) { + TypeDefinition.ARRAY_OF_UBYTES, TypeDefinition.ARRAY_OF_UBYTES_NO_SIZE, TypeDefinition.ARRAY_OF_UBYTES_LONG_SIZE -> { + methodBuilder.addStatement("val ${outputParam.parameterName} = UByteArray($length)") + } + TypeDefinition.UBYTE -> { + methodBuilder.addStatement("var ${outputParam.parameterName} : UByte = 0U") + } + else -> { + throw RuntimeException("Unhandled native output param type: ${outputParam.parameterType.typeName}") + } } - else -> { - throw RuntimeException("Unhandled native output param type: ${outputParam.parameterType.typeName}") - } - - } } + fun createTupleOutputParams(outputParams: List) : String { + return outputParams.map { it.parameterName }.joinToString (separator = ", ") + } + fun pinParams(methodDefinition: FunctionDefinition, methodBuilder: FunSpec.Builder) { methodDefinition.parameterList.forEachIndexed { index, paramDefinition -> if (paramDefinition.parameterType is TypeDefinition) { diff --git a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt index d1acc23..763ea38 100644 --- a/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/commonMain/kotlin/debug/test/DebugTest.kt @@ -20,6 +20,13 @@ data class SecretStreamStateAndHeader( val header: UByteArray ) +data class DecryptedDataAndTag( + @JsName("decrypted") + val decrypted: UByteArray, + @JsName("tag") + val tag: UByte +) + expect class Crypto internal constructor() { /** * Initialize the SHA256 hash @@ -68,5 +75,5 @@ expect class Crypto internal constructor() { state: SecretStreamState, c: UByteArray, ad: UByteArray - ): UByteArray + ): DecryptedDataAndTag } diff --git a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamTest.kt b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamTest.kt index c9e3cf4..e477f41 100644 --- a/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/commonTest/kotlin/com/ionspin/kotlin/crypto/secretstream/SecretStreamTest.kt @@ -65,7 +65,7 @@ class SecretStreamTest { encrypted.hexColumsPrint() val decryptState = crypto.crypto_secretstream_xchacha20poly1305_init_pull(stateAndHeader.header, key) val decrypted = - crypto.crypto_secretstream_xchacha20poly1305_pull(decryptState, encrypted, ubyteArrayOf()) //TODO JS pull returns a tag and a message!!! + crypto.crypto_secretstream_xchacha20poly1305_pull(decryptState, encrypted, ubyteArrayOf()) decrypted.hexColumsPrint() decrypted.contentEquals(message) diff --git a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/debug/test/DebugTest.kt b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/debug/test/DebugTest.kt index cb820c3..2c462b6 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/debug/test/DebugTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jsMain/kotlin/debug/test/DebugTest.kt @@ -70,17 +70,17 @@ actual class Crypto internal actual constructor() { getSodium().crypto_secretstream_xchacha20poly1305_init_push(key.toUInt8Array()) val state = stateAndHeader.state val header = (stateAndHeader.header as Uint8Array).toUByteArray() - return SecretStreamStateAndHeader(state, header) + return SecretStreamStateAndHeader(state, header) } /** * Initialize state from header and key. The state can then be used for decryption. */ actual fun crypto_secretstream_xchacha20poly1305_init_pull(header: UByteArray, key: UByteArray): - SecretStreamState { + dynamic { println("Debug crypto_secretstream_xchacha20poly1305_init_pull") return getSodium().crypto_secretstream_xchacha20poly1305_init_pull(header.toUInt8Array(), - key.toUInt8Array()) as SecretStreamState + key.toUInt8Array()) } /** @@ -104,9 +104,9 @@ actual class Crypto internal actual constructor() { state: SecretStreamState, c: UByteArray, ad: UByteArray - ): UByteArray { + ): UByte { println("Debug crypto_secretstream_xchacha20poly1305_pull") return getSodium().crypto_secretstream_xchacha20poly1305_pull(state, c.toUInt8Array(), - ad.toUInt8Array()).toUByteArray() + ad.toUInt8Array()) } } diff --git a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt index b2b3082..17529ec 100644 --- a/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/jvmMain/kotlin/debug/test/DebugTest.kt @@ -117,11 +117,12 @@ actual class Crypto internal actual constructor() { state: SecretStreamState, c: UByteArray, ad: UByteArray - ): UByteArray { + ): DecryptedDataAndTag { val m = UByteArray(c.size - 17) + var tag_p : UByte = 0U println("Debug crypto_secretstream_xchacha20poly1305_pull") - sodium.crypto_secretstream_xchacha20poly1305_pull(state, m.asByteArray(), null, null, + sodium.crypto_secretstream_xchacha20poly1305_pull(state, m.asByteArray(), null, tag_p.toByte(), c.asByteArray(), c.size.toLong(), ad.asByteArray(), ad.size.toLong()) - return m + return debug.test.DecryptedDataAndTag(m, tag_p) } } diff --git a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/DebugTest.kt b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/DebugTest.kt index 7bb9657..52cc5fa 100644 --- a/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/DebugTest.kt +++ b/multiplatform-crypto-libsodium-bindings/src/nativeMain/kotlin/debug/test/DebugTest.kt @@ -162,17 +162,18 @@ actual class Crypto internal actual constructor() { state: SecretStreamState, c: UByteArray, ad: UByteArray - ): UByteArray { + ): DecryptedDataAndTag { val m = UByteArray(c.size - 17) + var tag_p : UByte = 0U println("Debug crypto_secretstream_xchacha20poly1305_pull") val pinnedM = m.pin() val pinnedC = c.pin() val pinnedAd = ad.pin() libsodium.crypto_secretstream_xchacha20poly1305_pull(state.ptr, pinnedM.addressOf(0), null, - null, pinnedC.addressOf(0), c.size.convert(), pinnedAd.addressOf(0), ad.size.convert()) + tag_p, pinnedC.addressOf(0), c.size.convert(), pinnedAd.addressOf(0), ad.size.convert()) pinnedM.unpin() pinnedC.unpin() pinnedAd.unpin() - return m + return debug.test.DecryptedDataAndTag(m, tag_p) } }