在 kSecAttrAcct 中存储 NSData object 时,iOS 和 MacOS 上的不同钥匙串行为
Differing keychain behavior on iOS and MacOS when storing an NSData object in kSecAttrAcct
iOS 和 MacOS 在存储和获取 kSecAttrAcct
属性中带有 NSData
object 的钥匙串条目时的行为似乎有所不同。尽管 apple docs 指定这应该是一个字符串,但我已经看到库存储 NSData
objects 的实例。
为什么 iOS 和 MacOS 之间有 不同的处理方式,哪个代码块(因为它是开源的)是导致它?
正在获取 iOS 上的钥匙串条目,其中 kSecAttrAcct
值为 returned :
(lldb) po queryResult
<__NSArrayM 0x60c00025a9a0>(
{
acct = <6261726b 6579>;
agrp = "K7J25DP2KC.com.squareup.ValetTestAPp";
cdat = "2017-12-01 22:16:57 +0000";
mdat = "2017-12-01 22:16:57 +0000";
musr = <>;
pdmn = ak;
persistref = <>;
sha1 = <cf3cf6e6 5aff34b9 0563232a a9c17bee 86e28cfa>;
svce = "some_identifier_ios";
sync = 0;
tomb = 0;
}
)
在 MacOS 中获取钥匙串条目,其中 kSecAttrAcct
值不是 returned:
<__NSArrayM 0x60000005ce30>(
{
cdat = "2017-12-01 22:14:38 +0000";
class = genp;
labl = "some_identifier_macos";
mdat = "2017-12-01 22:14:38 +0000";
svce = "some_identifier_macos";
"v_Ref" = "<SecKeychainItem 0x102c21040 [0x7fffaf65b570]>";
}
)
如果存储 NSString
,iOS 和 MacOS return 字典中预期的帐户值。
{
acct = "accountKey";
...
}
Apple 安全源代码
我花了一些时间浏览 latest apple security open source code, SecItem.c and SecItem.cpp。还有一个SecItemShim.h
header,其中包含以下注释:
SecItemShim defines functions and macros for shimming iOS Security implementation to be used inside OSX.
还有 SecItemAdd_ios
、SecItemAdd_osx
、SecItemCopyMatching_ios
和 SecItemCopyMatching_osx
函数,这表明 iOS 和 OSX。
虽然我无法查明导致对 kSecAttrAccount
值进行不同处理的确切代码行。如果有不同的行为,我希望看到类似以下内容的内容:
#if SECITEM_SHIM_OSX
if(isString(account)) { add value to dictionary } else { ignore value }
#elif
add value to dictionary
#endif
也许这是一个错误?即使是这样,知道是哪段代码导致了它仍然很好。
附录:下面的示例代码在 Xcode 的 iOS 和 MacOS 项目中都是 运行。
NSString *identifier = @"some_identifier_<os_name here>";
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
[self setValue];
[self fetchValue];
}
- (void)setValue;
{
NSData *accountBlob = [@"accountKey" dataUsingEncoding:NSUTF8StringEncoding];
NSData *dataBlob = [@"accountValue" dataUsingEncoding:NSUTF8StringEncoding];
// kSecAttrAccount entry is expected to be a CFString, but a CFDataRef can also be stored as a value.
NSMutableDictionary *keychainData = [self _baseQuery];
keychainData[(__bridge id)kSecAttrAccount] = accountBlob;
keychainData[(__bridge id)kSecValueData] = dataBlob;
SecItemDelete((__bridge CFDictionaryRef)keychainData);
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)keychainData, NULL);
NSLog(@"Insert Status: %@", @(status));
}
- (id)fetchValue;
{
NSMutableDictionary *query = [self _baseQuery];
query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;
query[(__bridge id)kSecReturnAttributes] = @YES;
query[(__bridge id)kSecReturnData] = @NO;
query[(__bridge id)kSecReturnRef] = @NO;
query[(__bridge id)kSecReturnPersistentRef] = @YES;
CFTypeRef dataTypeRef = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef);
NSLog(@"Fetch status: %@", @(status));
NSArray *queryResult = (__bridge_transfer NSArray *)dataTypeRef;
return queryResult;
}
- (NSMutableDictionary *)_baseQuery;
{
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
query[(__bridge id)kSecAttrService] = identifier;
query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
return query;
}
我希望 iOS 和 MacOS 上的钥匙链行为都使用 AES 和加密哈希函数 来存储 NSData 对象。
注意:(from here)
Since the release of the iPhone 3GS, Apple has built encryption into
the hardware and firmware of its iPads and iPhones. Every iOS device
now has a dedicated Advanced Encryption Standard (AES) 256-bit crypto
engine that sits between the flash storage and main system memory. The
engine works in conjunction with the SHA-1 cryptographic hash function
-- which is implemented in the hardware as well -- to reduce overhead for cryptographic operations.
最后,在我看来:
iOS 在 kSecAttrAcct 中存储 NSData 对象时 iOS 上的钥匙串行为将不得不考虑硬件和固件的加密,但 MacOS 钥匙串行为不必处理 firmware/hardware...解释一下区别..
找到这个 Apple reply to a dev forum thread:
There are two implementations of the SecItem API:
the iOS implementation, which is also used for iCloud Keychain on OS X
the OS X implementation, which is a compatibility shim that bridges over to the traditional keychain
Note Both are available in Darwin. Search the Security project for SecItemUpdate_ios and SecItemUpdate_osx to see how this works under the covers.
The iOS implementation is based on SQLite. If you’re familiar with SQLite you’ll know that it is, at its core, untyped, and thus the iOS implementation has to do its own type conversion. This is why that implementation is somewhat forgiving on the types front. However…
IMPORTANT I strongly recommend that you use the types specified in the header. Other types do work but that’s an accident of the implementation rather than a designed in feature. Moreover, as there are two implementations, it’s not always the case that these accidents line up.
I realise that this rule is broken by various bits of Apple sample code.
这解释了为什么 iOS 比 OSX 更宽容,并存储 kSecAttrAccount
值而 OSX 丢弃它。
iOS 和 MacOS 在存储和获取 kSecAttrAcct
属性中带有 NSData
object 的钥匙串条目时的行为似乎有所不同。尽管 apple docs 指定这应该是一个字符串,但我已经看到库存储 NSData
objects 的实例。
为什么 iOS 和 MacOS 之间有 不同的处理方式,哪个代码块(因为它是开源的)是导致它?
正在获取 iOS 上的钥匙串条目,其中 kSecAttrAcct
值为 returned :
(lldb) po queryResult
<__NSArrayM 0x60c00025a9a0>(
{
acct = <6261726b 6579>;
agrp = "K7J25DP2KC.com.squareup.ValetTestAPp";
cdat = "2017-12-01 22:16:57 +0000";
mdat = "2017-12-01 22:16:57 +0000";
musr = <>;
pdmn = ak;
persistref = <>;
sha1 = <cf3cf6e6 5aff34b9 0563232a a9c17bee 86e28cfa>;
svce = "some_identifier_ios";
sync = 0;
tomb = 0;
}
)
在 MacOS 中获取钥匙串条目,其中 kSecAttrAcct
值不是 returned:
<__NSArrayM 0x60000005ce30>(
{
cdat = "2017-12-01 22:14:38 +0000";
class = genp;
labl = "some_identifier_macos";
mdat = "2017-12-01 22:14:38 +0000";
svce = "some_identifier_macos";
"v_Ref" = "<SecKeychainItem 0x102c21040 [0x7fffaf65b570]>";
}
)
如果存储 NSString
,iOS 和 MacOS return 字典中预期的帐户值。
{
acct = "accountKey";
...
}
Apple 安全源代码
我花了一些时间浏览 latest apple security open source code, SecItem.c and SecItem.cpp。还有一个SecItemShim.h
header,其中包含以下注释:
SecItemShim defines functions and macros for shimming iOS Security implementation to be used inside OSX.
还有 SecItemAdd_ios
、SecItemAdd_osx
、SecItemCopyMatching_ios
和 SecItemCopyMatching_osx
函数,这表明 iOS 和 OSX。
虽然我无法查明导致对 kSecAttrAccount
值进行不同处理的确切代码行。如果有不同的行为,我希望看到类似以下内容的内容:
#if SECITEM_SHIM_OSX
if(isString(account)) { add value to dictionary } else { ignore value }
#elif
add value to dictionary
#endif
也许这是一个错误?即使是这样,知道是哪段代码导致了它仍然很好。
附录:下面的示例代码在 Xcode 的 iOS 和 MacOS 项目中都是 运行。
NSString *identifier = @"some_identifier_<os_name here>";
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
[self setValue];
[self fetchValue];
}
- (void)setValue;
{
NSData *accountBlob = [@"accountKey" dataUsingEncoding:NSUTF8StringEncoding];
NSData *dataBlob = [@"accountValue" dataUsingEncoding:NSUTF8StringEncoding];
// kSecAttrAccount entry is expected to be a CFString, but a CFDataRef can also be stored as a value.
NSMutableDictionary *keychainData = [self _baseQuery];
keychainData[(__bridge id)kSecAttrAccount] = accountBlob;
keychainData[(__bridge id)kSecValueData] = dataBlob;
SecItemDelete((__bridge CFDictionaryRef)keychainData);
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)keychainData, NULL);
NSLog(@"Insert Status: %@", @(status));
}
- (id)fetchValue;
{
NSMutableDictionary *query = [self _baseQuery];
query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;
query[(__bridge id)kSecReturnAttributes] = @YES;
query[(__bridge id)kSecReturnData] = @NO;
query[(__bridge id)kSecReturnRef] = @NO;
query[(__bridge id)kSecReturnPersistentRef] = @YES;
CFTypeRef dataTypeRef = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef);
NSLog(@"Fetch status: %@", @(status));
NSArray *queryResult = (__bridge_transfer NSArray *)dataTypeRef;
return queryResult;
}
- (NSMutableDictionary *)_baseQuery;
{
NSMutableDictionary *query = [[NSMutableDictionary alloc] init];
query[(__bridge id)kSecAttrService] = identifier;
query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
return query;
}
我希望 iOS 和 MacOS 上的钥匙链行为都使用 AES 和加密哈希函数 来存储 NSData 对象。
注意:(from here)
Since the release of the iPhone 3GS, Apple has built encryption into the hardware and firmware of its iPads and iPhones. Every iOS device now has a dedicated Advanced Encryption Standard (AES) 256-bit crypto engine that sits between the flash storage and main system memory. The engine works in conjunction with the SHA-1 cryptographic hash function -- which is implemented in the hardware as well -- to reduce overhead for cryptographic operations.
最后,在我看来:
iOS 在 kSecAttrAcct 中存储 NSData 对象时 iOS 上的钥匙串行为将不得不考虑硬件和固件的加密,但 MacOS 钥匙串行为不必处理 firmware/hardware...解释一下区别..
找到这个 Apple reply to a dev forum thread:
There are two implementations of the SecItem API:
the iOS implementation, which is also used for iCloud Keychain on OS X
the OS X implementation, which is a compatibility shim that bridges over to the traditional keychain
Note Both are available in Darwin. Search the Security project for SecItemUpdate_ios and SecItemUpdate_osx to see how this works under the covers.
The iOS implementation is based on SQLite. If you’re familiar with SQLite you’ll know that it is, at its core, untyped, and thus the iOS implementation has to do its own type conversion. This is why that implementation is somewhat forgiving on the types front. However…
IMPORTANT I strongly recommend that you use the types specified in the header. Other types do work but that’s an accident of the implementation rather than a designed in feature. Moreover, as there are two implementations, it’s not always the case that these accidents line up.
I realise that this rule is broken by various bits of Apple sample code.
这解释了为什么 iOS 比 OSX 更宽容,并存储 kSecAttrAccount
值而 OSX 丢弃它。