अंतिम ब्लॉक को देखते हुए ठीक से गद्देदार नहीं


115

मैं पासवर्ड आधारित एन्क्रिप्शन एल्गोरिथ्म को लागू करने की कोशिश कर रहा हूं, लेकिन मुझे यह अपवाद मिलता है:

javax.crypto.BadPaddingException: अंतिम ब्लॉक को ठीक से गद्देदार नहीं दिया गया

क्या समस्या हो सकती है?

यहाँ मेरा कोड है:

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

(द ज्यूनिट टेस्ट)

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.
        }
    }
}

जवाबों:


197

यदि आप गलत कुंजी के साथ PKCS5- गद्देदार डेटा को डिक्रिप्ट करने की कोशिश करते हैं, और फिर इसे अनपैड (जो कि सिफर क्लास द्वारा स्वचालित रूप से किया जाता है), तो आप सबसे अधिक संभावना BadPaddingException (255/256 से थोड़ा कम, लगभग 99.61% के साथ) प्राप्त करेंगे। ), क्योंकि पैडिंग में एक विशेष संरचना होती है जिसे अनपेड के दौरान मान्य किया जाता है और बहुत कम चाबियाँ वैध पैडिंग का उत्पादन करती हैं।

इसलिए, यदि आपको यह अपवाद मिलता है, तो इसे पकड़ें और इसे "गलत कुंजी" मानें।

यह तब भी हो सकता है जब आप एक गलत पासवर्ड प्रदान करते हैं, जो तब कीस्टोर से कुंजी प्राप्त करने के लिए उपयोग किया जाता है, या जिसे कुंजी पीढ़ी फ़ंक्शन का उपयोग करके कुंजी में परिवर्तित किया जाता है।

यदि आपका डेटा ट्रांसपोर्ट में दूषित है, तो निश्चित रूप से खराब पैडिंग भी हो सकती है।

कहा कि, आपकी योजना के बारे में कुछ सुरक्षा टिप्पणियां हैं:

  • पासवर्ड-आधारित एन्क्रिप्शन के लिए, आपको KeyGenerator के साथ SecureRandom का उपयोग करने के बजाय एक SecretKeyFactory और PBEKeySpec का उपयोग करना चाहिए। कारण यह है कि SecureRandom प्रत्येक जावा कार्यान्वयन पर एक अलग एल्गोरिथ्म हो सकता है, जिससे आपको एक अलग कुंजी मिल जाएगी। SecretKeyFactory एक परिभाषित तरीके से कुंजी व्युत्पत्ति करता है (और एक तरीका जिसे सुरक्षित माना जाता है, यदि आप सही एल्गोरिदम का चयन करते हैं)।

  • ईसीबी-मोड का उपयोग न करें। यह प्रत्येक ब्लॉक को स्वतंत्र रूप से एन्क्रिप्ट करता है, जिसका अर्थ है कि समान सादे पाठ ब्लॉक भी हमेशा समान सिफरटेक्स्ट ब्लॉक देते हैं।

    अधिमानतः ऑपरेशन के सुरक्षित मोड का उपयोग करें सीबीसी (सिफर ब्लॉक चेनिंग) या सीटीआर (काउंटर) जैसे । वैकल्पिक रूप से, एक मोड का उपयोग करें जिसमें प्रमाणीकरण भी शामिल है, जैसे जीसीएम (गैल्विस-काउंटर मोड) या सीसीएम (सीबीसी-मैक के साथ काउंटर), अगला बिंदु देखें।

  • आप आम तौर पर केवल गोपनीयता नहीं चाहते हैं, लेकिन यह भी प्रमाणीकरण है, जो यह सुनिश्चित करता है कि संदेश के साथ छेड़छाड़ नहीं की गई है। (यह आपके सिफर पर चुने गए सिफरटेक्स्ट हमलों को भी रोकता है, यानी गोपनीयता के लिए मदद करता है।) इसलिए, अपने संदेश में एक मैक (संदेश प्रमाणीकरण कोड) जोड़ें, या एक सिफर मोड का उपयोग करें जिसमें प्रमाणीकरण शामिल है (पिछले बिंदु देखें)।

  • DES में केवल 56 बिट्स का एक प्रभावी कुंजी है। यह प्रमुख स्थान काफी छोटा है, यह समर्पित हमलावर द्वारा कुछ घंटों में क्रूरतापूर्ण हो सकता है। यदि आप पासवर्ड द्वारा अपनी कुंजी बनाते हैं, तो यह और भी तेज़ हो जाएगा। इसके अलावा, DES में केवल 64 बिट्स का एक ब्लॉक आकार है, जो कि चेनिंग मोड में कुछ और कमजोरियों को जोड़ता है। इसके बजाय एईएस जैसे आधुनिक एल्गोरिदम का उपयोग करें, जिसमें 128 बिट्स का एक ब्लॉक आकार और 128 बिट्स का एक महत्वपूर्ण आकार (मानक संस्करण के लिए) है।


1
मैं सिर्फ पुष्टि करना चाहता हूं। मैं एन्क्रिप्शन के लिए नया हूं और यह मेरा परिदृश्य है, मैं एईएस एन्क्रिप्शन का उपयोग कर रहा हूं। मेरे एन्क्रिप्ट / डिक्रिप्ट फ़ंक्शन में, मैं एक एन्क्रिप्शन कुंजी का उपयोग कर रहा हूं। मैंने डिक्रिप्ट में एक गलत एन्क्रिप्शन कुंजी का उपयोग किया और मुझे यह मिला javax.crypto.BadPaddingException: Given final block not properly padded। क्या मुझे इसे एक गलत कुंजी के रूप में मानना ​​चाहिए?
kenicky

बस स्पष्ट होने के लिए, यह एक कुंजी स्टोर फ़ाइल के लिए गलत पासवर्ड प्रदान करते समय भी हो सकता है, जैसे कि .p12 फ़ाइल, जो कि अभी मेरे साथ हुआ है।
वारेन ड्यू

2
@WarrenDew "एक कुंजी स्टोर फ़ाइल के लिए गलत पासवर्ड" "गलत कुंजी" का एक विशेष मामला है।
पाओलो एबरमन

@kenicky क्षमा करें, मैंने अभी आपकी टिप्पणी देखी ... हाँ, एक गलत कुंजी लगभग हमेशा इस आशय का कारण बनती है। (बेशक, दूषित डेटा एक और संभावना है।)
पाओलो एबरमैन

@ Pa @loEbermann मैं सहमत हूँ, लेकिन मुझे नहीं लगता कि यह जरूरी तुरंत स्पष्ट है, क्योंकि यह मूल पोस्ट की स्थिति से अलग है जहां प्रोग्रामर का कुंजी और डिक्रिप्शन पर नियंत्रण है। मुझे आपका उत्तर उपयोगी लगा, जो इसे उभारने के लिए पर्याप्त था।
वारेन ड्यू

1

आपके द्वारा उपयोग की जा रही क्रिप्टोग्राफी एल्गोरिथ्म के आधार पर, आपको बाइट सरणी को एन्क्रिप्ट करने से पहले अंत में कुछ पैडिंग बाइट्स जोड़ने पड़ सकते हैं ताकि बाइट सरणी की लंबाई ब्लॉक आकार में से कई हो:

विशेष रूप से आपके मामले में आपके द्वारा चुना गया पैडिंग स्कीमा PKCS5 है जिसका वर्णन यहाँ दिया गया है: http://www.rsa.com/products/bsafe/documentation/cryptoj35html/doc/dev_guide/group_ CJ _SYM__PAD.html

(मुझे लगता है जब आप एन्क्रिप्ट करने की कोशिश करते हैं तो आपके पास समस्या है)

आप अपने गद्दी स्कीमा का चयन कर सकते हैं जब आप सिफर ऑब्जेक्ट को तुरंत करते हैं। समर्थित मान आपके द्वारा उपयोग किए जा रहे सुरक्षा प्रदाता पर निर्भर करते हैं।

वैसे क्या आप सुनिश्चित हैं कि आप पासवर्ड को एन्क्रिप्ट करने के लिए एक सममित एन्क्रिप्शन तंत्र का उपयोग करना चाहते हैं? बेहतर होगा एक तरह से हैश नहीं होगा? यदि आपको वास्तव में पासवर्ड को डिक्रिप्ट करने में सक्षम होने की आवश्यकता है, तो डेस काफी कमजोर समाधान है, यदि आपको सममित एल्गोरिथ्म के साथ रहने की आवश्यकता है, तो आपको एईएस जैसी मजबूत चीज़ का उपयोग करने में रुचि हो सकती है।


1
तो क्या आप उस कोड को पोस्ट कर सकते हैं जो एन्क्रिप्ट / डिक्रिप्ट करने की कोशिश करता है? (और जांच लें कि आप जिस बाइट को डिक्रिप्ट करने की कोशिश करते हैं, वह ब्लॉक साइज से बड़ा नहीं है)
fpacifici

1
मैं जावा और क्रिप्टोग्राफी के लिए बहुत नया हूं इसलिए मुझे अभी भी एन्क्रिप्शन करने के बेहतर तरीके नहीं पता हैं। मैं बस इसे लागू करने के लिए बेहतर तरीकों की तलाश में इसे पूरा करना चाहता हूं।
अल्ट्रिम

क्या आप लिंक को अपडेट कर सकते हैं क्योंकि यह @fpacifici पर काम नहीं करता है और मैंने अपनी पोस्ट अपडेट की है जिसमें मैंने JUnit टेस्ट शामिल किया है जो एन्क्रिप्शन और डिक्रिप्शन टेस्ट करता है
Altrim

सही किया गया (क्षमा करें कॉपी पेस्ट त्रुटि)। वैसे भी, वास्तव में आपका मुद्दा तब से होता है जब आप एक कुंजी के साथ डिक्रिप्ट करते हैं जो कि पॉलो द्वारा बताए अनुसार एन्क्रिप्शन के लिए उपयोग नहीं किया जाता है। ऐसा इसलिए होता है क्योंकि जून में @Before के साथ एनोटेट की गई विधि को हर परीक्षण विधि से पहले निष्पादित किया जाता है, इस प्रकार हर बार कुंजी को फिर से बनाया जाता है। चूंकि कुंजी को प्रारंभिक रूप से अनियमित किया जाता है, इसलिए यह हर बार अलग होगा।
22

1

मैं JRE कार्यान्वयन के बारे में अलग-अलग प्लेटफॉर्म के लिए सरल, ऑपरेशन सिस्टम के कारण इस मुद्दे से मिला।

new SecureRandom(key.getBytes())

विंडोज में समान मूल्य मिलेगा, जबकि लिनक्स में यह अलग है। इसलिए लिनक्स में इसे बदलने की जरूरत है

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

"SHA1PRNG" एल्गोरिदम का उपयोग किया जाता है, आप एल्गोरिदम के बारे में अधिक जानकारी के लिए यहां उल्लेख कर सकते हैं ।


0

जब आप अपनी साइन कुंजी के लिए गलत पासवर्ड दर्ज करते हैं तो यह एक समस्या भी हो सकती है।


यह वास्तव में एक टिप्पणी है, एक जवाब नहीं है। थोड़ा और प्रतिनिधि के साथ, आप टिप्पणी पोस्ट करने में सक्षम होंगे
एड्रियन मोल

इसका जवाब नहीं है
zig razor
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.