YYKeychain.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. //
  2. // YYKeychain.h
  3. // YYKit <https://github.com/ibireme/YYKit>
  4. //
  5. // Created by ibireme on 14/10/15.
  6. // Copyright (c) 2015 ibireme.
  7. //
  8. // This source code is licensed under the MIT-style license found in the
  9. // LICENSE file in the root directory of this source tree.
  10. //
  11. #import <Foundation/Foundation.h>
  12. @class YYKeychainItem;
  13. NS_ASSUME_NONNULL_BEGIN
  14. /**
  15. A wrapper for system keychain API.
  16. Inspired by [SSKeychain](https://github.com/soffes/sskeychain) 😜
  17. */
  18. @interface YYKeychain : NSObject
  19. #pragma mark - Convenience method for keychain
  20. ///=============================================================================
  21. /// @name Convenience method for keychain
  22. ///=============================================================================
  23. /**
  24. Returns the password for a given account and service, or `nil` if not found or
  25. an error occurs.
  26. @param serviceName The service for which to return the corresponding password.
  27. This value must not be nil.
  28. @param account The account for which to return the corresponding password.
  29. This value must not be nil.
  30. @param error On input, a pointer to an error object. If an error occurs,
  31. this pointer is set to an actual error object containing the error information.
  32. You may specify nil for this parameter if you do not want the error information.
  33. See `YYKeychainErrorCode`.
  34. @return Password string, or nil when not found or error occurs.
  35. */
  36. + (nullable NSString *)getPasswordForService:(NSString *)serviceName
  37. account:(NSString *)account
  38. error:(NSError **)error;
  39. + (nullable NSString *)getPasswordForService:(NSString *)serviceName
  40. account:(NSString *)account;
  41. /**
  42. Deletes a password from the Keychain.
  43. @param serviceName The service for which to return the corresponding password.
  44. This value must not be nil.
  45. @param account The account for which to return the corresponding password.
  46. This value must not be nil.
  47. @param error On input, a pointer to an error object. If an error occurs,
  48. this pointer is set to an actual error object containing the error information.
  49. You may specify nil for this parameter if you do not want the error information.
  50. See `YYKeychainErrorCode`.
  51. @return Whether succeed.
  52. */
  53. + (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account error:(NSError **)error;
  54. + (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account;
  55. /**
  56. Insert or update the password for a given account and service.
  57. @param password The new password.
  58. @param serviceName The service for which to return the corresponding password.
  59. This value must not be nil.
  60. @param account The account for which to return the corresponding password.
  61. This value must not be nil.
  62. @param error On input, a pointer to an error object. If an error occurs,
  63. this pointer is set to an actual error object containing the error information.
  64. You may specify nil for this parameter if you do not want the error information.
  65. See `YYKeychainErrorCode`.
  66. @return Whether succeed.
  67. */
  68. + (BOOL)setPassword:(NSString *)password
  69. forService:(NSString *)serviceName
  70. account:(NSString *)account
  71. error:(NSError **)error;
  72. + (BOOL)setPassword:(NSString *)password
  73. forService:(NSString *)serviceName
  74. account:(NSString *)account;
  75. #pragma mark - Full query for keychain (SQL-like)
  76. ///=============================================================================
  77. /// @name Full query for keychain (SQL-like)
  78. ///=============================================================================
  79. /**
  80. Insert an item into keychain.
  81. @discussion The service,account,password is required. If there's item exist
  82. already, an error occurs and insert fail.
  83. @param item The item to insert.
  84. @param error On input, a pointer to an error object. If an error occurs,
  85. this pointer is set to an actual error object containing the error information.
  86. You may specify nil for this parameter if you do not want the error information.
  87. See `YYKeychainErrorCode`.
  88. @return Whether succeed.
  89. */
  90. + (BOOL)insertItem:(YYKeychainItem *)item error:(NSError **)error;
  91. + (BOOL)insertItem:(YYKeychainItem *)item;
  92. /**
  93. Update item in keychain.
  94. @discussion The service,account,password is required. If there's no item exist
  95. already, an error occurs and insert fail.
  96. @param item The item to insert.
  97. @param error On input, a pointer to an error object. If an error occurs,
  98. this pointer is set to an actual error object containing the error information.
  99. You may specify nil for this parameter if you do not want the error information.
  100. See `YYKeychainErrorCode`.
  101. @return Whether succeed.
  102. */
  103. + (BOOL)updateItem:(YYKeychainItem *)item error:(NSError **)error;
  104. + (BOOL)updateItem:(YYKeychainItem *)item;
  105. /**
  106. Delete items from keychain.
  107. @discussion The service,account,password is required. If there's item exist
  108. already, an error occurs and insert fail.
  109. @param item The item to update.
  110. @param error On input, a pointer to an error object. If an error occurs,
  111. this pointer is set to an actual error object containing the error information.
  112. You may specify nil for this parameter if you do not want the error information.
  113. See `YYKeychainErrorCode`.
  114. @return Whether succeed.
  115. */
  116. + (BOOL)deleteItem:(YYKeychainItem *)item error:(NSError **)error;
  117. + (BOOL)deleteItem:(YYKeychainItem *)item;
  118. /**
  119. Find an item from keychain.
  120. @discussion The service,account is optinal. It returns only one item if there
  121. exist multi.
  122. @param item The item for query.
  123. @param error On input, a pointer to an error object. If an error occurs,
  124. this pointer is set to an actual error object containing the error information.
  125. You may specify nil for this parameter if you do not want the error information.
  126. See `YYKeychainErrorCode`.
  127. @return An item or nil.
  128. */
  129. + (nullable YYKeychainItem *)selectOneItem:(YYKeychainItem *)item error:(NSError **)error;
  130. + (nullable YYKeychainItem *)selectOneItem:(YYKeychainItem *)item;
  131. /**
  132. Find all items matches the query.
  133. @discussion The service,account is optinal. It returns all item matches by the
  134. query.
  135. @param item The item for query.
  136. @param error On input, a pointer to an error object. If an error occurs,
  137. this pointer is set to an actual error object containing the error information.
  138. You may specify nil for this parameter if you do not want the error information.
  139. See `YYKeychainErrorCode`.
  140. @return An array of YYKeychainItem.
  141. */
  142. + (nullable NSArray<YYKeychainItem *> *)selectItems:(YYKeychainItem *)item error:(NSError **)error;
  143. + (nullable NSArray<YYKeychainItem *> *)selectItems:(YYKeychainItem *)item;
  144. @end
  145. #pragma mark - Const
  146. /**
  147. Error code in YYKeychain API.
  148. */
  149. typedef NS_ENUM (NSUInteger, YYKeychainErrorCode) {
  150. YYKeychainErrorUnimplemented = 1, ///< Function or operation not implemented.
  151. YYKeychainErrorIO, ///< I/O error (bummers)
  152. YYKeychainErrorOpWr, ///< File already open with with write permission.
  153. YYKeychainErrorParam, ///< One or more parameters passed to a function where not valid.
  154. YYKeychainErrorAllocate, ///< Failed to allocate memory.
  155. YYKeychainErrorUserCancelled, ///< User cancelled the operation.
  156. YYKeychainErrorBadReq, ///< Bad parameter or invalid state for operation.
  157. YYKeychainErrorInternalComponent, ///< Internal...
  158. YYKeychainErrorNotAvailable, ///< No keychain is available. You may need to restart your computer.
  159. YYKeychainErrorDuplicateItem, ///< The specified item already exists in the keychain.
  160. YYKeychainErrorItemNotFound, ///< The specified item could not be found in the keychain.
  161. YYKeychainErrorInteractionNotAllowed, ///< User interaction is not allowed.
  162. YYKeychainErrorDecode, ///< Unable to decode the provided data.
  163. YYKeychainErrorAuthFailed, ///< The user name or passphrase you entered is not.
  164. };
  165. /**
  166. When query to return the item's data, the error
  167. errSecInteractionNotAllowed will be returned if the item's data is not
  168. available until a device unlock occurs.
  169. */
  170. typedef NS_ENUM (NSUInteger, YYKeychainAccessible) {
  171. YYKeychainAccessibleNone = 0, ///< no value
  172. /** Item data can only be accessed
  173. while the device is unlocked. This is recommended for items that only
  174. need be accesible while the application is in the foreground. Items
  175. with this attribute will migrate to a new device when using encrypted
  176. backups. */
  177. YYKeychainAccessibleWhenUnlocked,
  178. /** Item data can only be
  179. accessed once the device has been unlocked after a restart. This is
  180. recommended for items that need to be accesible by background
  181. applications. Items with this attribute will migrate to a new device
  182. when using encrypted backups.*/
  183. YYKeychainAccessibleAfterFirstUnlock,
  184. /** Item data can always be accessed
  185. regardless of the lock state of the device. This is not recommended
  186. for anything except system use. Items with this attribute will migrate
  187. to a new device when using encrypted backups.*/
  188. YYKeychainAccessibleAlways,
  189. /** Item data can
  190. only be accessed while the device is unlocked. This class is only
  191. available if a passcode is set on the device. This is recommended for
  192. items that only need to be accessible while the application is in the
  193. foreground. Items with this attribute will never migrate to a new
  194. device, so after a backup is restored to a new device, these items
  195. will be missing. No items can be stored in this class on devices
  196. without a passcode. Disabling the device passcode will cause all
  197. items in this class to be deleted.*/
  198. YYKeychainAccessibleWhenPasscodeSetThisDeviceOnly,
  199. /** Item data can only
  200. be accessed while the device is unlocked. This is recommended for items
  201. that only need be accesible while the application is in the foreground.
  202. Items with this attribute will never migrate to a new device, so after
  203. a backup is restored to a new device, these items will be missing. */
  204. YYKeychainAccessibleWhenUnlockedThisDeviceOnly,
  205. /** Item data can
  206. only be accessed once the device has been unlocked after a restart.
  207. This is recommended for items that need to be accessible by background
  208. applications. Items with this attribute will never migrate to a new
  209. device, so after a backup is restored to a new device these items will
  210. be missing.*/
  211. YYKeychainAccessibleAfterFirstUnlockThisDeviceOnly,
  212. /** Item data can always
  213. be accessed regardless of the lock state of the device. This option
  214. is not recommended for anything except system use. Items with this
  215. attribute will never migrate to a new device, so after a backup is
  216. restored to a new device, these items will be missing.*/
  217. YYKeychainAccessibleAlwaysThisDeviceOnly,
  218. };
  219. /**
  220. Whether the item in question can be synchronized.
  221. */
  222. typedef NS_ENUM (NSUInteger, YYKeychainQuerySynchronizationMode) {
  223. /** Default, Don't care for synchronization */
  224. YYKeychainQuerySynchronizationModeAny = 0,
  225. /** Is not synchronized */
  226. YYKeychainQuerySynchronizationModeNo,
  227. /** To add a new item which can be synced to other devices, or to obtain
  228. synchronized results from a query*/
  229. YYKeychainQuerySynchronizationModeYes,
  230. } NS_AVAILABLE_IOS (7_0);
  231. #pragma mark - Item
  232. /**
  233. Wrapper for keychain item/query.
  234. */
  235. @interface YYKeychainItem : NSObject <NSCopying>
  236. @property (nullable, nonatomic, copy) NSString *service; ///< kSecAttrService
  237. @property (nullable, nonatomic, copy) NSString *account; ///< kSecAttrAccount
  238. @property (nullable, nonatomic, copy) NSData *passwordData; ///< kSecValueData
  239. @property (nullable, nonatomic, copy) NSString *password; ///< shortcut for `passwordData`
  240. @property (nullable, nonatomic, copy) id <NSCoding> passwordObject; ///< shortcut for `passwordData`
  241. @property (nullable, nonatomic, copy) NSString *label; ///< kSecAttrLabel
  242. @property (nullable, nonatomic, copy) NSNumber *type; ///< kSecAttrType (FourCC)
  243. @property (nullable, nonatomic, copy) NSNumber *creater; ///< kSecAttrCreator (FourCC)
  244. @property (nullable, nonatomic, copy) NSString *comment; ///< kSecAttrComment
  245. @property (nullable, nonatomic, copy) NSString *descr; ///< kSecAttrDescription
  246. @property (nullable, nonatomic, readonly, strong) NSDate *modificationDate; ///< kSecAttrModificationDate
  247. @property (nullable, nonatomic, readonly, strong) NSDate *creationDate; ///< kSecAttrCreationDate
  248. @property (nullable, nonatomic, copy) NSString *accessGroup; ///< kSecAttrAccessGroup
  249. @property (nonatomic) YYKeychainAccessible accessible; ///< kSecAttrAccessible
  250. @property (nonatomic) YYKeychainQuerySynchronizationMode synchronizable NS_AVAILABLE_IOS(7_0); ///< kSecAttrSynchronizable
  251. @end
  252. NS_ASSUME_NONNULL_END