Anyone know how one could verify an RSA signature ...
# multiplatform
m
Anyone know how one could verify an RSA signature from Objective-C?
jvm
Copy code
internal actual fun verifyOrThrow(data: ByteArray, signature: ByteArray, pubKey: ByteArray) {
    try {
        val key = KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(pubKey))
        val sig = Signature.getInstance("SHA256withRSA")
        sig.initVerify(key)
        sig.update(data)

        if (!sig.verify(signature)) {
            throw IllegalArgumentException("Failed to verify message")
        }
    } catch (t: Throwable) {
        if (t is IllegalArgumentException) {
            throw t
        } else {
            throw IllegalArgumentException("Failed to verify message", t)
        }
    }
}
darwin (iOS, tvOS, watchOS)
Copy code
internal actual fun verifyOrThrow(data: ByteArray, signature: ByteArray, pubKey: ByteArray) {
   // TODO
}
NVM... figured it out... Was a casting issue the whole time. Simply needed to use
CFData
instead of
NSData
Copy code
import kotlinx.cinterop.*
import platform.CoreFoundation.*
import platform.Security.*

@OptIn(UnsafeNumber::class)
@Throws(IllegalArgumentException::class)
internal actual fun verifyOrThrow(data: ByteArray, pubKey: ByteArray, signature: ByteArray) {
    val allocator = CFAllocatorGetDefault()
        ?: throw IllegalArgumentException("Failed to retrieve CFAllocator")
    val allocated = mutableSetOf<CPointer<*>>()

    val result = try {
        val attributes = CFDictionaryCreateMutable(allocator, 2, null, null)
            ?.also { allocated.add(it) }
            ?: throw IllegalArgumentException("Failed to create CFDictionary")

        CFDictionaryAddValue(attributes, kSecAttrKeyType, kSecAttrKeyTypeRSA)
        CFDictionaryAddValue(attributes, kSecAttrKeyClass, kSecAttrKeyClassPublic)

        val pubKeyData = pubKey.toCFData(allocator).also { allocated.add(it) }

        val keyRef: SecKeyRef = SecKeyCreateWithData(pubKeyData, attributes, null)
            ?: throw IllegalArgumentException("Failed to create SecKeyRef for public key")

        val messageData = data.toCFData(allocator).also { allocated.add(it) }
        val signatureData = signature.toCFData(allocator).also { allocated.add(it) }

        SecKeyVerifySignature(
            keyRef,
            kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256,
            messageData,
            signatureData,
            null
        )
    } catch (t: Throwable) {
        if (t is IllegalArgumentException) {
            throw t
        } else {
            throw IllegalArgumentException("Failed to verify signature", t)
        }
    } finally {
        for (ptr in allocated) {
            CFAllocatorDeallocate(allocator, ptr)
        }
    }

    if (!result) {
        throw IllegalArgumentException("Failed to verify signature")
    }
}

@OptIn(UnsafeNumber::class)
@Suppress("NOTHING_TO_INLINE")
private inline fun ByteArray.toCFData(allocator: CFAllocatorRef): CFDataRef = usePinned {
    CFDataCreate(allocator, it.addressOf(0).reinterpret(), size.toLong().convert())
} ?: throw IllegalArgumentException("Failed to convert bytes to CFData")