有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

使用PKCS7Padding的AES CBC加密在Java和Objective中有不同的结果

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

目的-C结果:U7FAVHi01q0Hhf+m9NsKjw==


共 (3) 个答案

  1. # 1 楼答案

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

    IvParameterSpec ivSpec = new IvParameterSpec(keyBytes);
    

    在目标C中,IV参数设置为空:

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

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

  2. # 2 楼答案

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

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

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

    输出:

    iv: 8617dcf92de01ac2c0b92763b206b3f5

  3. # 3 楼答案

    您的问题在于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