java - 为什么 JNCryptor/RNCryptor 库会抛出 InvalidHMACException?

标签 java ios encryption rncryptor jncryptor

我想使用 AES256 对称加密我的 iPhone 应用程序和我的 Java 服务器套接字。我目前正在使用 Rob Napier 的 RNCryptor/JNCryptor 库。 iPhone 上的加密似乎运行良好,因为我能够再次解密加密的字符串。但是,一旦我尝试在我的 Java 服务器套接字上解密字符串,就会抛出以下异常:

com.acme.crypto.InvalidHMACException: Incorrect HMAC value.
    at com.acme.crypto.AES256JNCryptor.decryptV3Data(AES256JNCryptor.java:248)
    at com.acme.crypto.AES256JNCryptor.decryptV3Data(AES256JNCryptor.java:323)
    at com.acme.crypto.AES256JNCryptor.decryptData(AES256JNCryptor.java:280)

com.acme.crypto.CryptorException: Unrecognised version number: 61.
    at com.acme.crypto.AES256JNCryptor.decryptData(AES256JNCryptor.java:283)

以下是用于发送加密数据的相关客户端代码片段 (iOS/Objective-C):

 // add line break and send message to server
 NSString* message = [NSString stringWithFormat:@"%@\n", output];
 NSData* data = [[NSData alloc] initWithData:[message dataUsingEncoding:NSUTF8StringEncoding 
                                                   allowLossyConversion:NO]];
 // encrypt outgoing data with AES-256
 NSError *error1;
 NSData *cypher = [RNEncryptor encryptData:data
                              withSettings:kRNCryptorAES256Settings
                                  password:@"mypassword"
                                     error:&error1];
 // write encrypted data to output stream
 if (error1==nil) {
     NSInteger result = [outputStream write:[cypher bytes] maxLength:[cypher length]];
 } else {
     NSLog(@"Encryption of outgoing data failed: %@", error1);
 }

这是在其套接字上接收加密数据的相应服务器代码 (Linux/Java):

// initializing cryptor object during object construction
JNCryptor cryptor = new AES256JNCryptor();

// setting up the input stream on the server socket
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));

// this is within the client thread ...

String line;
while((line=input.readLine())!=null) {
    try {
        // ... the exception is thrown at the following line  ...
        byte[] decrypted = cryptor.decryptData(line.getBytes(), password.toCharArray());
        line = new String(decrypted, StandardCharsets.UTF_8);
        // message handling ...
    } catch (Exception ex) {
        // print exception ...
    }
 }

有人知道我做错了什么吗?在发送数据之前我是否必须使用 Base64 或类似的编码?非常感谢任何帮助。

编辑:这是解决方案。我现在不使用基于字符的输入流,而是直接使用来自套接字的 InputStream 来读取原始字节以提供给解密算法:

@Override
public void run() {
    try {
        int bytes;
        byte[] buffer = new byte[4096];
        while((bytes=input.read(buffer))!=-1) {
            try {
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                baos.write(buffer, 0, bytes);
                byte[] decrypted = cryptor.decryptData(baos.toByteArray(), password.toCharArray());
                String line = new String(decrypted, StandardCharsets.UTF_8);
                // handle input ...
            } catch (Exception ex) {
                // handle exception ...
            }
        }
    } catch (Exception ex) {
        // handle exception ...
    }
}

最佳答案

InvalidHMACException 表示您的密码不正确或您的数据已损坏。

(我的 Java 有点弱,但我相当确定我对此处文档的理解是正确的。)

我怀疑您的问题是您正在使用 InputStreamReader。这从字节流桥接到字符流(在你的例子中是 UTF-8 流)。密文是完全随机的字节,在大多数情况下是非法的 UTF-8 字符(不仅是“乱码”,而且实际上是非法的且不可解码)。我当然希望在 bytes->utf8->bytes 的往返过程中出现损坏。

您根本不需要在这里使用 InputStreamReader。摆脱它。

关于java - 为什么 JNCryptor/RNCryptor 库会抛出 InvalidHMACException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32116108/

相关文章:

java - 将文件的内容复制到同一个文件

java - 为什么我不能使用 Scanner(System.in) 读取整行和 double?

ios - Storyboard因 Xcode 7/Swift 2 错误而崩溃 - 由于缺少入口点而无法访问场景

mysql - 调用 native 函数时参数计数不正确 'aes_decrypt'

java - Eclipse 4.5 Java 格式化程序已更改

java - 如何合并两个 HashMap 并对相同键的值求和?

ios - Swift 中 XCode 中的计算器布局困难

php - 从网站获取数据到 iPhone 应用程序

jakarta-ee - 如何使用 JWE 生成 JWT/JWS

c++ - gcrypt 是针对哪个版本的 PKCS#1 规范实现的?