Keychain is stored in the SQLite database on iOS.
Location of this database file:
Real machine:
/private/var/keychains/keychain-2.db
Virtual machines:
/users/user-home/library/developer/coresimulator/devices/26dca62c-b516-4dea-a601-5c2d0ea07710/data/library/ Keychains/keychain-2-debug.db
In the virtual machine, this database can not read the test, very strange.
Each of the following items represents a table. The fields for each table are different.
Table for Ksecclassgenericpassword: GENP
Table for Ksecclassinternetpassword: inet
Table for ksecclasscertificate: Cert
Cftyperef ksecclasskey corresponding table: Keys
Cftyperef ksecclassidentity corresponding table: Not found, it should be cert and key The two tables together, each put part.
Each table has fields that are defined at the beginning of the ksecattr.
Some of the fields in the table are maintained by the system itself, such as CDate: Creation time, Mdate: Modification time, creator, etc.
Each of these fields specifies the data type, so what type of value is the field dead.
For example, Ksecattrservice under Ksecclassgenericpassword can only hold strings.
Because some of the values of the fields are enumerated types, such as
The Ksecattrprotocol field under Ksecclassinternetpassword is an enumeration type,
So we define a lot of constants that start with Ksecattrprotocol.
Most commonly used Ksecclassgenericpassword table: GENP
The primary key for this table is Ksecattraccount and ksecattrservice, so create a newSecitem, these two items cannot be weighed in an existing item.
These three constants correspond to the data fields of the table, but when they are removed from the database, they are converted to a different datatype.
This field is encrypted and saved.
Ksecvaluedata
Ksecvalueref
Ksecvaluepersistentref
Ksecclassgenericpassword Item Attributes:
Ksecattraccessible
Ksecattraccesscontrol
Ksecattraccessgroup corresponding field: AgRP
ksecattrcreationdate corresponding field: Cdat
ksecattrmodificationdate corresponding field: Mdat
ksecattrdescription corresponding field: desc
Ksecattrcomment
Ksecattrcreator corresponding field: CRTR
Ksecattrtype corresponding field: type
Ksecattrlabel corresponding field: LABL
ksecattrisinvisible corresponding field: Invi
ksecattrisnegative corresponding field: Nega
Ksecattraccount corresponding field: Acct
Ksecattrservice corresponding field: Svce
ksecattrgeneric corresponding field: Gena
Apple's official Keychainitemwrapper library uses Ksecclassgenericpassword, but it's wrong. This library is too old, and has not been updated for a long time, not recommended.
-(ID) Initwithidentifier: (NSString *) identifier Accessgroup: (NSString *) Accessgroup;
The value of identifier is set to the Ksecattrgeneric field, which is wrong, because Ksecattrgeneric is not a primary key.
Therefore, the following code, the second item will be error, because the primary key is repeated.
Keychainitemwrapper * keychin1 = [[Keychainitemwrapper alloc]initwithidentifier:@ "Pwd1" accessgroup:nil];
[Keychin1 setobject:pwd1 Forkey: (__bridge ID) ksecvaluedata];
After the above execution, the following execution error occurs:
Keychainitemwrapper * keychin2 = [[Keychainitemwrapper alloc]initwithidentifier:@ "Pwd2" accessgroup:nil];
[Keychin2 setobject:pwd2 Forkey: (__bridge ID) ksecvaluedata];
You can do it with the following:
Keychainitemwrapper * keychin2 = [[Keychainitemwrapper alloc]initwithidentifier:@ "Pwd2" accessgroup:nil];
[Keychin2 setobject:pwd2 Forkey: (__bridge ID) ksecattrservice];
Research on the keychain storage structure in iOS