2016-07-19 4 views
5

कभी-कभी, मैं एक रोचक, अजीब चीज को पूरा करता हूं: एन्क्रिप्टेड टेक्स्ट का एक ही ब्लॉक कई अलग-अलग कुंजी का उपयोग करके डिक्रिप्ट किया जा सकता है!अजीब डीईएस व्यवहार - विभिन्न कुंजी का उपयोग करके डिक्रिप्शन सफल होता है

क्या कोई मुझे बता सकता है कि क्या गलत हो रहा है? बहुत बहुत धन्यवाद।

कृपया मुझे ट्रिपल डीईएस/एईएस आदि पर स्विच करने की कोशिश न करें, मैं सिर्फ यह जानना चाहता हूं कि समस्या कहां है - जावा एसडीके को कॉल करने का तरीका, या जावा एसडीके में बग?

नीचे विंडोज 7 लिनक्स बॉक्स में, एक ही परिणाम पर उत्पादन होता है:

D:\>java -version 
java version "1.7.0_21" 
Java(TM) SE Runtime Environment (build 1.7.0_21-b11) 
Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode) 

D:\>java DESTest -e 12345678 abcde977 

encrypted as [17fd146fa6fdbb5db667efe657dfcb60] 

D:\>java DESTest -d 17fd146fa6fdbb5db667efe657dfcb60 abcde977 

decryted as [12345678] 

D:\>java DESTest -d 17fd146fa6fdbb5db667efe657dfcb60 abcde976 

decryted as [12345678] 

D:\>java DESTest -d 17fd146fa6fdbb5db667efe657dfcb60 abcde967 

decryted as [12345678] 

D:\>java DESTest -d 17fd146fa6fdbb5db667efe657dfcb60 abcde867 

decryted as [12345678] 

D:\>java DESTest -d 17fd146fa6fdbb5db667efe657dfcb60 abcdf867 
Exception in thread "main" java.lang.RuntimeException: javax.crypto.BadPaddingEx 
ception: Given final block not properly padded 
     at DESTest.des(DESTest.java:46) 
     at DESTest.dec(DESTest.java:31) 
     at DESTest.main(DESTest.java:19) 
Caused by: javax.crypto.BadPaddingException: Given final block not properly padd 
ed 
     at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811) 
     at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676) 
     at com.sun.crypto.provider.DESCipher.engineDoFinal(DESCipher.java:314) 
     at javax.crypto.Cipher.doFinal(Cipher.java:2087) 
     at DESTest.des(DESTest.java:44) 
     ... 2 more 

D:\>java DESTest -e 12345678 abcde976 

encrypted as [17fd146fa6fdbb5db667efe657dfcb60] 

D:\>java DESTest -e 12345678 abcde967 

encrypted as [17fd146fa6fdbb5db667efe657dfcb60] 

D:\> 

स्रोत कोड:

import java.io.UnsupportedEncodingException; 
import java.security.SecureRandom; 

import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.DESKeySpec; 

public class DESTest { 
    public static void main(String[] args) { 
     if (args.length < 3) { 
      System.out.println("usage: java " + DESTest.class.getCanonicalName() + " -e|-d text key"); 
      return; 
     } 
     String mode = args[0].trim(); 
     String text = args[1].trim(); 
     String key = args[2].trim(); 
     try { 
      String s = "-d".equalsIgnoreCase(mode) ? dec(text, key) : enc(text, key); 
      System.out.println("\n" + ("-d".equalsIgnoreCase(mode) ? "decryted as [" : "encrypted as [") + s + "]"); 
     } catch (UnsupportedEncodingException e) { 
      e.printStackTrace(); 
     } 
    } 

    private static String enc(String plainText, String key) throws UnsupportedEncodingException { 
     return new String(encHex(des(plainText.getBytes("UTF-8"), key, Cipher.ENCRYPT_MODE))); 
    } 

    private static String dec(String encrypted, String key) throws UnsupportedEncodingException { 
     return new String(des(decHex(encrypted), key, Cipher.DECRYPT_MODE), "UTF-8"); 
    } 

    private static byte[] des(byte[] bytes, String key, int cipherMode) { 
     final String encoding = "UTF-8"; 
     try { 
      DESKeySpec desKey = new DESKeySpec(key.getBytes(encoding)); 
      SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); 
      SecretKey securekey = keyFactory.generateSecret(desKey); 
      // SecretKey securekey = new SecretKeySpec(key.getBytes(encoding), "DES");//same result as the 3 lines above 
      Cipher cipher = Cipher.getInstance("DES"); 
      SecureRandom random = new SecureRandom(); 
      cipher.init(cipherMode, securekey, random); 
      return cipher.doFinal(bytes); 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 

    private static final char[] HEX_CHARS = "abcdef".toCharArray(); 

    private static String encHex(byte[] bytes) { 
     final char[] chars = new char[bytes.length * 2]; 
     for (int i = 0, j = 0; i < bytes.length; i++) { 
      chars[j++] = HEX_CHARS[(0xF0 & bytes[i]) >>> 4]; 
      chars[j++] = HEX_CHARS[0x0F & bytes[i]]; 
     } 
     return new String(chars); 
    } 

    private static byte[] decHex(String hex) { 
     final int len = hex.length(); 
     final byte[] bytes = new byte[len/2]; 
     for (int i = 0, j = 0; j < len; i++) { 
      int f = Character.digit(hex.charAt(j), 16) << 4; 
      j++; 
      f = f | Character.digit(hex.charAt(j), 16); 
      j++; 
      bytes[i] = (byte) (f & 0xFF); 
     } 
     return bytes; 
    } 
} 
+0

मैंने कोड डीबग किया, पाया कि अलग-अलग कुंजी स्ट्रिंग एक ही सुरक्षितकी (लाइन 39), यानी [9 7, 98, 98, 100, 100, 56, 55, 55] उत्पन्न होगी, वही सुरक्षित है क्योंकि डिक्रिप्शन की सफलता का कारण बनता है । लेकिन मुझे नहीं पता कि अलग-अलग कुंजी समान सुरक्षित क्यों उत्पन्न करेगी, और इससे कैसे बचें? – reqresp

उत्तर

4

डेस आपरेशन (दोनों एन्क्रिप्शन और डिक्रिप्शन) प्रत्येक बाइट के lsbit पर ध्यान नहीं देता कुंजी का यही है, अगर आप कुंजी के भीतर किसी भी lsbits फ्लिप, ऑपरेशन वही रहता है। आपके द्वारा की जाने वाली कुंजियों में यही हो रहा है: अंतरिक्ष के लिए ASCII कोड 0x20 है, जबकि ASCII कोड के लिए! 0x21 है; वे केवल lsbit में भिन्न हैं। इसलिए, यदि कुंजी के पास एएससीआईआई कोड के साथ एक बाइट है, तो आप इसे एक के साथ बदल सकते हैं!, और यह अभी भी डिक्रिप्ट करने में सक्षम होगा। इसी प्रकार, * ASCII कोड * 0x2a है, जबकि ASCII कोड + 0x2b है; एलएसबीटी में भी अलग है।

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

Poncho'sCryptography Stackexchange पर अंतर्दृष्टि Answer से निकाला गया।

+0

इसे मिला। स्पष्टीकरण के लिए धन्यवाद! – reqresp

1

डीईएस की 56-बिट कुंजी है, प्रत्येक कुंजी बाइट का एलएसबीटी समान रूप से समानता के लिए उपयोग किया जाता था, अब इसे अनदेखा किया जाता है।

उत्तर है: डीईएस का उपयोग न करें! डीईएस असुरक्षित है और एईएस (उन्नत एन्क्रिप्शन मानक) एईएस द्वारा विशेष रूप से डीईएस को बदलने के लिए डिज़ाइन किया गया है।

आगे किसी को एक कुंजी स्ट्रिंग का उपयोग कुंजी के रूप में नहीं करना चाहिए, सबसे अच्छा अभ्यास चरित्र स्ट्रिंग से एन्क्रिप्शन कुंजी प्राप्त करना है जैसे कि पीबीकेडीएफ 2 (पासवर्ड आधारित कुंजी व्युत्पन्न समारोह)।

+0

इसे मिला। स्पष्टीकरण के लिए धन्यवाद! – reqresp

संबंधित मुद्दे