Objective-C 中的 AES 字符串加密

问题描述 投票:0回答:5

我的 Objective-C 应用程序需要文本/字符串加密(特别是 )。

我知道 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
}

我如何使用这些代码、这些方法?它在我的实施文件中的哪里?

objective-c encryption cryptography aes
5个回答
7
投票

顶部附近的这一行表示您正在向 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"];

解密也类似。


6
投票

因为到目前为止这似乎被忽略了:

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,但由于多种原因不推荐使用这种模式


2
投票

我使用 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


0
投票

在我上面的例子中,给定的代码不起作用。它显示有关“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;
} 

希望可以帮助别人


0
投票
+ (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 @"";
}
© www.soinside.com 2019 - 2024. All rights reserved.