【问题标题】:AES CBC Encryption With PKCS7Padding Has Different Results In Java And Objective-C使用 PKCS7Padding 的 AES CBC 加密在 Java 和 Objective-C 中具有不同的结果
【发布时间】:2016-05-27 07:41:37
【问题描述】:

我用 Java 为 Android 创建了一个应用程序,并使用 Cipher 类使用 AES 加密数据。现在我想用CommonCrypto 类将该算法带入iOS。代码有效,但结果不同。

这是 Java 中的代码:

public static String Decrypt(String text, String key) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    byte[] keyBytes = new byte[16];
    byte[] b = key.getBytes("UTF-8");
    int len = b.length;
    if (len > keyBytes.length)
        len = keyBytes.length;
    System.arraycopy(b, 0, keyBytes, 0, len);
    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
    cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
    byte[] results = new byte[text.length()];
    BASE64Decoder decoder = new BASE64Decoder();
    try {
        results = cipher.doFinal(decoder.decodeBuffer(text));
    } catch (Exception e) {
        System.out.print("Erron in Decryption");
    }
    return new String(results, "UTF-8");
}

public static String Encrypt(String text, String key) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    byte[] keyBytes = new byte[16];
    byte[] b = key.getBytes("UTF-8");
    int len = b.length;
    if (len > keyBytes.length)
        len = keyBytes.length;
    System.arraycopy(b, 0, keyBytes, 0, len);
    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
    IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
    System.out.println(keyBytes);
    System.out.println(keySpec);
    System.out.println(ivSpec);
    cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);

    byte[] results = cipher.doFinal(text.getBytes("UTF-8"));
    BASE64Encoder encoder = new BASE64Encoder();
    return encoder.encode(results);
}

这是Objective-C中的代码:

+ (NSString*)AES256EncryptData:(NSString*)data WithKey:(NSString*)key {
    char keyPtr[kCCKeySizeAES128]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = data.length;

    size_t bufferSize           = dataLength + kCCBlockSizeAES128;
    void* buffer                = malloc(bufferSize);

    size_t numBytesEncrypted    = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          data.UTF8String, dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesEncrypted);

    if (cryptStatus == kCCSuccess) {
        return [[NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted] base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];
    }

    free(buffer); //free the buffer;
    return nil;
}

+ (NSString*)AES256DecryptData:(NSString*)data WithKey:(NSString*)key {
    char keyPtr[kCCKeySizeAES256 + 1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = data.length;

    size_t bufferSize           = dataLength + kCCBlockSizeAES128;
    void* buffer                = malloc(bufferSize);

    size_t numBytesDecrypted    = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                          keyPtr, kCCKeySizeAES256,
                                          NULL /* initialization vector (optional) */,
                                          data.UTF8String, dataLength, /* input */
                                          buffer, bufferSize, /* output */
                                          &numBytesDecrypted);

    if (cryptStatus == kCCSuccess) {
        return [[NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted] base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];
    }

    free(buffer); //free the buffer;
    return nil;
}

更新 1:

数据:text to encrypt

密钥:testkey

Java (需要) 结果:7ptTEyImNz9KgC96+JPFXQ==

Objective-C 结果:U7FAVHi01q0Hhf+m9NsKjw==

【问题讨论】:

  • 请发布结果和想要的结果。
  • @JulienLopez 使用示例数据编辑帖子
  • 上面的超级不安全的代码。永远不要将您的密钥或其任何部分用作 IV,永远。

标签: java objective-c encryption aes cbc-mode


【解决方案1】:

您的问题在于 Objective-C 代码。您应该在 Java 和 Obj-C 中使用相同的方法。您可以使用此代码以使其返回相同的结果:

AES.h

#import <Foundation/Foundation.h>
#import <CommonCrypto/CommonCrypto.h>

@interface AES : NSObject 

+ (NSData *)Encrypt:(NSString *)data WithKey:(NSString *)key;
+ (NSString *)Decrypt:(NSData *)data WithKey:(NSString *)key;

+ (NSData *)AESOperation:(CCOperation)operation OnData:(NSData *)data key:(NSString *)key;

@end

AES.m

#import "AES.h"

@implementation AES

+ (NSData *)Encrypt:(NSString *)data WithKey:(NSString *)key {
    return [self AESOperation:kCCEncrypt OnData:[data dataUsingEncoding:NSUTF8StringEncoding] key:key];
}
+ (NSString *)Decrypt:(NSData *)data WithKey:(NSString *)key {
    return [[NSString alloc] initWithData:[self AESOperation:kCCDecrypt OnData:data key:key] encoding:NSUTF8StringEncoding];
}

+ (NSData *)AESOperation:(CCOperation)operation OnData:(NSData *)data key:(NSString *)key {
    char keyPtr[kCCKeySizeAES128];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [data length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(operation,
                                          kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kCCBlockSizeAES128,
                                          keyPtr,
                                          [data bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer);
    return nil;
}

@end

【讨论】:

  • 不要使用 iv 的密钥,它们需要不同,并且每个加密的 iv 应该不同。 iv 不需要保密。
  • @zaph 我同意这一点,但在这里,我刚刚为他翻译了 java 代码
  • @zaph 您可能需要检查两种语言的填充大小。并检查你的静脉注射。这些是最重要的因素。在我的情况下, key 和 iv 是相同的。但这不是正确的方法
【解决方案2】:

在 java 代码中,您使用的是 IV 参数:

IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);

在Objective C中,IV参数设置为NULL:

CCCrypt(..,   NULL /* initialization vector (optional) */,

除此之外,IV 参数应该是一些随机值,而不是您的密钥(或其中的一部分)。这个想法是输出不同的密码文本并防止块模式匹配

【讨论】:

  • 我怎样才能在 Obj-C 中拥有那个 IV?抱歉,我是密码学新手
  • 在 Internet 或 stackoverflow 上有很多示例(即stackoverflow.com/questions/36229572/…)。如果您想在 ObjectiveC 和 java 中获得相同的结果,则需要应用相同的逻辑来获得您的 IV。但是,如前所述,最好保持 IV 随机
【解决方案3】:

您需要在 ObjC 代码中添加一个 iv,而不是 NULL。

不要使用 iv 的密钥,而是创建一个随机字节的 iv,将其添加到加密数据以用于解密。在 ObjC 中,您可以使用 SecRandomCopyBytes 创建一个随机 iv:

uint8_t iv[kCCBlockSizeAES128];
SecRandomCopyBytes(kSecRandomDefault, kCCBlockSizeAES128, iv);

输出:

iv: 8617dcf92de01ac2c0b92763b206b3f5

【讨论】:

    猜你喜欢
    • 2019-04-07
    • 2016-08-21
    • 2012-06-06
    • 2018-10-08
    • 2015-05-27
    • 2014-08-20
    • 1970-01-01
    • 2014-01-27
    • 2014-01-13
    相关资源
    最近更新 更多