代码之家  ›  专栏  ›  技术社区  ›  Janusz Daniel Rindt

用Java解密Objy-C加密的AES数据

  •  4
  • Janusz Daniel Rindt  · 技术社区  · 14 年前

    我尝试用Java中的Objtovi-C解密原始加密的数据。

    There are other questions mentioning this but they are really cluttered and many of them aren't solved yet therefore I will post my own.

    这是加密数据的代码:

      - (int) encryptWithKey: (NSString *) key
        {
        // 'key' should be 32 bytes for AES256, will be null-padded otherwise
        char * keyPtr[kCCKeySizeAES128+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];
    
        // encrypts in-place, since this is a mutable data object
        size_t numBytesEncrypted = 0;
        CCCryptorStatus result = CCCrypt( kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
                                         keyPtr, kCCKeySizeAES128,
                                         NULL /* initialization vector (optional) */, 
                                         [self mutableBytes], [self length], /* input */
                                         [self mutableBytes], [self length]+32, /* output */
                                         &numBytesEncrypted );
        return numBytesEncrypted;
    }
    

    我执行此函数,并用此代码将结果数据写入光盘:

    NSString* strTest = @"Hallo Welt!";
    NSLog(@"strTest = %@", strTest);
    
    NSMutableData *protectedData = [NSMutableData dataWithData:[strTest dataUsingEncoding:NSUTF8StringEncoding]];
    
    int laenge = [protectedData encryptWithKey:@"keykeykeykeykeykeykeykey"];
    
    NSData* dataOutput = [[NSData alloc] initWithBytes:[protectedData bytes] length:laenge];
    
    
    [dataOutput writeToFile:@"/encryptedFileObjC" atomically:YES];
    

    在Java中,我使用此代码尝试实现相同的行为:

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    String keyString = "keykeykeykeykeykeykeykey";
    byte[] keyBytes = keyString.getBytes("UTF-8");
    
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"),
            new IvParameterSpec(new byte[16]));
    byte[] resultBytes = cipher.doFinal("Hallo Welt!".getBytes("UTF8"));
    
    FileOutputStream out =
            new FileOutputStream(new File("encryptedFileJava"));
    out.write(resultBytes);
    out.close();
    

    如果我现在尝试解密通过Objective-C加密的文件,我会得到一个糟糕的填充异常。如果我打开两个加密内容的文件,它们是不同的:

    哈啰!用Java加密: 96 C5 CB 51 39 B5 27 FB B3 93 BF 92 18 BB 16 9B
    哈啰!用objc加密: A3 61 32 8E A5 E6 66 E0 41 64 89 25 62 D3 21 16

    文件内容不应该相同吗?我认为在两种语言中,算法的所有参数都不相同。

    我需要修改Java代码以获得与Objtovi-C代码相同的结果,以便能够解密用Objtovi-C加密的一些数据。

    3 回复  |  直到 14 年前
        1
  •  2
  •   Rasmus Faber    14 年前
    1. 我不认为cccrypt支持对输入和输出使用相同的数组。尝试使用两个不同的数组。
    2. 您必须自己调整输出数组的大小(numBytesEncrypted在调用后应等于16)。
    3. 据我所知,零IV信号使用ECB加密而不是CBC。只要您的输入小于15个字节,它就不会有任何区别,但它仍然是您应该解决的问题。

    编辑: 另一个问题:

    1. 您使用的是24字节密钥。AES-128需要128位=16字节的密钥,AES-192需要192位=24字节的密钥,而AES-256需要256位=32字节的密钥。您显式地将aes-128指示为cccrypt,这意味着它忽略了密钥的最后8个字节。您只是指示AES到Java,这意味着它查看密钥大小来决定使用哪种AES变体。因为您提供了一个24字节的密钥,所以它使用了AES-192。修正它,使两端使用相同的算法,你应该是好的。
        2
  •  1
  •   PaulG    14 年前

    你可能有很多问题。

    在进行任何加密/解密时,您需要确保:

    • 字符串编码是相同的(您在这两种格式中都使用了utf8,这很好)
    • 填充方案相同(一个上有pkcs5,另一个上有pkcs7)
    • 初始化向量相同(其中一个为空,另一个为空字节)

    …当然,加密方案是相同的。令人困惑的是,您的加密似乎在使用aes128,尽管评论讨论使用aes256。不确定Java版本使用的是什么

        3
  •  1
  •   JeremyP    14 年前

    这可能不会导致您的问题,但无论如何,这是错误的:

       char * keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
    

    它定义了kckeysizes128+1的数组 指针 ,而不是kckeysizes128+1字节。事实上,这是正常的,因为您得到的缓冲区比您需要的大四到八倍,这取决于您是为32位还是64位编译。