EXC_BAD_ACCESS CCCrypt 上的代码 2

EXC_BAD_ACCESS Code 2 on CCCrypt

我正在尝试使用 DES 加密来加密密码(不要问为什么使用 DES,我知道它不太安全)。我是在 iOS 中第一次这样做,因此不得不依赖另一个 post 来了解如何做。

当我运行加密的时候returnsnull,和解密一个已经加密的字符串一样(我是用在线工具加密的)。当我设置断点以查看发生了什么时,它停在 CCCrypt 处提到 EXC_BAD_ACCESS (Code 2)

我尝试使用不同的 CCOptions,但它 returns 总是一样。 任何提示出了什么问题?是否需要 iv 字符串?

我使用了以下 NSString 类别来加密或解密字符串 -

#import "NSString+DES.h"

@implementation NSString(DES)

- (NSString*) encryptDES: (NSString *) key
{
    const void *vplainText;
    size_t plainTextBufferSize;

    plainTextBufferSize = [self length];
    vplainText = (const void *) [self UTF8String];

    CCCryptorStatus ccStatus;
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t *movedBytes;

    bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
    memset((void *)bufferPtr, 0x0, bufferPtrSize);
    // memset((void *) iv, 0x0, (size_t) sizeof(iv));


    //NSString *initVec = @"init Vec";
    const void *vkey = (const void *) [key UTF8String];
    //const void *vinitVec = (const void *) [initVec UTF8String];

    ccStatus = CCCrypt(kCCEncrypt,
                       kCCAlgorithmDES,
                       kCCOptionPKCS7Padding | kCCOptionECBMode,
                       vkey,
                       kCCKeySizeDES,
                       NULL,
                       vplainText,
                       plainTextBufferSize,
                       (void *)bufferPtr,
                       bufferPtrSize,
                       movedBytes);

    NSString *result;
    NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
    result = [myData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    return result;
}

- (NSString *) decryptDES: (NSString *) key
{
    const void *vplainText;
    size_t plainTextBufferSize;

    plainTextBufferSize = [self length];
    vplainText = (const void *) [self UTF8String];

    CCCryptorStatus ccStatus;
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t *movedBytes;

    bufferPtrSize = (plainTextBufferSize + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
    memset((void *)bufferPtr, 0x0, bufferPtrSize);
    // memset((void *) iv, 0x0, (size_t) sizeof(iv));


    //NSString *initVec = @"init Vec";
    const void *vkey = (const void *) [key UTF8String];
    //const void *vinitVec = (const void *) [initVec UTF8String];

    ccStatus = CCCrypt(kCCDecrypt,
                       kCCAlgorithmDES,
                       kCCOptionPKCS7Padding | kCCOptionECBMode,
                       vkey, //"123456789012345678901234", //key
                       kCCKeySizeDES,
                       NULL,// vinitVec, //"init Vec", //iv,
                       vplainText, //"Your Name", //plainText,
                       plainTextBufferSize,
                       (void *)bufferPtr,
                       bufferPtrSize,
                       movedBytes);

    NSString *result;
    NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
    result = [myData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
    return result;
}

@end

更新:

我又检查了几个地方并稍微更改了代码,加密有效但没有用正确的值解密。

例如当我使用YourName作为字符串和12345作为密钥时,我得到Fu2sK61e7l5rkXRhAKjPWA==作为加密代码,但是解密returns+54qWCYTB5LkdARDZjAow== 而不是 YourName.

更新代码:

#import "NSString+DES.h"

@implementation NSString(DES)

- (NSString*) encryptDES: (NSString *) key
{
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *stringData = [self dataUsingEncoding:NSUTF8StringEncoding];
    size_t numBytesEncrypted = 0;
    size_t bufferSize = stringData.length + kCCBlockSizeDES;
    void *buffer = malloc(bufferSize);

    CCCryptorStatus result = CCCrypt( kCCEncrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding,
                                     keyData.bytes, kCCKeySizeDES,
                                     NULL,
                                     stringData.bytes, stringData.length,
                                     buffer, bufferSize,
                                     &numBytesEncrypted);
    NSData *output = [NSData dataWithBytes:buffer length:numBytesEncrypted];
    free(buffer);
    if( result == kCCSuccess )
    {
        NSString *resultStr = [output base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
        return resultStr;
    } else {
        NSLog(@"Failed DES encrypt...");
        return nil;
    }

}

- (NSString *) decryptDES: (NSString *) key
{
    NSData *keyData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *stringData = [[NSData alloc] initWithBase64EncodedString:self options:0];

    size_t numBytesEncrypted = 0;
    size_t bufferSize = stringData.length + kCCBlockSizeDES;
    void *buffer = malloc(bufferSize);

    CCCryptorStatus result = CCCrypt( kCCDecrypt, kCCAlgorithmDES, kCCOptionPKCS7Padding,
                                     keyData.bytes, kCCKeySizeDES,
                                     NULL,
                                     stringData.bytes, stringData.length,
                                     buffer, bufferSize,
                                     &numBytesEncrypted);
    NSData *output = [NSData dataWithBytes:buffer length:numBytesEncrypted];
    free(buffer);
    if( result == kCCSuccess )
    {
        NSString *resultStr = [output base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
        return resultStr;
    } else {
        NSLog(@"Failed DES decrypt...");
        return nil;
    }
}

@end

似乎普遍混淆了算法,DES 或 3DES,混合使用但密钥是 3DES(24 字节)。密钥需要更改为 8 字节。块大小常量也应更改为 kCCBlockSizeDES 但这不会导致错误,因为它是相同的值。

对于方法:

- (NSString *) decryptDES: (NSString *) key

访问错误错误是因为没有为movedBytes分配存储空间,只是一个指针。将声明更改为:

size_t movedBytes;

CCCrypt 中对 movedBytes 的引用更改为 &movedBytes

加密测试输出:

string: "Your Name"
key: "12345678"

movedBytes: 16
myData: 136142f6 6cd98e01 af1eef46 28d36499
result: E2FC9mzZjgGvHu9GKNNkmQ==

根据要求从评论中注释:

ECB 模式不使用 iv。

对于DES,密钥需要恰好是8字节,如果太短,结果将是不确定的。在更新后的代码中,密钥为 5 个字节,但长度为 8 个字节 (kCCKeySizeDES),因此缺少的三个密钥字节将是 keyData.

之后的任何字节

更新的答案没有指定ECB模式,默认是CBC模式。添加 kCCOptionECBMode.

在解密时不要使用Base64编码,将数据转换成NSString:

NSString * resultStr = [[NSString alloc] initWithData:output encoding:NSUTF8StringEncoding];  

如果使用使用 php mcrypt 函数的在线加密,数据的最后一个块将不正确,因为 mcrypt 不支持 PKCS#7 填充,它使用非标准和不安全的空填充。