0.9.7
$ git clone https://github.com/ivRodriguezCA/IRCrypto
构建框架
方案并构建项目(⌘ + b
),这将生成一个IRCrypto.framework
框架,位于您的桌面目录中。创建一个IRCrypto
实例并使用选项进行配置(有关选项的更多信息,请参阅IRPublicConstants
头文件)。当你使用默认选项时,IRCrypto将生成一对RSA密钥(2048位),一个AES密钥(256位),一个用于签名的RSA密钥对(私钥将永远不会离开安全区域)和一个HMAC密钥(256位)。所有这些密钥都将使用TouchID保护保存在密钥chain中。(注意:如果设备不支持TouchID,则需要应用密码
来保护这些密钥。在创建您的IRCrypto实例时使用kIRAppPasswordKey
选项密钥。)
- (void)someMethod {
IRCrypto *crypto = [IRCrypto new];
}
- (BOOL)supportsTouchID {
LAContext *context = [LAContext new];
NSError *error = nil;
return [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
}
- (void)someMethod {
kIRKeyProtection protection = [self supportsTouchID] ? kIRKeyProtectionTouchID : kIRKeyProtectionPassword;
NSDictionary *options = @{
kIRAsymmetricEncryptionProtectionKey:@(protection),
kIRSymmetricEncryptionProtectionKey:@(protection),
kIRHMACProtectionKey:@(protection),
kIRAppPasswordKey: @"my-secret-password"
};
IRCrypto *crypto = [[IRCrypto alloc] initWithOptions:options];
}
- (void)someMethod {
IRCrypto *crypto = [[IRCrypto alloc] initWithOptions:@{kIREncryptionOptionsKey:@(kEncryptionOptionsNone)}];
}
IRCrypto可以帮助你生成安全的AES和HMAC密钥,还可以从密码中导出安全的AES密钥。
生成256位AES密钥
- (void)generateAESKey {
IRCrypto *crypto = ...
NSData *aesKey = [crypto randomAESEncryptionKeyOfLength:32];
//Encrypt using `aesKey`
}
生成256位HMAC密钥
- (void)generateHMACKey {
IRCrypto *crypto = ...
NSData *hmacKey = [crypto randomHMACKeyOfLength:32];
//Use `hmacKey`
}
从密码中导出256位AES密钥
- (void)generateAESKeyFromPassword {
NSString *password = ...
IRCrypto *crypto = [IRCrypto new];
[crypto keyFromPassword:password
ofLength:32
completion:^(NSData * _Nonnull aesKey, NSData * _Nonnull salt) {
// Use the aesKey
}];
}
加密应提供机密性和完整性,这就是我们为什么需要使用类似于认证加密与关联数据(AEAD)的方案。IRCrypto使用高级加密标准 (AES)在加密块链(CBC)模式下进行机密性加密,使用基于散列的消息认证码(HMAC)进行完整性认证。IRCrypto使用RNCryptor文件格式v3来封装标题、密文和MAC。
如果使用默认选项,您可以简单地使用带有明文数据的aeEncryptData:completion:failure:
方法。您不需要保存IV,因为它是RNCryptor数据格式的一部分。
- (void)someAuthenticatedEncryptionMethod {
IRCrypto *crypto = ...
NSData *plaintext = ...
[crypto aeEncryptData:plaintext
completion:^(NSData *cipherData, NSData *iv, NSData *encryptionSalt, NSData *hmacSalt) {
// encryptionSalt and hmacSalt will be nil
// iv is returned but could be ignored
// Do something cipherData
}
failure:^(NSError *error) {
// Handle error
}
];
}
您还可以使用aeEncryptData:symmetricKey:hmacKey:completion:failure:
方法使用自己的密钥进行加密(建议使用2个不同的密钥,一个用于AES,一个用于HMAC)。您不需要保存IV,因为它是RNCryptor数据格式的一部分。
- (void)someAuthenticatedEncryptionMethod {
IRCrypto *crypto = ...
NSData *plaintext = ...
NSData *aesKey = ... // This should be a 256 bit random key
NSData *hmacKey = ... // This should be a 256 bit random key
[crypto aeEncryptData:plaintext
symmetricKey:aesKey
hmacKey:hmacKey
completion:^(NSData *cipherData, NSData *iv, NSData *encryptionSalt, NSData *hmacSalt) {
// encryptionSalt and hmacSalt will be nil
// iv is returned but could be ignored
// Do something cipherData
}
failure:^(NSError *error) {
// Handle error
}
];
}
如果您不想生成随机密钥,则可以使用aeEncryptData:password:completion:failure:
方法使用简单的文本密码进行加密。您不需要保存encryptionSalt
和hmacSalt
,因为它们是RNCryptor数据格式的一部分。
- (void)someAuthenticatedEncryptionMethod {
IRCrypto *crypto = ...
NSData *plaintext = ...
NSString *password = ... // This can be a string of any length
[crypto aeEncryptData:plaintext
password:password
completion:^(NSData *cipherData, NSData *iv, NSData *encryptionSalt, NSData *hmacSalt) {
// iv, encryptionSalt and hmacSalt are returned but could be ignored
// Do something with cipherData *and* encryptionSalt *and* hmacSalt
}
failure:^(NSError *error) {
// Handle error
}
];
}
由于IRCryptor使用了RNCryptor文件格式,大部分解密所需的信息都已经包含在其中,IRCryptor只需要相应的解密密钥,这样就简化了保存IV和Salt的烦恼。
如果您使用默认选项,您只需使用您的密文调用aeDecryptData:completion:failure:
方法即可。
- (void)someAuthenticatedDecryptionMethod {
IRCrypto *crypto = ...
NSData *ciphertext = ...
[crypto aeDecryptData:ciphertext
completion:^(NSData *decryptedData) {
// Do something with decryptedData
}
failure:^(NSError *error) {
// Handle error
}
];
}
使用自己的密钥使用aeDecryptData:symmetricKey:hmacKey:completion:failure:
方法解密
- (void)someAuthenticatedDecryptionMethod {
IRCrypto *crypto = ...
NSData *ciphertext = ...
NSData *aesKey = ... // This should be a 256 bit random key
NSData *hmacKey = ... // This should be a 256 bit random key
[crypto aeDecryptData:ciphertext
symmetricKey:aesKey
hmacKey:hmacKey
completion:^(NSData *decryptedData) {
// Do something with decryptedData
}
failure:^(NSError *error) {
// Handle error
}
];
}
当然,您也可以使用密码通过aeDecryptData:password:completion:failure:
方法解密
- (void)someAuthenticatedDecryptionMethod {
IRCrypto *crypto = ...
NSData *ciphertext = ...
NSString *password = ... // This can be a string of any length
[crypto aeDecryptData:ciphertext
password:password
completion:^(NSData *decryptedData) {
// Do something with decryptedData
}
failure:^(NSError *error) {
// Handle error
}
];
}
IRCrypto还提供了使用CBC模式下AES进行简单加密和解密的方法。请注意,这些方法提供机密性,但无法抵抗主动攻击。此外,在采用此方法时,您需要记住保存相应的IV和Salt。
如果您使用默认选项,可以直接使用您的明文数据调用encryptData:completion:failure:
方法(记得保存返回的IV用于解密)。
- (void)someEncryptionMethod {
IRCrypto *crypto = ...
NSData *plaintext = ...
[crypto encryptData:plaintext
completion:^(NSData *cipherData, NSData *iv, NSData *salt) {
// Salt will be nil
// Do something with iv and cipherData
}
failure:^(NSError *error) {
// Handle error
}
];
}
您还可以使用自己的密钥通过encryptData:withKey:completion:failure:
方法进行加密。
- (void)someEncryptionMethod {
IRCrypto *crypto = ...
NSData *plaintext = ...
NSData *key = ... // This should be a 256 bit random key
[crypto encryptData:plaintext
withKey:key
completion:^(NSData *cipherData, NSData *iv, NSData *salt) {
// Salt will be nil
// Do something with iv and cipherData
}
failure:^(NSError *error) {
// Handle error
}
];
}
与AEAD类似,如果您不想生成随机密钥,可以使用encryptData:withPassword:completion:failure:
方法通过简单的文本密码进行加密(注意,在这种情况下,您还需要保存salt用于解密)。
- (void)someEncryptionMethod {
IRCrypto *crypto = ...
NSData *plaintext = ...
NSString *password = ... // This can be a string of any length
[crypto encryptData:plaintext
withPassword:password
completion:^(NSData *cipherData, NSData *iv, NSData *salt) {
// Note that salt will *not* be nil
// Do something with iv, cipherData *and* salt
}
failure:^(NSError *error) {
// Handle error
}
];
}
如果您使用默认选项,可以简单调用decryptData:iv:completion:failure:
方法,传入您的密文和解密时返回的iv。
- (void)someDecryptionMethod {
IRCrypto *crypto = ...
NSData *ciphertext = ...
NSData *iv = ... // The iv returned after encryption
[crypto decryptData:ciphertext
iv:iv
completion:^(NSData *decryptedData) {
// Do something with decryptedData
}
failure:^(NSError *error) {
// Handle error
}
];
}
使用您自己的密钥通过decryptData:withKey:iv:completion:failure:
方法进行解密。
- (void)someDecryptionMethod {
IRCrypto *crypto = ...
NSData *ciphertext = ...
NSData *key = ... // This should be a 256 bit random key
NSData *iv = ... // The iv returned after encryption
[crypto decryptData:ciphertext
withKey:key
iv:iv
completion:^(NSData *decryptedData) {
// Do something with decryptedData
}
failure:^(NSError *error) {
// Handle error
}
];
}
使用密码通过decryptData:withPassword:iv:salt:completion:failure:
方法进行解密。
- (void)someDecryptionMethod {
IRCrypto *crypto = ...
NSData *ciphertext = ...
NSString *password = ... // This can be a string of any length
NSData *iv = ... // The iv returned after encryption
NSData *salt = ... // The salt returned after encryption
[crypto decryptData:ciphertext
withPassword:password
iv:iv
salt:salt
completion:^(NSData *decryptedData) {
// Do something with decryptedData
}
failure:^(NSError *error) {
// Handle error
}
];
}
IRCrypto可以帮助您使用HMAC-SHA256和SHA256哈希摘要添加数据完整性。
使用HMAC进行数据完整性校验
- (void)hmacData {
IRCrypto *crypto = ...
NSData *data = ...
[crypto hmacData:data
completion:^(NSData * _Nonnull hmacData) {
//Use HMAC data
}
failure:^(NSError * _Nonnull error) {
//Use error
}];
}
使用自定义密钥的HMAC进行数据完整性校验
- (void)hmacDataWithCustomKey {
IRCrypto *crypto = ...
NSData *hmacKey = ...
NSData *data = ...
[crypto hmacData:data
withKey:hmacKey
completion:^(NSData * _Nonnull hmacData) {
//Use HMAC data
}
failure:^(NSError * _Nonnull error) {
//Use error
}];
}
使用SHA256哈希数据
- (void)hashData {
IRCrypto *crypto = ...
NSData *data = ...
NSData *digest = [crypto hashData:data]; //Use SHA256 digest
}
测试是用Objective-C编写的,使用XCTest框架,选择IRCrypto
方案,并按⌘ + u
。
想要贡献?太好了!
再次强调,这是一个学习实验,如果你发现问题或想添加更多功能,我非常乐意合并你的pull requests :)。
IRCrypto
添加数据签名功能在任意加密课程中,您首先要学习的是:绝对不要实施自己的加密,尽管我在尽可能地正确使用加密并采用所有最佳实践,这个库中可能也有一些问题。那为什么我会创建这个库呢?简短的答案是:我想学习。虽然这个库目前不打算用于实际应用中(也许在将来?),在实施它的过程中我学到了很多,我不仅理解了这些密码学概念的原理,还想通过实际代码来实验这些概念。话虽如此,如果你找到任何问题,请告诉我,我会修复它们,我们可以共同从中学习。
MIT许可(MIT)版权(c)2016伊万·罗德里格斯