2012-02-01 10 views
30

इस विषय के साथ बहुत सारे प्रश्न हैं, एक ही समाधान है, लेकिन यह मेरे लिए काम नहीं करता है। मेरे पास एक एन्क्रिप्शन के साथ एक सरल परीक्षण है। एन्क्रिप्शन/डिक्रिप्शन स्वयं काम करता है (जब तक मैं इस परीक्षण को बाइट सरणी के साथ ही संभालता हूं) स्ट्रिंग्स के रूप में नहीं। समस्या यह है कि इसे बाइट सरणी के रूप में संभालना नहीं चाहते हैं, लेकिन स्ट्रिंग के रूप में, लेकिन जब मैं बाइट सरणी को स्ट्रिंग और बैक करने के लिए एन्कोड करता हूं, परिणामी बाइट सरणी मूल बाइट सरणी से अलग होती है, इसलिए डिक्रिप्शन अब और काम नहीं करता है। मैंने संबंधित स्ट्रिंग विधियों में निम्नलिखित पैरामीटरों का प्रयास किया: यूटीएफ -8, यूटीएफ 8, यूटीएफ -16, यूटीएफ 8। उनमें से कोई भी काम नहीं करता है। परिणामी बाइट सरणी मूल से अलग है। कोई विचार क्यों ऐसा है?बाइट सरणी को स्ट्रिंग और बैट सरणी पर वापस करने में समस्याएं

encrypter:

public class NewEncrypterTest 
{ 
    @Test 
    public void canEncryptAndDecrypt() throws Exception 
    { 
     String toEncrypt = "FOOBAR"; 

     NewEncrypter encrypter = new NewEncrypter(); 

     byte[] encryptedByteArray = encrypter.encrypt(toEncrypt); 
     System.out.println("encryptedByteArray:" + encryptedByteArray); 

     String decoded = new String(encryptedByteArray, "UTF-16"); 
     System.out.println("decoded:" + decoded); 

     byte[] encoded = decoded.getBytes("UTF-16"); 
     System.out.println("encoded:" + encoded); 

     String decryptedText = encrypter.decrypt(encoded); //Exception here 
     System.out.println("decryptedText:" + decryptedText); 

     assertEquals(toEncrypt, decryptedText); 
    } 
} 
+3

आपको पहले बाइट को किसी स्ट्रिंग के रूप में प्रस्तुत करने की आवश्यकता है। आमतौर पर हेक्स या बेस 64 में परिवर्तित करके। –

+0

स्ट्रिंग में कनवर्ट करने से पहले और बाद में बाइट एरे में आप क्या वास्तविक अंतर देखते हैं? – Herms

+0

@Roger Lindsjö: टिप के लिए धन्यवाद। मैं इसे तुरंत कोशिश करूंगा। – Bevor

उत्तर

73

स्ट्रिंग्स में एन्क्रिप्टेड डेटा को स्टोर करना एक अच्छा विचार नहीं है क्योंकि वे मानव-पठनीय पाठ के लिए हैं, मनमाना बाइनरी डेटा के लिए नहीं। बाइनरी डेटा के लिए byte[] का उपयोग करना सबसे अच्छा है।

हालांकि, अगर आप यह करना चाहिए कि आप, कि है, कोई एन्कोडिंग एक 1 से 1 मानचित्रण बाइट्स और वर्णों के बीच है का उपयोग करना चाहिए, जहां हर बाइट क्रम पात्रों में से एक अनूठा अनुक्रम मैप किया जा सकता , और वापस। ऐसा ही एक एन्कोडिंग ISO-8859-1 है, वह यह है कि:

String decoded = new String(encryptedByteArray, "ISO-8859-1"); 
    System.out.println("decoded:" + decoded); 

    byte[] encoded = decoded.getBytes("ISO-8859-1"); 
    System.out.println("encoded:" + java.util.Arrays.toString(encoded)); 

    String decryptedText = encrypter.decrypt(encoded); 

अन्य सामान्य एन्कोडिंग्स कि खोना नहीं है डेटा हेक्साडेसिमल और बेस 64 कर रहे हैं, लेकिन दुर्भाग्य से आप उनके लिए एक सहायक पुस्तकालय की जरूरत है। मानक एपीआई उनके लिए कक्षाओं को परिभाषित नहीं करता है।

साथ UTF-16

कार्यक्रम दो कारणों से विफल हो जाएगा:

  1. String.getBytes ("UTF-16") एक बाइट आदेश-मार्कर चरित्र उत्पादन के लिए बाइट के आदेश की पहचान के लिए कहते हैं । ऐसा होने के लिए आपको यूटीएफ -16LE या यूटीएफ -16 बीई का उपयोग करना चाहिए।
  2. यूटीएफ -16 में वर्णों के लिए बाइट्स के सभी अनुक्रमों को मैप नहीं किया जा सकता है। सबसे पहले, यूटीएफ -16 में एन्कोड किए गए टेक्स्ट में बाइट्स की संख्या भी होनी चाहिए। दूसरा, यूटीएफ -16 में यू + एफएफएफएफ से परे यूनिकोड वर्णों को एन्कोड करने के लिए एक तंत्र है। इसका मतलब है कि उदा। वहाँ 4 बाइट्स के अनुक्रम हैं जो केवल एक यूनिकोड चरित्र को मैप करते हैं। इसके लिए संभव है कि 4 के पहले 2 बाइट यूटीएफ -16 में किसी भी चरित्र को एन्कोड न करें।
+0

आज मैंने देखा कि मुझे विभिन्न वीएम में एन्क्रिप्शन और डिक्रिप्शन का उपयोग करते समय समस्या है। जाहिर है केवल आपका समाधान काम करता है। – Bevor

+0

अपाचे कॉमन्स कोडेक का उपयोग करने के आपके दृष्टिकोण को भी काम करना चाहिए, लेकिन आपको अपने एप्लिकेशन के साथ कॉमन्स-कोडेक लाइब्रेरी वितरित करना होगा। – Joni

+0

बहुत उपयोगी, बहुत बहुत धन्यवाद :) – Spl2nky

0

आपकी समस्या यह है कि आप एक मनमाना से एक UTF-16 (या किसी अन्य एन्कोडिंग) स्ट्रिंग निर्माण नहीं कर सकते है:

public class NewEncrypter 
{ 
    private String algorithm = "DESede"; 
    private Key key = null; 
    private Cipher cipher = null; 

    public NewEncrypter() throws NoSuchAlgorithmException, NoSuchPaddingException 
    { 
     key = KeyGenerator.getInstance(algorithm).generateKey(); 
     cipher = Cipher.getInstance(algorithm); 
    } 

    public byte[] encrypt(String input) throws Exception 
    { 
     cipher.init(Cipher.ENCRYPT_MODE, key); 
     byte[] inputBytes = input.getBytes("UTF-16"); 

     return cipher.doFinal(inputBytes); 
    } 

    public String decrypt(byte[] encryptionBytes) throws Exception 
    { 
     cipher.init(Cipher.DECRYPT_MODE, key); 
     byte[] recoveredBytes = cipher.doFinal(encryptionBytes); 
     String recovered = new String(recoveredBytes, "UTF-16"); 

     return recovered; 
    } 
} 

यह परीक्षण जहां मैं इसे करने की कोशिश है बाइट सरणी (UTF-16 on Wikipedia देखें)। हालांकि, यह आपके ऊपर है, बिना किसी नुकसान के एन्क्रिप्टेड बाइट सरणी को क्रमबद्ध और deserialize करने के लिए, कहने के लिए, इसे जारी रखें, और बाद में इसका उपयोग करें।

public static void main(String[] args) throws Exception { 
    String toEncrypt = "FOOBAR"; 

    NewEncrypter encrypter = new NewEncrypter(); 

    byte[] encryptedByteArray = encrypter.encrypt(toEncrypt); 
    System.out.println("encryptedByteArray:" + Arrays.toString(encryptedByteArray)); 

    String decoded = new String(encryptedByteArray, "UTF-16"); 
    System.out.println("decoded:" + decoded); 

    byte[] encoded = decoded.getBytes("UTF-16"); 
    System.out.println("encoded:" + Arrays.toString(encoded)); 

    String decryptedText = encrypter.decrypt(encryptedByteArray); // NOT the "encoded" value! 
    System.out.println("decryptedText:" + decryptedText); 
} 

यह आउटपुट है::

encryptedByteArray:[90, -40, -39, -56, -90, 51, 96, 95, -65, -54, -61, 51, 6, 15, -114, 88] 
decoded:<some garbage> 
encoded:[-2, -1, 90, -40, -1, -3, 96, 95, -65, -54, -61, 51, 6, 15, -114, 88] 
decryptedText:FOOBAR 

decryptedText सही है, जब मूल encryptedByteArray से बहाल यहाँ संशोधित ग्राहक कोड है कि आप क्या वास्तव में बाइट सरणियों के साथ क्या हो रहा है में से कुछ जानकारी दे देना चाहिए । कृपया ध्यान दें कि मान जैसा नहीं है, byte[] -> String("UTF-16")->byte[] रूपांतरण के दौरान डेटा हानि के कारण।

+0

धन्यवाद, इस समय मुझे एक और समाधान मिला (मेरा जवाब देखें)। फिर भी मैं आपका जवाब स्वीकार करूंगा, क्योंकि आपका समाधान भी काम करता है। – Bevor

+0

आज मैंने देखा कि आप मूल बाइट सरणी को डिक्रिप्ट करते हैं। यह वास्तव में वह नहीं है जो मैं चाहता था (और दुर्भाग्यवश मुझे विभिन्न वीएम में इसका उपयोग करते समय इसे फिर से डिक्रिप्ट करना पड़ा), इसलिए केवल जॉनी का समाधान काम करता था। – Bevor

+0

मेरा कोड आपके कोड में आपके द्वारा की गई त्रुटि का एक उदाहरण था, एक धारावाहिक समाधान नहीं ("यह आपके ऊपर है, हालांकि, बिना किसी हानि के एन्क्रिप्टेड बाइट सरणी को क्रमबद्ध और deserialize करने के लिए"), जैसा कि आप उपयोग करना चाहते हैं विभिन्न धारावाहिक तकनीकों के टन (डेटाइन/आउटपुटस्ट्रीम इत्यादि का उपयोग करके) –

5

अब, मैं एक और समाधान भी ...

public class NewEncrypterTest 
    { 
     @Test 
     public void canEncryptAndDecrypt() throws Exception 
     { 
      String toEncrypt = "FOOBAR"; 

      NewEncrypter encrypter = new NewEncrypter(); 

      byte[] encryptedByteArray = encrypter.encrypt(toEncrypt); 
      String encoded = String.valueOf(Hex.encodeHex(encryptedByteArray)); 

      byte[] byteArrayToDecrypt = Hex.decodeHex(encoded.toCharArray()); 
      String decryptedText = encrypter.decrypt(byteArrayToDecrypt); 

      System.out.println("decryptedText:" + decryptedText); 

      assertEquals(toEncrypt, decryptedText); 
     } 
    } 
13

अगर आपके String कुछ गैर विशिष्ट š, ž, ć, Ō, ō, Ū रूप में इस तरह charcaters है स्वीकृत समाधान काम नहीं करेगा, आदि

कोड काम के बाद पाया मेरे लिए अच्छी तरह से।

byte[] myBytes = Something.getMyBytes(); 
String encodedString = Base64.encodeToString(bytes, Base64.NO_WRAP); 
byte[] decodedBytes = Base64.decode(encodedString, Base64.NO_WRAP); 
+0

एकमात्र कामकाजी समाधान, हालांकि आपको ApacheCommons – AntJavaDev

+3

पर निर्भर होना है, मैं 'android.util.Base64' का उपयोग कर रहा था। यदि आप 'अपाचे कॉमन्स' शामिल नहीं करना चाहते हैं तो मुझे लगता है कि आप हमेशा अपनी परियोजना में फ़ाइल कॉपी कर सकते हैं। यहां स्रोत है: https://github.com/android/platform_frameworks_base/blob/master/core/java/android/util/Base64.java –

+1

हाँ मैंने इंगित किया कि जावा अनुप्रयोगों के लिए, यह उपयोगिता कक्षा जेडीके 1.8 के साथ भी आती है , लेकिन पिछले जावा संस्करणों के लिए आपको अपाचे कॉमन्स पर निर्भर होना है क्योंकि यह एकमात्र कामकाजी विधि है। – AntJavaDev

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