diff --git a/library/crypto-rand/build.gradle.kts b/library/crypto-rand/build.gradle.kts index f9a5303..f33e1c6 100644 --- a/library/crypto-rand/build.gradle.kts +++ b/library/crypto-rand/build.gradle.kts @@ -71,16 +71,18 @@ kmpConfiguration { .resolve("cinterop") val interopTaskInfo = targets.filterIsInstance().map { target -> - if (target.konanTarget.family == Family.ANDROID) { - target.compilations["main"].cinterops.create("crypto_rand_sys") { - definitionFile.set(cInteropDir.resolve("$name.def")) - includeDirs(cInteropDir) - } + val hasSysGetRandom = when (target.konanTarget.family) { + Family.ANDROID, Family.LINUX -> "-DCRYPTO_RAND_HAS_SYS_GETRANDOM=1" + else -> null } - target.compilations["test"].cinterops.create("syscall") { + val taskName = target.compilations["main"].cinterops.create("crypto_rand_sys") { definitionFile.set(cInteropDir.resolve("$name.def")) - }.interopProcessingTaskName to target.konanTarget + includeDirs(cInteropDir) + if (hasSysGetRandom != null) compilerOpts.add(hasSysGetRandom) + }.interopProcessingTaskName + + Triple(taskName, target.konanTarget, hasSysGetRandom) } project.extensions.configure("cklib") { @@ -97,11 +99,21 @@ kmpConfiguration { val kt = KonanTarget.predefinedTargets[target]!! - // Must add dependency on the test cinterop task to ensure - // that Kotlin/Native dependencies get downloaded beforehand - interopTaskInfo.forEach { (interopTaskName, konanTarget) -> + interopTaskInfo.forEach { (interopTaskName, konanTarget, hasSysGetRandom) -> if (kt != konanTarget) return@forEach + + // Must add dependency on the test cinterop task to ensure + // that Kotlin/Native dependencies get downloaded beforehand this.dependsOn(interopTaskName) + + if (hasSysGetRandom != null) { + compilerArgs.add(hasSysGetRandom) + + // Linux x86_64 is the only compilation w/o sys/random.h + if (konanTarget != KonanTarget.LINUX_X64) { + compilerArgs.add("-DCRYPTO_RAND_HAS_SYS_RANDOM_H=1") + } + } } } } diff --git a/library/crypto-rand/src/androidNativeMain/kotlin/org/kotlincrypto/random/internal/AndroidNativePlatform.kt b/library/crypto-rand/src/androidNativeMain/kotlin/org/kotlincrypto/random/internal/AndroidNativePlatform.kt deleted file mode 100644 index 4e8845e..0000000 --- a/library/crypto-rand/src/androidNativeMain/kotlin/org/kotlincrypto/random/internal/AndroidNativePlatform.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2025 KotlinCrypto - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -@file:Suppress("FunctionName", "NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress", "SpellCheckingInspection") - -package org.kotlincrypto.random.internal - -import kotlinx.cinterop.ExperimentalForeignApi - -// https://youtrack.jetbrains.com/issue/KT-75722 -@ExperimentalForeignApi -internal actual inline fun _SYS_getrandom(): Int = __SYS_getrandom() diff --git a/library/crypto-rand/src/androidNativeTest/kotlin/org/kotlincrypto/random/internal/CryptoRandAndroidNativeUnitTest.kt b/library/crypto-rand/src/androidNativeTest/kotlin/org/kotlincrypto/random/internal/CryptoRandAndroidNativeUnitTest.kt deleted file mode 100644 index 72b5571..0000000 --- a/library/crypto-rand/src/androidNativeTest/kotlin/org/kotlincrypto/random/internal/CryptoRandAndroidNativeUnitTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2025 KotlinCrypto - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -package org.kotlincrypto.random.internal - -import kotlinx.cinterop.ExperimentalForeignApi -import org.kotlincrypto.random.internal.testing.SYS_getrandom -import kotlin.test.Test -import kotlin.test.assertEquals - -@OptIn(ExperimentalForeignApi::class) -class CryptoRandAndroidNativeUnitTest { - - @Test - fun givenSYSgetrandom_whenCheckedAgainstHeaderDefinition_thenMatches() { - assertEquals( - SYS_getrandom, - _SYS_getrandom(), - "expected[${SYS_getrandom}] vs actual[${_SYS_getrandom()}]", - ) - } -} diff --git a/library/crypto-rand/src/linuxAndroidMain/kotlin/org/kotlincrypto/random/internal/LinuxAndroidPlatform.kt b/library/crypto-rand/src/linuxAndroidMain/kotlin/org/kotlincrypto/random/internal/LinuxAndroidPlatform.kt index ba18938..2ac2a53 100644 --- a/library/crypto-rand/src/linuxAndroidMain/kotlin/org/kotlincrypto/random/internal/LinuxAndroidPlatform.kt +++ b/library/crypto-rand/src/linuxAndroidMain/kotlin/org/kotlincrypto/random/internal/LinuxAndroidPlatform.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -@file:Suppress("KotlinRedundantDiagnosticSuppress", "NOTHING_TO_INLINE", "SpellCheckingInspection", "UnnecessaryOptInAnnotation") +@file:Suppress("NOTHING_TO_INLINE", "RemoveRedundantCallsOfConversionMethods") package org.kotlincrypto.random.internal @@ -24,20 +24,12 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract -@Suppress("FunctionName") -internal expect inline fun _SYS_getrandom(): Int - -@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) -private inline fun getrandom2(buf: CPointer, buflen: size_t, flags: u_int): Int { - return syscall(_SYS_getrandom().convert(), buf, buflen, flags).convert() -} - // getrandom(2) available for Linux Kernel 3.17+ (Android API 26+) @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) internal val HAS_GET_RANDOM: Boolean by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { val buf = ByteArray(1) val result = buf.usePinned { pinned -> - getrandom2(pinned.addressOf(0), buf.size.convert(), 0x0001u /* GRND_NONBLOCK */) + __getrandom(__buf = pinned.addressOf(0), __len = buf.size.convert(), __is_nonblock = 1).toInt() } if (result >= 0) return@lazy true @@ -54,7 +46,7 @@ internal val HAS_GET_RANDOM: Boolean by lazy(LazyThreadSafetyMode.SYNCHRONIZED) @OptIn(ExperimentalForeignApi::class, UnsafeNumber::class) internal actual fun ByteArray.cryptoRandFill() { if (HAS_GET_RANDOM) { - cryptoRandFill { ptr, len -> getrandom2(ptr, len.toULong().convert(), 0u) } + cryptoRandFill { ptr, len -> __getrandom(__buf = ptr, __len = len.convert(), __is_nonblock = 0).toInt() } } else { cryptoRandFillURandom() } diff --git a/library/crypto-rand/src/linuxMain/kotlin/org/kotlincrypto/random/internal/LinuxPlatform.kt b/library/crypto-rand/src/linuxMain/kotlin/org/kotlincrypto/random/internal/LinuxPlatform.kt deleted file mode 100644 index 5edfd42..0000000 --- a/library/crypto-rand/src/linuxMain/kotlin/org/kotlincrypto/random/internal/LinuxPlatform.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2025 KotlinCrypto - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ -@file:Suppress("FunctionName", "NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress", "SpellCheckingInspection") - -package org.kotlincrypto.random.internal - -import platform.linux.SYS_getrandom - -internal actual inline fun _SYS_getrandom(): Int = SYS_getrandom diff --git a/library/crypto-rand/src/nativeInterop/cinterop/crypto_rand_sys.c b/library/crypto-rand/src/nativeInterop/cinterop/crypto_rand_sys.c index 9bc3037..a2b04c4 100644 --- a/library/crypto-rand/src/nativeInterop/cinterop/crypto_rand_sys.c +++ b/library/crypto-rand/src/nativeInterop/cinterop/crypto_rand_sys.c @@ -16,12 +16,29 @@ #include "crypto_rand_sys.h" -#ifdef __ANDROID__ +#if CRYPTO_RAND_HAS_SYS_GETRANDOM #include +#include -int -__SYS_getrandom() +#ifndef CRYPTO_RAND_HAS_SYS_RANDOM_H +#define CRYPTO_RAND_HAS_SYS_RANDOM_H 0 +#endif // CRYPTO_RAND_HAS_SYS_RANDOM_H + +#if CRYPTO_RAND_HAS_SYS_RANDOM_H +#include +#endif // CRYPTO_RAND_HAS_SYS_RANDOM_H + +#ifndef GRND_NONBLOCK +#define GRND_NONBLOCK 0x01 +#endif // GRND_NONBLOCK + +ssize_t +__getrandom(void *__buf, size_t __len, int __is_nonblock) { - return SYS_getrandom; + unsigned int flags = 0; + if (__is_nonblock) { + flags = GRND_NONBLOCK; + } + return syscall(SYS_getrandom, __buf, __len, flags); } -#endif /* !defined(__ANDROID__) */ +#endif // CRYPTO_RAND_HAS_SYS_GETRANDOM diff --git a/library/crypto-rand/src/nativeInterop/cinterop/crypto_rand_sys.h b/library/crypto-rand/src/nativeInterop/cinterop/crypto_rand_sys.h index 2c9dbbf..4ff0861 100644 --- a/library/crypto-rand/src/nativeInterop/cinterop/crypto_rand_sys.h +++ b/library/crypto-rand/src/nativeInterop/cinterop/crypto_rand_sys.h @@ -14,12 +14,22 @@ * limitations under the License. **/ -/* https://youtrack.jetbrains.com/issue/KT-75722 */ #ifndef CRYPTO_RAND_SYS_H #define CRYPTO_RAND_SYS_H -#ifdef __ANDROID__ -int __SYS_getrandom(); -#endif /* !defined(__ANDROID__) */ +#ifndef CRYPTO_RAND_HAS_SYS_GETRANDOM +#define CRYPTO_RAND_HAS_SYS_GETRANDOM 0 +#endif // CRYPTO_RAND_HAS_SYS_GETRANDOM -#endif /* !defined(CRYPTO_RAND_SYS_H) */ +#if CRYPTO_RAND_HAS_SYS_GETRANDOM +#include + +/** + * Performs syscall using SYS_getrandom and provided arguments. + * + * If __is_nonblock > 0, will use flag GRND_NONBLOCK, otherwise will use 0. + * */ +ssize_t __getrandom(void *__buf, size_t __len, int __is_nonblock); +#endif // CRYPTO_RAND_HAS_SYS_GETRANDOM + +#endif // CRYPTO_RAND_SYS_H diff --git a/library/crypto-rand/src/nativeInterop/cinterop/syscall.def b/library/crypto-rand/src/nativeInterop/cinterop/syscall.def deleted file mode 100644 index a806b30..0000000 --- a/library/crypto-rand/src/nativeInterop/cinterop/syscall.def +++ /dev/null @@ -1,6 +0,0 @@ -# SYS_getrandom for AndroidNative testing -package = org.kotlincrypto.random.internal.testing ---- -#ifdef __ANDROID__ -#include -#endif diff --git a/test-android/src/androidInstrumentedTest/kotlin/org/kotlincrypto/random/test/android/AndroidNativeTest.kt b/test-android/src/androidInstrumentedTest/kotlin/org/kotlincrypto/random/test/android/AndroidNativeTest.kt index d3b79b7..44a8019 100644 --- a/test-android/src/androidInstrumentedTest/kotlin/org/kotlincrypto/random/test/android/AndroidNativeTest.kt +++ b/test-android/src/androidInstrumentedTest/kotlin/org/kotlincrypto/random/test/android/AndroidNativeTest.kt @@ -20,7 +20,7 @@ import androidx.test.core.app.ApplicationProvider import io.matthewnelson.kmp.file.toFile import io.matthewnelson.kmp.process.Process import kotlin.test.Test -import kotlin.test.assertEquals +import kotlin.test.fail class AndroidNativeTest { @@ -35,8 +35,11 @@ class AndroidNativeTest { maxBuffer = Int.MAX_VALUE / 2 } - assertEquals(0, out.processInfo.exitCode, out.stdout) - println(out.stdout) - println(out.stderr) + if (out.processInfo.exitCode == 0) return + + val sb = StringBuilder(out.toString()).appendLine() + sb.appendLine(out.stdout).appendLine() + sb.appendLine(out.stderr).appendLine() + fail(sb.toString()) } }