99#import " org_cryptomator_macos_keychain_MacKeychain_Native.h"
1010#import < Foundation/Foundation.h>
1111#import < Security/Security.h>
12+ #import < LocalAuthentication/LocalAuthentication.h>
1213
13- JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Native_storePassword (JNIEnv *env, jobject thisObj, jbyteArray service, jbyteArray key, jbyteArray password) {
14+ static LAContext *sharedContext = nil ;
15+ static LAContext* getSharedLAContext (void ) {
16+ static dispatch_once_t onceToken;
17+ dispatch_once (&onceToken, ^{
18+ sharedContext = [[LAContext alloc ] init ];
19+ });
20+ return sharedContext;
21+ }
22+
23+ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Native_storePassword (JNIEnv *env, jobject thisObj, jbyteArray service, jbyteArray key, jbyteArray password, jboolean requireOsAuthentication) {
1424 jbyte *serviceStr = (*env)->GetByteArrayElements (env, service, NULL );
1525 jbyte *keyStr = (*env)->GetByteArrayElements (env, key, NULL );
1626 jbyte *pwStr = (*env)->GetByteArrayElements (env, password, NULL );
1727 jsize length = (*env)->GetArrayLength (env, password);
1828
1929 // find existing:
20- NSDictionary *query = @{
30+ NSMutableDictionary *query = [ @{
2131 (__bridge id )kSecClass : (__bridge id )kSecClassGenericPassword ,
2232 (__bridge id )kSecAttrService : [NSString stringWithCString: (char *)serviceStr encoding: NSUTF8StringEncoding],
2333 (__bridge id )kSecAttrAccount : [NSString stringWithCString: (char *)keyStr encoding: NSUTF8StringEncoding],
2434 (__bridge id )kSecReturnAttributes : @YES ,
2535 (__bridge id )kSecReturnData : @YES ,
2636 (__bridge id )kSecMatchLimit : (__bridge id )kSecMatchLimitOne
27- };
37+ } mutableCopy];
38+ if (requireOsAuthentication) {
39+ LAContext *context = getSharedLAContext ();
40+ query[(__bridge id )kSecUseAuthenticationContext ] = context;
41+ }
2842 CFDictionaryRef result = NULL ;
2943 OSStatus status = SecItemCopyMatching ((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
3044 if (status == errSecSuccess && result != NULL ) {
@@ -35,12 +49,15 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati
3549 status = SecItemUpdate ((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)attributesToUpdate);
3650 } else if (status == errSecItemNotFound) {
3751 // add new:
38- NSDictionary *attributes = @{
52+ NSMutableDictionary *attributes = [ @{
3953 (__bridge id )kSecClass : (__bridge id )kSecClassGenericPassword ,
4054 (__bridge id )kSecAttrService : [NSString stringWithCString: (char *)serviceStr encoding: NSUTF8StringEncoding],
4155 (__bridge id )kSecAttrAccount : [NSString stringWithCString: (char *)keyStr encoding: NSUTF8StringEncoding],
4256 (__bridge id )kSecValueData : [NSData dataWithBytes: pwStr length: length]
43- };
57+ } mutableCopy];
58+ if (requireOsAuthentication) {
59+ attributes[(__bridge id )kSecAttrAccessControl ] = (__bridge_transfer id )SecAccessControlCreateWithFlags (kCFAllocatorDefault , kSecAttrAccessibleWhenUnlocked , kSecAccessControlUserPresence , NULL );
60+ }
4461 status = SecItemAdd ((__bridge CFDictionaryRef)attributes, NULL );
4562 } else {
4663 NSLog (@" Error storing item in keychain. Status code: %d " , (int )status);
@@ -57,13 +74,15 @@ JNIEXPORT jbyteArray JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_000
5774 jbyte *keyStr = (*env)->GetByteArrayElements (env, key, NULL );
5875
5976 // find existing:
77+ LAContext *context = getSharedLAContext ();
6078 NSDictionary *query = @{
6179 (__bridge id )kSecClass : (__bridge id )kSecClassGenericPassword ,
6280 (__bridge id )kSecAttrService : [NSString stringWithCString: (char *)serviceStr encoding: NSUTF8StringEncoding],
6381 (__bridge id )kSecAttrAccount : [NSString stringWithCString: (char *)keyStr encoding: NSUTF8StringEncoding],
6482 (__bridge id )kSecReturnAttributes : @YES ,
6583 (__bridge id )kSecReturnData : @YES ,
66- (__bridge id )kSecMatchLimit : (__bridge id )kSecMatchLimitOne
84+ (__bridge id )kSecMatchLimit : (__bridge id )kSecMatchLimitOne ,
85+ (__bridge id )kSecUseAuthenticationContext : context
6786 };
6887 CFDictionaryRef result = NULL ;
6988 OSStatus status = SecItemCopyMatching ((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
@@ -88,18 +107,15 @@ JNIEXPORT jint JNICALL Java_org_cryptomator_macos_keychain_MacKeychain_00024Nati
88107 jbyte *keyStr = (*env)->GetByteArrayElements (env, key, NULL );
89108
90109 // find existing:
110+ LAContext *context = getSharedLAContext ();
91111 NSDictionary *query = @{
92112 (__bridge id )kSecClass : (__bridge id )kSecClassGenericPassword ,
93113 (__bridge id )kSecAttrService : [NSString stringWithCString: (char *)serviceStr encoding: NSUTF8StringEncoding],
94114 (__bridge id )kSecAttrAccount : [NSString stringWithCString: (char *)keyStr encoding: NSUTF8StringEncoding],
95- (__bridge id )kSecMatchLimit : (__bridge id ) kSecMatchLimitOne
115+ (__bridge id )kSecUseAuthenticationContext : context
96116 };
97- CFDictionaryRef result = NULL ;
98- OSStatus status = SecItemCopyMatching ((__bridge CFDictionaryRef)query, (CFTypeRef *)&result);
99- if (status == errSecSuccess && result != NULL ) {
100- // delete:
101- status = SecItemDelete ((__bridge CFDictionaryRef)query);
102- } else if (status != errSecItemNotFound) {
117+ OSStatus status = SecItemDelete ((__bridge CFDictionaryRef)query);
118+ if (status != errSecSuccess) {
103119 NSLog (@" Error deleting item from keychain. Status code: %d " , (int )status);
104120 }
105121
0 commit comments