我的 Objective-C 应用程序需要文本/字符串加密(特别是 nsstring)。
我知道 AES 是可供消费者使用的最安全的加密方法。我还了解如何将字符串转换为数据并返回...(只是初学者)。
许多关于 AES 加密的网页和 Q/As 都不清楚,并且没有一个说明如何使用给定的代码。例如,网页可能会说:“这是代码……这是它的作用……”但没有解释如何使用它。
我通过大量研究找到了这段代码:
#import "<CommonCrypto/CommonCryptor.h>"
@implementation NSMutableData(AES)
对于加密:
- (NSMutableData*) EncryptAES:(NSString *)key {
char keyPtr[kCCKeySizeAES256+1];
bzero( keyPtr, sizeof(keyPtr) );
[key getCString: keyPtr maxLength: sizeof(keyPtr) encoding: NSUTF16StringEncoding];
size_t numBytesEncrypted = 0;
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
NSMutableData *output = [[NSData alloc] init];
CCCryptorStatus result = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES256, NULL, [self mutableBytes], [self length], buffer, bufferSize, &numBytesEncrypted);
output = [NSMutableData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
if(result == kCCSuccess) {
return output;
}
return NULL;
}
解密:
- (NSMutableData*)DecryptAES: (NSString*)key andForData:(NSMutableData*)objEncryptedData {
char keyPtr[kCCKeySizeAES256+1];
bzero( keyPtr, sizeof(keyPtr) );
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF16StringEncoding];
size_t numBytesEncrypted = 0;
NSUInteger dataLength = [self length];
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer_decrypt = malloc(bufferSize);
NSMutableData *output_decrypt = [[NSData alloc] init];
CCCryptorStatus result = CCCrypt(kCCDecrypt , kCCAlgorithmAES128, kCCOptionPKCS7Padding, keyPtr, kCCKeySizeAES256, NULL, [self mutableBytes], [self length], buffer_decrypt, bufferSize, &numBytesEncrypted);
output_decrypt = [NSMutableData dataWithBytesNoCopy:buffer_decrypt length:numBytesEncrypted];
if(result == kCCSuccess) {
return output_decrypt;
}
return NULL;
}
}
这是我制作的代码,我想与上面的代码相对应:
- (void)Encrypt {
//Convert NSString to NSData so that it can be used to encrypt the Input
NSString *Input = [Inputbox text];
NSData *InputData = [Input dataUsingEncoding:NSUTF8StringEncoding];
//What to do here
}
我如何使用这些代码、这些方法?它在我的实施文件中的哪里?
顶部附近的这一行表示您正在向 NSMutableData 添加 AES 功能:
@implementation NSMutableData(AES)
在 Objective-C 中,这称为类别;类别让您可以扩展现有的类。
此代码通常位于名为 NSMutableData-AES.m 的文件中。还创建一个头文件 NSMutableData-AES.h。它应该包含:
@interface NSMutableData(AES)
- (NSMutableData*) EncryptAES: (NSString *) key;
@end
在主文件中包含(#import)该标头。在代码中添加对加密函数的调用:
NSData *InputData = [Input dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [InputData EncryptAES:@"myencryptionkey"];
解密也类似。
因为到目前为止这似乎被忽略了:
CCCryptorStatus result = CCCrypt( kCCDecrypt , kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES256,
**NULL**,
[self mutableBytes], [self length],
buffer_decrypt, bufferSize,
&numBytesEncrypted );
来自头文件CommonCrypto/CommonCryptor.h:
@param iv 初始化向量,可选。使用者 密码块链接 (CBC) 时的块密码 模式已启用。如果存在,则必须相同 length 作为所选算法的块大小。 如果选择 CBC 模式(由于没有 选项标志中的 kCCOptionECBMode 位)并且没有 IV 存在,将使用 NULL(全零)IV。 如果使用 ECB 模式或 如果选择流密码算法。
粗体的 NULL 对应于 IV。遗憾的是,无论是谁设计了该 API,都将其设为可选。这使得这种 CBC 模式本质上等同于 ECB,但由于多种原因不推荐使用这种模式。
我使用 AES 并使用以下代码取得了成功:
头文件
#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCryptor.h>
NS_ASSUME_NONNULL_BEGIN
@interface SecurityUtils : NSObject
+ (NSString *)encrypt:(NSString *)plainText error:(NSError **)error;
+ (NSString *)decrypt:(NSString *)plainText error:(NSError **)error;
@end
NS_ASSUME_NONNULL_END
实施文件
NSString *const IV = @"AEE0515D0B08A4E4";
NSString *const KEY = @"9336565521E5F082BB5929E8E033BC69";
#import "SecurityUtils.h"
@implementation SecurityUtils
+ (NSString *)encrypt:(NSString *)plainText error:(NSError **)error {
NSMutableData *result = [SecurityUtils doAES:[plainText dataUsingEncoding:NSUTF8StringEncoding] context: kCCEncrypt error:error];
return [result base64EncodedStringWithOptions:0];
}
+ (NSString *)decrypt:(NSString *)encryptedBase64String error:(NSError **)error {
NSData *dataToDecrypt = [[NSData alloc] initWithBase64EncodedString:encryptedBase64String options:0];
NSMutableData *result = [SecurityUtils doAES:dataToDecrypt context: kCCDecrypt error:error];
return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
+ (NSMutableData *)doAES:(NSData *)dataIn context:(CCOperation)kCCEncrypt_or_kCCDecrypt error:(NSError **)error {
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCBlockSizeBlowfish];
NSData *key =[KEY dataUsingEncoding:NSUTF8StringEncoding];
NSData *iv = [IV dataUsingEncoding:NSUTF8StringEncoding];
ccStatus = CCCrypt( kCCEncrypt_or_kCCDecrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
key.bytes,
key.length,
(iv)?nil:iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus == kCCSuccess) {
dataOut.length = cryptBytes;
}
else {
if (error) {
*error = [NSError errorWithDomain:@"kEncryptionError"
code:ccStatus
userInfo:nil];
}
dataOut = nil;
}
return dataOut;
}
@end
IOS测试
NSError *error;
NSString *encrypted = [SecurityUtils encrypt:@"My Secret Text" error:&error];
NSLog(@"encrypted: %@",encrypted);
NSLog(@"decrypted: %@",[SecurityUtils decrypt:encrypted error:&error]);
最后,测试输出:
IOS 输出
2019-05-16 21:38:02.947043-0300 MyApp[63392:1590665] encrypted: EJ41am5W1k6fA7ygFjTSEw==
2019-05-16 21:38:02.947270-0300 MyApp[63392:1590665] decrypted: My Secret Text
我在 github 上的存储库包含以下示例:https://github.com/juliancorrea/aes-crypto-android-and-ios
在我上面的例子中,给定的代码不起作用。它显示有关“kCCBufferTooSmall errorCode = -4301”的错误。 我必须稍微改变一下,如果上面的代码不起作用,请尝试一下
+ (NSMutableData *)doAES:(NSData *)dataIn context:(CCOperation)kCCEncrypt_or_kCCDecrypt error:(NSError **)error {
CCCryptorStatus ccStatus = kCCSuccess;
size_t cryptBytes = 0;
NSMutableData *dataOut = [NSMutableData dataWithLength:dataIn.length + kCCKeySizeAES256];
NSData *key =[encryptionNewKey dataUsingEncoding:NSUTF8StringEncoding];
NSData *iv = [encryptionIV dataUsingEncoding:NSUTF8StringEncoding];
ccStatus = CCCrypt( kCCEncrypt_or_kCCDecrypt,
kCCAlgorithmAES,
kCCOptionPKCS7Padding,
key.bytes,
kCCKeySizeAES256,
iv.bytes,
dataIn.bytes,
dataIn.length,
dataOut.mutableBytes,
dataOut.length,
&cryptBytes);
if (ccStatus == kCCSuccess) {
dataOut.length = cryptBytes;
}
else {
if (error) {
*error = [NSError errorWithDomain:@"kEncryptionError"
code:ccStatus
userInfo:nil];
}
dataOut = nil;
}
return dataOut;
}
希望可以帮助别人
+ (NSString*)encryptFileAtPath:(NSString *)inputFilePath outputPath:(NSString *)outputFilePath password:(NSString *)password {
// Convert the URL to a local file path
// Use the converted local file path to read the input data
NSData *inputData = [NSData dataWithContentsOfFile:inputFilePath];
if (!inputData) {
NSLog(@"Failed to read input file.");
return @"";
}
// Generate the key and IV from the password using PBKDF2 (same as in encryption)
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
NSMutableData *keyData = [NSMutableData dataWithLength:kCCKeySizeAES256];
NSMutableData *ivData = [NSMutableData dataWithLength:kCCBlockSizeAES128];
// Use the same salt and rounds as in encryption
const char myByteArray[] = {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
NSData *salt = [NSData dataWithBytes:myByteArray length:32];
unsigned int rounds = 50000;
CCKeyDerivationPBKDF(kCCPBKDF2, passwordData.bytes, passwordData.length, [salt bytes], [salt length], 0, rounds, keyData.mutableBytes, keyData.length);
// Set up the decryption context with CBC mode
CCCryptorRef cryptor;
CCCryptorStatus status = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionPKCS7Padding | kCCOptionECBMode,
keyData.bytes, keyData.length, ivData.bytes, &cryptor);
if (status == kCCSuccess) {
NSMutableData *outputData = [NSMutableData dataWithLength:inputData.length + kCCBlockSizeAES128];
size_t encryptedLength;
// Perform encryption
status = CCCryptorUpdate(cryptor, inputData.bytes, inputData.length, outputData.mutableBytes, outputData.length, &encryptedLength);
if (status == kCCSuccess) {
// Finalize encryption
size_t finalLength;
status = CCCryptorFinal(cryptor, outputData.mutableBytes + encryptedLength, outputData.length - encryptedLength, &finalLength);
// [outputData setLength:encryptedLength + finalLength];
if (status == kCCSuccess) {
// Write encrypted data to the output file
NSString *outputFileName = [inputFilePath lastPathComponent];
NSURL *outPath = [NSURL URLWithString:outputFilePath];
NSString *trimmedFilePaths = [outPath.absoluteString containsString:@"file://"] == YES? [outPath.absoluteString stringByReplacingOccurrencesOfString:@"file://" withString:@""]: outPath.absoluteString;
NSString *trimmedD = [trimmedFilePaths containsString:@"%20"] == YES? [trimmedFilePaths stringByReplacingOccurrencesOfString:@"%20" withString:@" "]: trimmedFilePaths;
NSString *outputFileSPath = [trimmedD stringByAppendingPathComponent:outputFileName];
[outputData writeToFile:outputFileSPath atomically:YES];
NSLog(@"File encrypted successfully: %@", outputFilePath);
return outputFileSPath;
} else {
NSLog(@"Encryption finalization error: %d", status);
}
} else {
NSLog(@"Encryption update error: %d", status);
}
CCCryptorRelease(cryptor);
} else {
NSLog(@"Cryptor creation error: %d", status);
}
return @"";
}