it-swarm-tr.com

Verilen son blok uygun şekilde doldurulmamış

Parola tabanlı şifreleme algoritması uygulamaya çalışıyorum, ancak bu istisna var:

javax.crypto.BadPaddingException: Verilen son blok gerektiği gibi yastıklı değil

Sorun ne olabilir (Java’da yeniyim.)

İşte kodum:

public class PasswordCrypter {

    private Key key;

    public PasswordCrypter(String password)  {
        try{
            KeyGenerator generator;
            generator = KeyGenerator.getInstance("DES");
            SecureRandom sec = new SecureRandom(password.getBytes());
            generator.init(sec);
            key = generator.generateKey();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public byte[] encrypt(byte[] array) throws CrypterException {
        try{
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);

            return cipher.doFinal(array);
        } catch (Exception e) { 
            e.printStackTrace();
        }
        return null;
    }

    public byte[] decrypt(byte[] array) throws CrypterException{
        try{
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, key);

            return cipher.doFinal(array);
        } catch(Exception e ){
            e.printStackTrace();
        }
        return null;
    }
}

(JUnit Testi)

public class PasswordCrypterTest {

    private static final byte[] MESSAGE = "Alpacas are awesome!".getBytes();
    private PasswordCrypter[] passwordCrypters;
    private byte[][] encryptedMessages;

    @Before
    public void setUp() {
        passwordCrypters = new PasswordCrypter[] {
            new PasswordCrypter("passwd"),
            new PasswordCrypter("passwd"),
            new PasswordCrypter("otherPasswd")
        };

        encryptedMessages = new byte[passwordCrypters.length][];
        for (int i = 0; i < passwordCrypters.length; i++) {
            encryptedMessages[i] = passwordCrypters[i].encrypt(MESSAGE);
        }
    }

    @Test
    public void testEncrypt() {
        for (byte[] encryptedMessage : encryptedMessages) {
            assertFalse(Arrays.equals(MESSAGE, encryptedMessage));
        }

        assertFalse(Arrays.equals(encryptedMessages[0], encryptedMessages[2]));
        assertFalse(Arrays.equals(encryptedMessages[1], encryptedMessages[2]));
    }

    @Test
    public void testDecrypt() {
        for (int i = 0; i < passwordCrypters.length; i++) {
            assertArrayEquals(MESSAGE, passwordCrypters[i].decrypt(encryptedMessages[i]));
        }

        assertArrayEquals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[1]));
        assertArrayEquals(MESSAGE, passwordCrypters[1].decrypt(encryptedMessages[0]));

        try {
            assertFalse(Arrays.equals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[2])));
        } catch (CrypterException e) {
            // Anything goes as long as the above statement is not true.
        }

        try {
            assertFalse(Arrays.equals(MESSAGE, passwordCrypters[2].decrypt(encryptedMessages[1])));
        } catch (CrypterException e) {
            // Anything goes as long as the above statement is not true.
        }
    }
}
93
Altrim

PKCS5-padded verilerinin şifresini yanlış anahtarla çözmeye çalışırsanız ve ardından (Cipher sınıfı tarafından otomatik olarak yapılır) paketini açarsanız, muhtemelen BadPaddingException (muhtemelen% 25.6/256'dan az,% 99.61 ile ), çünkü ped, unpad sırasında onaylanmış özel bir yapıya sahip olduğundan ve çok az sayıda tuş geçerli bir dolgu üretecektir.

Yani, eğer bu istisnayı alırsanız, yakalayın ve "yanlış anahtar" olarak kabul edin.

Bu, daha sonra anahtarı bir anahtar deposundan almak için kullanılan veya bir anahtar oluşturma işlevi kullanılarak bir anahtara dönüştürülen yanlış bir parola sağladığınızda da olabilir.

Elbette, verileriniz taşınırken bozulmuşsa hatalı dolgu da olabilir.

Bu, planınızla ilgili bazı güvenlik açıklamaları olduğunu söyledi:

  • Parola tabanlı şifreleme için, KeyGenerator ile SecureRandom kullanmak yerine bir SecretKeyFactory ve PBEKeySpec kullanmalısınız. Bunun nedeni, SecureRandom'un her Java uygulamasında farklı bir algoritma olabilmesi ve size farklı bir anahtar vermesidir. SecretKeyFactory anahtar türevini tanımlanmış bir şekilde (ve doğru algoritmayı seçerseniz güvenli olarak kabul edilen bir şekilde) yapar.

  • ECB modunu kullanmayın. Her bloğu bağımsız olarak şifreler, yani aynı düz metin blokları da her zaman aynı şifreli metin bloklarını verir.

    Tercihen CBC (Şifreli blok zincirleme) veya CTR (Sayaç) gibi güvenli bir çalışma modu kullanın. Alternatif olarak, GCM (Galois-Sayaç modu) veya CCM (CBC-MAC'li Sayaç) gibi kimlik doğrulama da içeren bir mod kullanın, bir sonraki noktaya bakın.

  • Normalde yalnızca gizlilik istememekle kalmaz, aynı zamanda iletinin tahrif edilmediğinden emin olan kimlik doğrulaması da isteyebilirsiniz. (Bu aynı zamanda şifrenizdeki seçili şifreleme saldırılarını da önler, yani gizliliğinize yardımcı olur.) Böylece, mesajınıza bir MAC (mesaj doğrulama kodu) ekleyin veya onaylama içeren bir şifre modu kullanın (önceki noktaya bakın).

  • DES, sadece 56 bit etkili bir anahtar boyutuna sahiptir. Bu anahtar alan oldukça küçük, birkaç saat içinde özel bir saldırgan tarafından kaba bir şekilde zorlanabilir. Anahtarınızı bir parola ile oluşturursanız, bu daha da hızlı olur .Ayrıca, DES sadece 64 bitlik bir blok büyüklüğüne sahiptir, bu da zincirleme modlarında daha fazla zayıflık ekler . Modern bir algoritma kullanın bunun yerine AES gibi, 128 bitlik bir blok büyüklüğüne ve anahtar boyutunun 128 bit'e (standart varyant için) sahip olması gibi.

177
Paŭlo Ebermann

kullandığınız şifreleme algoritmasına bağlı olarak, bir bayt dizisini şifrelemeden önce sonuna bir miktar doldurma baytı eklemeniz gerekebilir, böylece bayt dizisinin uzunluğu blok boyutunun katıdır:

Seçtiğiniz durumda, seçtiğiniz şema burada açıklanan PKCS5'tir: http://www.rsa.com/products/bsafe/documentation/cryptoj35html/doc/dev_guide/group_CJ _SYM__PAD.html

(Şifrelemeye çalıştığınızda sorun olduğunu farz ediyorum)

Cipher nesnesini başlattığınızda dolgu şemasını seçebilirsiniz. Desteklenen değerler, kullandığınız güvenlik sağlayıcısına bağlıdır. 

Bu arada, şifreleri şifrelemek için simetrik bir şifreleme mekanizması kullanmak istediğinize emin misiniz? Daha iyi bir yoldan olmaz mı? Şifrelerin şifresini çözebilmeniz gerçekten gerekiyorsa, DES oldukça zayıf bir çözümdür, simetrik bir algoritmayla kalmanız gerekirse, AES gibi daha güçlü bir şey kullanmak isteyebilirsiniz.

1
fpacifici

JRE uygulamasıyla ilgili olarak farklı platformlar için basit olan işletim sistemi nedeniyle bu sorunla karşılaştım. 

        new SecureRandom(key.getBytes())

linux'ta farklıyken Windows'ta da aynı değeri alacak. Yani Linux'ta değişmesi gerekiyor

        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(key.getBytes());
        kgen.init(128, secureRandom);

"SHA1PRNG", kullanılan algoritmadır, algoritmalar hakkında daha fazla bilgi için here adresine başvurabilirsiniz.

0
Bejond