SLKeyChain.m 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. //
  2. // SLKeyChain.m
  3. // DarkMode
  4. //
  5. // Created by wsl on 2020/6/15.
  6. // Copyright © 2020 https://github.com/wsl2ls ----- . All rights reserved.
  7. //
  8. #import "SLKeyChain.h"
  9. #import <Security/SecItem.h>
  10. #import <Security/SecBase.h>
  11. NSString* const SLkeychainService = @"com.wsl.ios.keychain";
  12. static NSString* const keychainErrorDomain = @"com.wsl.ios.keychain.errorDomain";
  13. static NSInteger const kErrorCodeKeychainSomeArgumentsInvalid = 1000; //! 传入的部分参数无效
  14. @implementation SLKeyChain
  15. ///更新钥匙串中的用户名和密码
  16. + (NSError *)updateKeychainWithService:(NSString *)service account:(NSString *)account password:(NSString *)password {
  17. if (!account || !password || !service) {
  18. NSError *error = [self errorWithErrorCode:kErrorCodeKeychainSomeArgumentsInvalid];
  19. return error;
  20. }
  21. NSDictionary *queryItems = @{(id)kSecClass: (id)kSecClassGenericPassword,
  22. (id)kSecAttrService: service,
  23. (id)kSecAttrAccount: account
  24. };
  25. NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
  26. NSDictionary *updatedItems = @{
  27. (id)kSecValueData: passwordData,
  28. };
  29. OSStatus updateStatus = SecItemUpdate((CFDictionaryRef)queryItems, (CFDictionaryRef)updatedItems);
  30. return [self errorWithErrorCode:updateStatus];
  31. }
  32. ///删除用户信息
  33. + (NSError *)deleteWithService:(NSString *)service account:(NSString *)account {
  34. if (!service || !account) {
  35. return [self errorWithErrorCode:kErrorCodeKeychainSomeArgumentsInvalid];
  36. }
  37. NSDictionary *deleteSecItems = @{
  38. (id)kSecClass: (id)kSecClassGenericPassword,
  39. (id)kSecAttrService: service,
  40. (id)kSecAttrAccount: account
  41. };
  42. OSStatus errorCode = SecItemDelete((CFDictionaryRef)deleteSecItems);
  43. return [self errorWithErrorCode:errorCode];
  44. }
  45. ///查询用户信息 查到的结果存在NSError中
  46. + (NSError *)queryKeychainWithService:(NSString *)service account:(NSString *)account {
  47. if (!service || !account) {
  48. return [self errorWithErrorCode:kErrorCodeKeychainSomeArgumentsInvalid];
  49. }
  50. NSDictionary *matchSecItems = @{
  51. (id)kSecClass: (id)kSecClassGenericPassword,
  52. (id)kSecAttrService: service,
  53. (id)kSecAttrAccount: account,
  54. (id)kSecMatchLimit: (id)kSecMatchLimitOne,
  55. (id)kSecReturnData: @(YES)
  56. };
  57. CFTypeRef dataRef = nil;
  58. OSStatus errorCode = SecItemCopyMatching((CFDictionaryRef)matchSecItems, (CFTypeRef *)&dataRef);
  59. if (errorCode == errSecSuccess) {
  60. NSString *password = [[NSString alloc] initWithData:CFBridgingRelease(dataRef) encoding:NSUTF8StringEncoding];
  61. return [self errorWithErrorCode:errSecSuccess errorMessage:password];
  62. }
  63. return [self errorWithErrorCode:errorCode];
  64. }
  65. ///保存用户信息
  66. + (NSError *)saveKeychainWithService:(NSString *)service account:(NSString *)account password:(NSString *)password {
  67. if (!account || !password || !service) {
  68. NSError *error = [self errorWithErrorCode:kErrorCodeKeychainSomeArgumentsInvalid];
  69. return error;
  70. }
  71. NSError *queryError = [self queryKeychainWithService:service account:account];
  72. if (queryError.code == errSecSuccess) {
  73. // update
  74. return [self updateKeychainWithService:service account:account password:password];
  75. }
  76. NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
  77. // save
  78. NSDictionary *saveSecItems = @{(id)kSecClass: (id)kSecClassGenericPassword,
  79. (id)kSecAttrService: service,
  80. (id)kSecAttrAccount: account,
  81. (id)kSecValueData: passwordData
  82. };
  83. OSStatus saveStatus = SecItemAdd((CFDictionaryRef)saveSecItems, NULL);
  84. return [self errorWithErrorCode:saveStatus];
  85. }
  86. ///错误信息
  87. + (NSError *)errorWithErrorCode:(OSStatus)errorCode {
  88. NSString *errorMsg = nil;
  89. switch (errorCode) {
  90. case errSecSuccess: {
  91. NSLog(@"操作成功");
  92. return nil;
  93. break;
  94. }
  95. case kErrorCodeKeychainSomeArgumentsInvalid:
  96. errorMsg = NSLocalizedString(@"参数无效", nil);
  97. break;
  98. case errSecDuplicateItem: // -25299
  99. errorMsg = NSLocalizedString(@"The specified item already exists in the keychain. ", nil);
  100. break;
  101. case errSecItemNotFound: // -25300
  102. errorMsg = NSLocalizedString(@"The specified item could not be found in the keychain. ", nil);
  103. break;
  104. default: {
  105. if (@available(iOS 11.3, *)) {
  106. errorMsg = (__bridge_transfer NSString *)SecCopyErrorMessageString(errorCode, NULL);
  107. }
  108. break;
  109. }
  110. }
  111. NSDictionary *errorUserInfo = nil;
  112. if (errorMsg) {
  113. errorUserInfo = @{NSLocalizedDescriptionKey: errorMsg};
  114. NSLog(@"%s--Line:%d--错误码:%d--错误信息:%@", __FUNCTION__, __LINE__, errorCode, errorMsg);
  115. }
  116. return [NSError errorWithDomain:keychainErrorDomain code:kErrorCodeKeychainSomeArgumentsInvalid userInfo:errorUserInfo];
  117. }
  118. + (NSError *)errorWithErrorCode:(OSStatus)errCode errorMessage:(NSString *)errorMsg {
  119. if (errCode == errSecSuccess && errorMsg) {
  120. NSLog(@"操作成功");
  121. return [NSError errorWithDomain:keychainErrorDomain code:errSecSuccess userInfo:@{NSLocalizedDescriptionKey: errorMsg}];
  122. } else {
  123. return [self errorWithErrorCode:errCode];
  124. }
  125. }
  126. @end