Andreas Jost
12/05/2019, 1:30 PMfun keychainQuery(key: String) =
CFDictionaryCreateMutable(null, 5, null, null).also {
CFDictionaryAddValue(it, kSecClassGenericPassword, kSecClass)
CFDictionaryAddValue(it, key.cstr, kSecAttrService)
CFDictionaryAddValue(it, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecAttrAccessible)
}
fun load(key: String) : String {
val query = keychainQuery(key)
CFDictionaryAddValue(query, kCFBooleanTrue, kSecReturnData)
CFDictionaryAddValue(query, kCFBooleanTrue, kSecReturnAttributes)
memScoped {
val result: CFTypeRefVar = alloc()
val status = SecItemCopyMatching(query, result.ptr)
val resultsDict = result as CFDictionaryRef // <-- This cast can never succeed
val resultsData: COpaquePointer? = CFDictionaryGetValue(result, kSecValueData)
}
}
Andreas Jost
12/06/2019, 8:49 AMfun keychainQuery(key: String) =
CFDictionaryCreateMutable(null, 5, null, null).also {
CFDictionaryAddValue(it, kSecClassGenericPassword, kSecClass)
CFDictionaryAddValue(it, key.cstr, kSecAttrService)
CFDictionaryAddValue(it, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecAttrAccessible)
}
fun load(key: String): String = memScoped {
val query = keychainQuery(key)
CFDictionaryAddValue(query, kCFBooleanTrue, kSecReturnData)
CFDictionaryAddValue(query, kCFBooleanTrue, kSecReturnAttributes)
val result: CFTypeRefVar = alloc()
val status = SecItemCopyMatching(query, result.ptr)
Logging.debug("Keychain Load", status.toString())
val resultsDict = result as CFDictionaryRefVar
val resultsData = CFDictionaryGetValue(resultsDict.value, kSecValueData) as CFDataRef
val value = CFStringCreateFromExternalRepresentation(null, resultsData, kCFStringEncodingUTF8)
return@memScoped CFBridgingRelease(value) as String
}
fun save(value: String, key: String) = memScoped {
val query = keychainQuery(key)
val objectData = CFDataCreate(null, value.cstr.ptr as CValuesRef<UInt8Var>, value.cstr.size.toLong())
if (SecItemCopyMatching(query, null) == noErr.toInt()) {
val attributes = CFDictionaryCreateMutable(null, 1, null, null)
CFDictionaryAddValue(attributes, kSecValueData, objectData)
val status = SecItemUpdate(query, attributes)
Logging.debug("Keychain Update", status.toString())
} else {
CFDictionaryAddValue(query, objectData, kSecValueData)
val status = SecItemAdd(query, null)
Logging.debug("Keychain Add", status.toString())
}
}
It compiles and there are no "This cast can never succeed"-warnings anymore, only unchecked casts.
The load function prints Keychain Load with Status -50 and afterwards:
kotlin.ClassCastException: kotlinx.cinterop.NativePointed cannot be cast to kotlinx.cinterop.CPointerVarOf
The save process stops with EXC_BAD_ACCESSEllen Shapiro
12/06/2019, 10:37 AMEllen Shapiro
12/06/2019, 10:38 AMEllen Shapiro
12/06/2019, 10:38 AMerrSecParam
Ellen Shapiro
12/06/2019, 10:39 AMEllen Shapiro
12/06/2019, 10:39 AMAndreas Jost
12/06/2019, 10:58 AMCFDictionaryAddValue(it, CFStringCreateWithCString(null, key, kCFStringEncodingUTF8), kSecAttrService)
Didn't change the result though :(Andreas Jost
12/06/2019, 12:38 PMsvyatoslav.scherbina
12/09/2019, 10:50 AMresult as CFDictionaryRefVarUse
result.reinterpret<CFDictionaryRefVar>()
Thomas Skovsgaard
09/08/2020, 7:31 AM