This directory contains several projects demonstrating how to interact with the Secure Enclave/Android Keystore in Xamarin. A description follows:
xamarin-default: a Xamarin project that uses the built-in Xamarin Secure Storage library (does NOT directly use SE/Keystore) to sign messages.android/: an Android Studio project containing a Kotlin library (KeyStoreTest/KeyManager/) and a demo application (KeyStoreTest/) that uses the Android Keystore to sign messages.ios/: an Xcode project containing a Swift library (KeyManager/) that uses the iOS Secure Enclave to sign messages.KeyManagerAndroid/: a Xamarin project containing bindings for the KotlinKeyManagerlibrary.KeyManagerIos/: a Xamarin project containing bindings for the SwiftKeyManager library.xamarin-native: a Xamarin project that links toKeyManager(Android|Ios)to sign messages in Xamarin using the Secure Enclave/Android Keystore.
(Based on Xamarin documentation.)
- Use Android Studio to open the
android/KeystoreTestproject and buildKeyManager(e.g. openKeyManager.ktand click Build -> Make Module '...') to produce an Android library atandroid/KeystoreTest/KeyManager/build/outputs/aar. - Copy the Android library
KeyManager-debug.aartoKeyManagerAndroid/KeyManagerAndroid/Jars. Open theKeyManagerAndroidsolution (e.g. in Jetbrains Rider or Visual Studio) and build it, producing a Xamarin Android DLL atKeyManagerAndroid/KeyManagerAndroid/bin/Debug.- Make sure you open the solution file (ending in
.sln), not the directory. - Before building, right-click the copied
KeyManager-debug.aarfile and click Properties. Make sure "Build action:" is set to "LibraryProjectZip". (See here for more information.)
- Make sure you open the solution file (ending in
- Open the
xamarin-nativesolution (e.g. in Jetbrains Rider or Visual Studio) and add the Xamarin Android DLL as a dependency toxamarin-native: right-click "Dependencies" under the Android project (here calledSigning.Android), click "Add Reference", and click "Add From...". This allows it to build and run on the Android emulator, using the Android Keystore.- Again make sure you open the solution file (ending in
.sln), not the directory.
- Again make sure you open the solution file (ending in
(Based on Xamarin documentation.)
- Build
ios/KeyManager/KeyManager.xcodeproj:- Open the project in Xcode and check that it compiles (Cmd+B).
- This project has a number of important build settings (see the documentation link above). "Always Embed Swift Standard Libraries" and "Enable Bitcode" are set to
No, and "Excluded Architectures" -> "Release" -> "Any iOS Simulator SDK" includesarm64.
- This project has a number of important build settings (see the documentation link above). "Always Embed Swift Standard Libraries" and "Enable Bitcode" are set to
- Navigate to the directory in a terminal and run
xcodebuild -showsdksto show available SDKs. - Choose an iOS and Simulator SDK; here we will use 14.4. Build by running:
xcodebuild -sdk iphonesimulator14.4 -project KeyManager.xcodeproj -configuration Release xcodebuild -sdk iphoneos14.4 -project KeyManager.xcodeproj -configuration Release- Compose the builds into a fat library:
Note: in theory this shouldn't be necessary since the iOS simulator and a real iOS device both use ARM, but due to a quirk/bug in how Visual Studio for Mac handles Xamarin builds for the iOS simulator on Apple silicon, we have to build an x86 library for the simulator, and therefore build a fat library.cp -R Release-iphoneos Release-fat cp -R Release-iphonesimulator/KeyManager.framework/Modules/KeyManager.swiftmodule Release-fat/KeyManager.framework/Modules/KeyManager.swiftmodule lipo -create -output Release-fat/KeyManager.framework/KeyManager Release-iphoneos/KeyManager.framework/KeyManager Release-iphonesimulator/KeyManager.framework/KeyManager - Open the project in Xcode and check that it compiles (Cmd+B).
- The linked documentation explains how to use Sharpie to generate C# bindings; this has already been done, so open
KeyManagerIos/KeyManagerIos.slnin Visual Studio and build it.- Note: I had trouble getting this to work with Debug configuration. You may need to just use Release.
- If building this project does not work immediately, remove the native reference from the solution, right-click "Native References" -> "Add Native References", and click
ios/KeyManager/build/Release-fat/KeyManager.framework/KeyManager(i.e. the executable file). - Right-click to open the added native reference's Properties and make sure "Smart Link" is checked.
- Also under Properties, add
Foundation CryptoKit LocalAuthenticationto the Frameworks field.
- Open
xamarin-native/Signing/Signing.slnin Visual Studio, and add the referenceKeyManagerIos/KeyManagerIos/bin/Debug/NativeLibrary.dll(as a ".NET Assembly") to the iOS project (here). You can now build and deploy to iOS using the Secure Enclave.- In theory this should also work for the iOS Simulator, but I had a lot of trouble doing this and unfortunately can't really figure out why.
Troubleshooting:
- Xcode gives
umbrella header ... not found: open the KeyManager project, and under "Build Phases" -> "Headers", move the header from "Project" to "Public" xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance: Run this command:
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
- Simulator app crashes, debug log shows
error accessing keychain: -34018:- In the
Signing.iOSproject, openEntitlements.plistand add theKeychain Access Groupsproperty if it is not present. - Open
Signing.iOSproject options, and check that "iOS Bundle Signing" has "Custom Entitlements" set toEntitlements.plist.
- In the
- If you get weird errors in the
xamarin-nativesolution, you can try removing the Xamarin.Essentials NuGet package and adding it again.
- If you can't build the KeyManager Android Studio project, try opening the
build.gradlefile in theKeyManagerdirectory and clicking any "run" buttons visible in it. - Try updating Android Studio and/or the Kotlin version.
- Try opening the
KeyManagerproject directly, instead of theKeyStoreTestparent project. - Try running the "app" target of the
KeystoreTestproject.