Dienkripsi di Java dan Mendekripsi di dart flutter

Oct 27 2020

Saya mendekripsi teks dalam dart yang dienkripsi di java. Berikut adalah kode java yang digunakan untuk enkripsi.

package aes;

import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class Aes {

    public static void main(String[] args) {
        try {

            String keyString = "1234567890123456";//length of key is 16
            Cipher desCipher = Cipher.getInstance("AES");
            byte[] key = keyString.getBytes("UTF-8");
            MessageDigest sha = MessageDigest.getInstance("SHA-1");
            key = sha.digest(key);
            key = Arrays.copyOf(key, 16); // use only first 128 bit

            SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
            desCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);

            String plainText = "abcd";

            byte[] text = plainText.getBytes("UTF-8");
            byte[] textencrypted = desCipher.doFinal(text);
            System.out.println("encrypted: " + new String(textencrypted));

        } catch (Exception ex) {
            Logger.getLogger(Aes.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}

Cipher desCipher = Cipher.getInstance("AES");di sini mode enkripsi tidak ditentukan. Saya menemukan bahwa ketika mode tidak ditentukan, ia menggunakan AES/ECB/PKCS5Padding. Juga IV tidak digunakan selama enkripsi.

Saya memigrasi aplikasi android java menjadi flutter. data di server dienkripsi menggunakan kode java di atas. Sekarang saya tidak dapat mengubah semua data yang digunakan dari server. Saya harus mendekripsinya dalam flutter untuk menampilkan data di aplikasi flutter.

Saya menggunakan encrypt: ^ 4.1.0 package untuk dekripsi di dart.

  Encrypted encryptedText = Encrypted.fromUtf8('ßȶ8)\œå7£');
  final key = Key.fromUtf8('1234567890123456');
  final iv = IV.fromLength(16);

  final encrypter = Encrypter(AES(key, mode: AESMode.ecb));

  final decrypted = encrypter.decrypt(encryptedText, iv: iv);

  print(decrypted); 

tetapi kode ini memberikan kesalahan sebagai berikut

E/flutter (18070): [ERROR:flutter/lib/ui/ui_dart_state.cc(171)] Unhandled Exception: Invalid argument(s): Input data length must be a multiple of cipher's block size
E/flutter (18070): #0      PaddedBlockCipherImpl.process (package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart:60:9)
E/flutter (18070): #1      AES.decrypt (package:encrypt/src/algorithms/aes.dart:55:22)
E/flutter (18070): #2      Encrypter.decryptBytes (package:encrypt/src/encrypter.dart:25:17)
E/flutter (18070): #3      Encrypter.decrypt (package:encrypt/src/encrypter.dart:31:17)
E/flutter (18070): #4      _MyHomePageState.sha1 (package:flutter_decrypt_video/main.dart:196:33)
E/flutter (18070): #5      _MyHomePageState.build (package:flutter_decrypt_video/main.dart:85:5)
E/flutter (18070): #6      StatefulElement.build (package:flutter/src/widgets/framework.dart:4681:28)
E/flutter (18070): #7      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4564:15)
E/flutter (18070): #8      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4737:11)
E/flutter (18070): #9      Element.rebuild (package:flutter/src/widgets/framework.dart:4280:5)
E/flutter (18070): #10     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4543:5)
E/flutter (18070): #11     StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4728:11)
E/flutter (18070): #12     ComponentElement.mount (package:flutter/src/widgets/framework.dart:4538:5)
E/flutter (18070): #13     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)
E/flutter (18070): #14     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)
E/flutter (18070): #15     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5892:14)
E/flutter (18070): #16     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)
E/flutter (18070): #17     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)
E/flutter (18070): #18     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4589:16)
E/flutter (18070): #19     Element.rebuild (package:flutter/src/widgets/framework.dart:4280:5)
E/flutter (18070): #20     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4543:5)
E/flutter (18070): #21     ComponentElement.mount (package:flutter/src/widgets/framework.dart:4538:5)
E/flutter (18070): #22     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)
E/flutter (18070): #23     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)
E/flutter (18070): #24     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5892:14)
E/flutter (18070): #25     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)
E/flutter (18070): #26     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)
E/flutter (18070): #27     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5892:14)
E/flutter (18070): #28     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)
E/flutter (18070): #29     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)
E/flutter (18070): #30     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4589:16)
E/flutter (18070): #31     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4737:11)
E/flutter (18070): #32     Element.rebuild (package:flutter/src/widgets/framework.dart:4280:5)
E/flutter (18070): #33     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4543:5)
E/flutter (18070): #34     StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4728:11)
E/flutter (18070): #35     ComponentElement.mount (package:flutter/src/widgets/framework.dart:4538:5)
E/flutter (18070): #36     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)
E/flutter (18070): #37     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)
E/flutter (18070): #38     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5892:14)
E/flutter (18070): #39     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)
E/flutter (18070): #40     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)
E/flutter (18070): #41     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:5892:14)
E/flutter (18070): #42     Element.inflateWidget (package:flutter/src/widgets/framework.dart:3508:14)
E/flutter (18070): #43     Element.updateChild (package:flutter/src/widgets/framework.dart:3266:18)
E/flutter (18070): #44     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4589:16)
E/flutter (18070): #45     StatefulElement.performRebuild (package:flutter/src/widgets/fram

Jika ada yang tahu bagaimana melakukan ini, mohon berikan jawaban Anda.

Dalam kode java yang digunakan untuk enkripsi, algoritma hashing SHA-1 digunakan untuk mendapatkan kunci 160 bit dan kemudian menggunakan 128 bit pertama untuk enkripsi, dapatkah hal itu menyebabkan masalah?

Jika ada yang tahu paket lain yang dapat menyelesaikan masalah saya, beri tahu saya.

Jika ada yang menginginkan informasi lebih lanjut, beri tahu saya.

Terima kasih sebelumnya !!

Jawaban

2 Topaco Oct 27 2020 at 20:10

Dalam kode Java, ciphertext diubah menjadi string menggunakan encoding charset (seperti UTF-8). Ini biasanya merusak data. Di sini pengkodean biner-ke-teks seperti base64 harus digunakan.

Kode Java yang diposting di pertanyaan menyediakan perubahan berikut:

import java.util.Base64;
...
Cipher desCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
...
String plainText = "The quick brown fox jumps over the lazy dog";
...
System.out.println("encrypted: " + Base64.getEncoder().encodeToString(textencrypted));
...

ciphertext yang dikodekan Base64 berikut ini:

encrypted: Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF

Ciphertext ini dapat didekripsi menggunakan paket Pointy Castle dengan kode Dart berikut:

import 'dart:convert';
import 'dart:typed_data';
import 'package:pointycastle/api.dart';
import 'package:pointycastle/block/aes_fast.dart';
import 'package:pointycastle/block/modes/ecb.dart';
import 'package:pointycastle/padded_block_cipher/padded_block_cipher_impl.dart';
import 'package:pointycastle/paddings/pkcs7.dart';
...
Digest sha1 = Digest("SHA-1");
Uint8List key = sha1.process(utf8.encode('1234567890123456')).sublist(0, 16);
Uint8List ciphertext = base64.decode('Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF');
ECBBlockCipher cipher = ECBBlockCipher(AESFastEngine());
PaddedBlockCipher paddedCipher = new PaddedBlockCipherImpl(new PKCS7Padding(), cipher);
PaddedBlockCipherParameters<CipherParameters, CipherParameters> paddingParams = new PaddedBlockCipherParameters(KeyParameter(key), null);
paddedCipher.init(false, paddingParams);
Uint8List plainText = paddedCipher.process(ciphertext);
print(utf8.decode(plainText));

Harap perhatikan hal berikut: ECB adalah mode tidak aman. Lebih aman adalah CBC (lihat di sini untuk contoh panah) atau GCM, di mana GCM memungkinkan enkripsi serta otentikasi data. Juga derivasi kunci dari kata sandi dengan SHA-1 tidak aman. Di sini fungsi derivasi kunci yang andal, misalnya PBKDF2, harus digunakan.

Edit:
Mengubah ciphertext menjadi string dengan charset seperti UTF-8 akan merusak data. Anda dapat menemukan banyak posting di Stackoverflow, misalnya yang ini , yang menjelaskan masalah secara detail. Ini berarti kode Java yang diposting di pertanyaan Anda tidak akan berfungsi dengan andal jika ciphertext diubah dengan UTF-8.

Namun, ada rangkaian karakter seperti ISO-8859-1 yang tidak merusak data. Ada kemungkinan charset seperti itu digunakan di server. Ini tidak dapat ditentukan dari kode yang diposting, karena tidak ada charset yang ditentukan selama decoding (yaitu dalam new String(textencrypted)), jadi charset default dari masing-masing platform diterapkan, lihat di sini . Oleh karena itu, untuk memeriksa kemungkinan ini, Anda harus menentukan charset default mana yang digunakan di server.
Cara lain untuk menganalisis encoding mana yang digunakan adalah dengan memeriksa (atau memposting) kode yang digunakan untuk mendekripsi ciphertext yang dibuat oleh server.

Paling andal adalah penggunaan pengkodean yang didedikasikan untuk mengubah data biner menjadi string, yang disebut pengkodean biner-ke-teks, seperti Base64, lihat di sini , itulah sebabnya saya menggunakan Base64 dalam contoh yang diposting.


Anda dapat memverifikasi efek konversi menggunakan UTF-8 atau ISO-8859-1 dengan kode Java berikut. Data dari contoh yang diposting di atas digunakan sebagai ciphertext:

convertDataWith(StandardCharsets.UTF_8);
convertDataWith(StandardCharsets.ISO_8859_1);
...
private static void convertDataWith(Charset charset) {
    String ciphertextBeforeB64 = "Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF";    // Data from posted example
    byte[] ciphertextBefore = Base64.getDecoder().decode(ciphertextBeforeB64);
    String ciphertextCharset = new String(ciphertextBefore, charset);                                   // Convert to String with specified charset
    byte[] ciphertextAfter = ciphertextCharset.getBytes(charset);                                       // Convert from String with specified charset
    String ciphertextAfterB64 = Base64.getEncoder().encodeToString(ciphertextAfter);
    System.out.println("Ciphertext BEFORE conversion: " + ciphertextBeforeB64);
    System.out.println("Ciphertext AFTER conversion:  " + ciphertextAfterB64);  
}

dengan keluaran:

Ciphertext BEFORE conversion: Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF
Ciphertext AFTER conversion:  Mj4877+9EiUSJ1xUdUcjDyLvv73vv73vv71RCO+/vQd7aO+/vUI7ODbvv71e77+977+9FyPvv73vv73vv73Euy0m77+9B++/vVRlRQ==

Ciphertext BEFORE conversion: Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF
Ciphertext AFTER conversion:  Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF

Seperti dijelaskan di atas, UTF-8 merusak data.