1

iPhone アプリと Java サーバーソケットで AES256 対称暗号化を使用したいと考えています。現在、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 ...
    }
}
4

2 に答える 2

3

InvalidHMACExceptionは、パスワードが正しくないか、データが破損していることを意味します。

(私の Java はやや弱いですが、ここにあるドキュメントの理解は正しいと確信しています。)

あなたの問題は、あなたが使用していることだと思いますInputStreamReader。これにより、バイト ストリームから文字ストリーム (この場合は UTF-8 ストリーム) にブリッジされます。暗号文は完全にランダムなバイトであり、ほとんどの場合、不正な UTF-8 文字になります (「意味不明」なだけでなく、実際には不正でデコードできません)。bytes->utf8->bytes からのラウンドトリップ中に破損が発生することは確かに予想されます。

InputStreamReaderここではまったく使用する必要はありません。それを取り除くだけです。

于 2015-08-21T13:54:15.750 に答える
0

私は同じ問題を抱えていました.私のバージョンは65で、JNCryptorは2または3を期待しています.

baos.toByteArray() を使用しないようにしてください。

byte[] decrypted = cryptor.decryptData(baos.toByteArray(), password.toCharArray());

代わりに次を使用します。

byte[] decrypted = cryptor.decryptData(Base64.decodeBase64(baos), password.toCharArray());

お役に立てば幸いです、ディエゴ

于 2015-11-17T13:57:55.143 に答える