Java'da şifrelenmiş ve dart flutter'da şifre çözme

Oct 27 2020

Java ile şifrelenmiş dart içindeki bir metnin şifresini çözüyorum. İşte şifreleme için kullanılan java kodu.

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");burada şifreleme modu tanımlanmamıştır. Mod tanımlanmadığında kullandığını buldum AES/ECB/PKCS5Padding. Ayrıca şifreleme sırasında IV kullanılmaz.

Java android uygulamasını flutter'a geçiriyorum. Sunucudaki veriler yukarıdaki java kodu kullanılarak şifrelenir. Artık kullanımda olan tüm verileri sunucudan değiştiremiyorum. Verileri flutter uygulamasında göstermek için flutter'da şifresini çözmem gerekiyor.

Dartta şifre çözme için şifreleme: ^ 4.1.0 paketi kullanıyorum .

  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); 

ancak bu kod aşağıdaki gibi hata verir

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

Bunun nasıl yapılacağını bilen varsa lütfen cevabınızı yazın.

Şifreleme için kullanılan java kodunda 160 bitlik anahtar elde etmek için SHA-1 hashing algoritması kullanılır ve ardından şifreleme için ilk 128 bit kullanılır, herhangi bir soruna neden olabilir mi?

Sorunumu çözebilecek başka bir paket bilen varsa lütfen bana bildirin.

Daha fazla bilgi isteyen varsa lütfen bana bildirin.

Şimdiden teşekkürler !!

Yanıtlar

2 Topaco Oct 27 2020 at 20:10

Java kodunda, şifreli metin bir karakter kümesi kodlaması (UTF-8 gibi) kullanılarak bir dizeye dönüştürülür. Bu genellikle verileri bozar. Burada, base64 gibi bir ikiliden metne kodlama kullanılmalıdır.

Soruya gönderilen Java kodu aşağıdaki değişiklikleri sağlar:

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));
...

aşağıdaki Base64 kodlu şifreli metin:

encrypted: Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF

Bu şifreli metnin şifresi , aşağıdaki Dart kodu ile Pointy Castle paketi kullanılarak çözülebilir :

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));

Lütfen aşağıdakilere dikkat edin: ECB, güvenli olmayan bir moddur. Daha güvenli olan CBC ( dart örneği için buraya bakın ) veya GCM'dir, burada ikincisi şifrelemeye ve veri kimlik doğrulamasına izin verir. Ayrıca SHA-1 ile bir paroladan bir anahtarın türetilmesi güvenli değildir. Burada güvenilir bir anahtar türetme fonksiyonu, örneğin PBKDF2 kullanılmalıdır.

Düzenleme:
Bir şifreli metni UTF-8 gibi bir karakter kümesine sahip bir dizeye dönüştürmek verilere zarar verir. Stackoverflow'da birçok gönderi bulabilirsiniz, örneğin bu , sorunu ayrıntılı olarak açıklar. Bu , şifreli metin UTF-8 ile dönüştürülürse sorunuzda yayınlanan Java kodunun güvenilir şekilde çalışmayacağı anlamına gelir .

Ancak, verileri bozmayan ISO-8859-1 gibi karakter setleri vardır. Sunucuda böyle bir karakter setinin kullanılması mümkündür. Bu, gönderilen koddan belirlenemez, çünkü kod çözme sırasında (yani içinde new String(textencrypted)) karakter kümesi belirtilmez , bu nedenle ilgili platformun varsayılan karakter kümesi uygulanır, buraya bakın . Bu nedenle, bu olasılığı kontrol etmek için, sunucuda hangi varsayılan karakter setinin kullanıldığını belirlemeniz gerekir.
Hangi kodlamanın kullanıldığını analiz etmenin başka bir yolu, sunucu tarafından oluşturulan şifreli metnin şifresini çözmek için kullanılan kodu kontrol etmek (veya göndermek) olabilir.

En güvenilir olanı, ikili verileri bir dizeye dönüştürmeye adanmış kodlamaların kullanılmasıdır, sözde ikili metne kodlamalar, örneğin Base64, buraya bakın , bu yüzden yayınlanan örnekte Base64'ü kullandım.


Aşağıdaki Java kodu ile UTF-8 veya ISO-8859-1 kullanarak bir dönüşümün etkilerini doğrulayabilirsiniz. Yukarıda yayınlanan örnekteki veriler şifreli metin olarak kullanılır:

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);  
}

çıktıyla:

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

Ciphertext BEFORE conversion: Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF
Ciphertext AFTER conversion:  Mj48sRIlEidcVHVHIw8i8PPXUQiZB3toykI7ODbzXvbrFyOO957Euy0mzgfbVGVF

Yukarıda açıklandığı gibi, UTF-8 verileri bozar.