whyoleg/cryptography-kotlin

ld.lld: error: undefined symbol: OpenSSL_version

Closed this issue · 2 comments

When trying to use CryptograhpyProvider.OpenSSL I get this error

e: /home/paul/.konan/dependencies/llvm-19-x86_64-linux-essentials-103/bin/ld.lld invocation reported errors
The /home/paul/.konan/dependencies/llvm-19-x86_64-linux-essentials-103/bin/ld.lld command returned non-zero exit code: 1.
output:
ld.lld: error: undefined symbol: OpenSSL_version
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OpenSSL_version_wrapper293)
ld.lld: error: undefined symbol: BN_num_bits
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_BN_num_bits_wrapper562)
ld.lld: error: undefined symbol: BN_bin2bn
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_BN_bin2bn_wrapper570)
ld.lld: error: undefined symbol: BN_bn2binpad
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_BN_bn2binpad_wrapper572)
ld.lld: error: undefined symbol: BN_free
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_BN_free_wrapper607)
ld.lld: error: undefined symbol: OSSL_PARAM_construct_int
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OSSL_PARAM_construct_int_wrapper713)
ld.lld: error: undefined symbol: OSSL_PARAM_construct_uint
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OSSL_PARAM_construct_uint_wrapper714)
ld.lld: error: undefined symbol: OSSL_PARAM_construct_uint32
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OSSL_PARAM_construct_uint32_wrapper718)
ld.lld: error: undefined symbol: OSSL_PARAM_construct_size_t
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OSSL_PARAM_construct_size_t_wrapper721)
ld.lld: error: undefined symbol: OSSL_PARAM_construct_BN
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OSSL_PARAM_construct_BN_wrapper723)
ld.lld: error: undefined symbol: OSSL_PARAM_construct_utf8_string
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OSSL_PARAM_construct_utf8_string_wrapper725)
ld.lld: error: undefined symbol: OSSL_PARAM_construct_octet_string
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OSSL_PARAM_construct_octet_string_wrapper727)
ld.lld: error: undefined symbol: OSSL_PARAM_construct_end
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OSSL_PARAM_construct_end_wrapper729)
ld.lld: error: undefined symbol: OBJ_nid2obj
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OBJ_nid2obj_wrapper1109)
ld.lld: error: undefined symbol: OBJ_obj2txt
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OBJ_obj2txt_wrapper1114)
ld.lld: error: undefined symbol: OBJ_txt2nid
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OBJ_txt2nid_wrapper1115)
ld.lld: error: undefined symbol: OBJ_sn2nid
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_OBJ_sn2nid_wrapper1117)
ld.lld: error: undefined symbol: EVP_MD_get_size
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_EVP_MD_get_size_wrapper1141)
ld.lld: error: undefined symbol: EVP_MD_get_block_size
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_EVP_MD_get_block_size_wrapper1142)
ld.lld: error: undefined symbol: EVP_CIPHER_fetch
>>> referenced by out
>>>               /tmp/konan_temp4793741098894229432/test.kexe.o:(dev_whyoleg_cryptography_providers_openssl3_internal_cinterop_EVP_CIPHER_fetch_wrapper1161)
ld.lld: error: too many errors emitted, stopping now (use --error-limit=0 to see all errors)

with following code:

internal actual object Compressor {
	private var crc: Int = 0
	private var finished: Boolean = false
	private var finish: Int = Z_FINISH

	@OptIn(ExperimentalForeignApi::class, UnsafeNumber::class)
	actual fun compress(input: ByteArray): ByteArray {
		memScoped {
			// Allocate output buffer with maximum possible size
			val maxOutputSize = compressBound(input.size.toUInt() as uLong).toInt()
			val output = ByteArray(maxOutputSize)

			// Prepare input and output pointers
			val inputPtr = input.refTo(0).getPointer(this)
			val outputPtr = output.refTo(0).getPointer(this)
			val outputSizePtr = nativeHeap.alloc<size_tVar>()

			// Initialize the deflate stream
			val stream = alloc<z_stream>()
			// Clear the structure
			memset(stream.ptr, 0, sizeOf<z_stream>().convert())

			deflateInit(stream.ptr, Z_DEFAULT_COMPRESSION)
			stream.next_in = inputPtr.reinterpret()
			stream.avail_in = input.size.toUInt()
			stream.next_out = outputPtr.reinterpret()
			stream.avail_out = output.size.toUInt()

			// Compress the data
			crc = deflate(stream.ptr, finish)
			check(crc != Z_STREAM_ERROR) { "Failed to compress data" }
			// Update output buffer size
			outputSizePtr.value = (output.size - stream.avail_out.toInt()).toULong()
			// Finalize the deflate stream
			check(deflateEnd(stream.ptr) == Z_OK) { "Failed to finalize compression" }
			finished = true
			// Create a new byte array with the compressed data
			return output.copyOf(outputSizePtr.value.toInt())
		}
	}

	@OptIn(ExperimentalForeignApi::class)
	@Suppress("unchecked_cast")
	actual fun decompress(input: ByteArray): ByteArray {
		memScoped {

			/* Create a zlib stream structure */
			val stream = alloc<z_stream>()

			/* Initialize the zlib stream */
			stream.next_in = input.refTo(0).getPointer(this) as CPointer<uByteVar>
			stream.avail_in = input.size.toUInt()

			/* Specify the decompression mode */
			inflateInit(stream.ptr)

			val outputBufferLength = 4096
			val outputBuffer = ByteArray(outputBufferLength)
			var decompressedData = ByteArray(0)

			try {
				while (true) {

					/* Set the output buffer and its length */
					stream.next_out = outputBuffer.refTo(0).getPointer(this) as CPointer<uByteVar>
					stream.avail_out = outputBufferLength.toUInt()

					/* Decompress the data */
					when (val result = inflate(stream.ptr, Z_NO_FLUSH)) {
						Z_STREAM_END -> {
							/* The end of the compressed data was reached */
							val bytesWritten = outputBufferLength - stream.avail_out.toInt()
							decompressedData += outputBuffer.take(bytesWritten)
							break
						}

						Z_OK -> {
							/* More decompressed data is available */
							val bytesWritten = outputBufferLength - stream.avail_out.toInt()
							decompressedData += outputBuffer.take(bytesWritten)
						}

						else -> {
							/* An error occurred during decompression */
							inflateEnd(stream.ptr)
							throw RuntimeException("Decompression error: $result")
						}
					}
				}

			} finally {
				/* Clean up the zlib stream */
				inflateEnd(stream.ptr)
			}

			return decompressedData
		}
	}
}

You can try it yourself by cloning this commit kxmpxtxnt/solembum@28dcfff and running the ByteArrayExtensionTests and running it on linuxX64

Hey!
That's probably because you are not adding shared or prebuilt OpenSSL dependency as mentioned in documentation.
In any case, starting from 0.5.0, you can add single optimal provider dependency in commonMain (as mentioned in the readme):

kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("dev.whyoleg.cryptography:cryptography-core:0.5.0")
            implementation("dev.whyoleg.cryptography:cryptography-provider-optimal:0.5.0")
        }
    }
}

Damn, somehow didnt see that, thank you!