2015-05-21 2 views
5

के साथ एक स्ट्रिंग को एन्क्रिप्ट करने और डिक्रिप्ट करने का प्रयास करते समय IllegalBlockSizeException मेरे पास एक हार्डकोडेड कुंजी है जिसके साथ मैं SharedPreferences में संग्रहीत करने से पहले एक स्ट्रिंग को एन्क्रिप्ट करना चाहता हूं।एलेस

public class TokenEncryptor { 

    private final static String TOKEN_KEY = "91a29fa7w46d8x41"; 

    public static String encrypt(String plain) { 
     try { 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      AlgorithmParameterSpec ivSpec = new IvParameterSpec(new byte[16]); 
      SecretKeySpec newKey = new SecretKeySpec(TOKEN_KEY.getBytes(), "AES"); 
      cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec); 
      return new String(cipher.doFinal(plain.getBytes())); 
     } catch (Exception e) { 
      Ln.e(e); 
      return null; 
     } 
    } 

    public static String decrypt(String encoded) { 
     try { 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      AlgorithmParameterSpec ivSpec = new IvParameterSpec(new byte[16]); 
      SecretKeySpec newKey = new SecretKeySpec(TOKEN_KEY.getBytes(), "AES"); 
      cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec); 
      return new String(cipher.doFinal(encoded.getBytes())); 
     } catch (Exception e) { 
      Ln.e(e); 
      return null; 
     } 
    } 
} 

यह decrypt विधि के अंत में एक अपवाद को पकड़ने जा रहा है:

javax.crypto.IllegalBlockSizeException: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length

कोई सही दिशा में मुझे बात कर सकते हैं इस कोड को मैं अब तक किया है? मुझे एहसास है कि मैं कुछ गलत कर रहा हूं IvParameterSpec

+1

आपकी कुंजी केवल 16 बाइट लंबी है, इसलिए आप एईएस-128 के बारे में बात नहीं कर रहे हैं एईएस -256। –

+0

@ArtjomB। क्या इसे एईएस -256 बनाने के लिए इसे 32 बाइट्स में बदलना चाहिए? इसके बारे में अपरिचित होने के लिए मेरी माफ़ी, यह पहली बार है कि मुझे एन्क्रिप्शन – Oleksiy

+0

से निपटना है हां, यदि आप 24 या 32 बाइट्स के लिए मुख्य आकार बढ़ाते हैं, तो एईएस -192 या एईएस -256 स्वचालित रूप से उपयोग किया जाएगा। –

उत्तर

5

जब आप एईएस के साथ एक स्ट्रिंग एन्क्रिप्ट करते हैं, तो आपको बाइट्स की एक सरणी मिल जाती है। उन बाइट्स को सीधे एक स्ट्रिंग (new String(cipher.doFinal(plaintextBytes))) में कनवर्ट करने का प्रयास करने से सभी प्रकार की समस्याएं पैदा हो जाएंगी। यदि आपको अपनी एन्क्रिप्शन विधि से स्ट्रिंग होने के आउटपुट की आवश्यकता है, तो प्रत्यक्ष रूपांतरण करने के बजाय Base64 का उपयोग करें। अपनी डिक्रिप्शन विधि में, बाइट सरणी को डिक्रिप्ट करने से पहले Base64 स्ट्रिंग को बाइट सरणी में वापस कनवर्ट करें।

इसके अलावा, getBytes() का उपयोग न करें क्योंकि आउटपुट सिस्टम डिफ़ॉल्ट पर निर्भर करता है। getBytes("utf-8") या जो कुछ भी उपयोग करें। यह अस्पष्टता को समाप्त करता है।

+2

[क्यू: बेस 64 एन्कोडर और डिकोडर] (http: // stackoverflow।कॉम/प्रश्न/4322182/बेस 64-एन्कोडर-एंड-डिकोडर) –

8

बस मामले में किसी को भी रुचि रखता है (या बहुत उनके अनुसंधान करने के लिए आलसी महसूस करता है), यहाँ है AES-256 एन्क्रिप्शन और डिक्रिप्शन के लिए परिणाम कोड है कि मैं स्वीकार किए जाते हैं जवाब और टिप्पणियों से एक साथ रखा, मदद से:

public class TokenEncryptor { 

    private final static String TOKEN_KEY = "fqJfdzGDvfwbedsKSUGty3VZ9taXxMVw"; 

    public static String encrypt(String plain) { 
     try { 
      byte[] iv = new byte[16]; 
      new SecureRandom().nextBytes(iv); 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(TOKEN_KEY.getBytes("utf-8"), "AES"), new IvParameterSpec(iv)); 
      byte[] cipherText = cipher.doFinal(plain.getBytes("utf-8")); 
      byte[] ivAndCipherText = getCombinedArray(iv, cipherText); 
      return Base64.encodeToString(ivAndCipherText, Base64.NO_WRAP); 
     } catch (Exception e) { 
      Ln.e(e); 
      return null; 
     } 
    } 

    public static String decrypt(String encoded) { 
     try { 
      byte[] ivAndCipherText = Base64.decode(encoded, Base64.NO_WRAP); 
      byte[] iv = Arrays.copyOfRange(ivAndCipherText, 0, 16); 
      byte[] cipherText = Arrays.copyOfRange(ivAndCipherText, 16, ivAndCipherText.length); 

      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(TOKEN_KEY.getBytes("utf-8"), "AES"), new IvParameterSpec(iv)); 
      return new String(cipher.doFinal(cipherText), "utf-8"); 
     } catch (Exception e) { 
      Ln.e(e); 
      return null; 
     } 
    } 

    private static byte[] getCombinedArray(byte[] one, byte[] two) { 
     byte[] combined = new byte[one.length + two.length]; 
     for (int i = 0; i < combined.length; ++i) { 
      combined[i] = i < one.length ? one[i] : two[i - one.length]; 
     } 
     return combined; 
    } 

} 
+0

मुझे खेद है, लेकिन हमारे पास "नया सिक्योररैंडम()। अगला बाइट्स (iv) क्यों है;" ? वापसी मूल्य का उपयोग नहीं किया जाता है, है ना? – zkvarz

+1

@zkvarz: विधि असाइन बाइट सरणी का उपयोग करता है -> कोई वापसी मूल्य –

+0

@NinoHandler ठीक है, धन्यवाद। – zkvarz

3

यह आर्टजॉम बी का एक विस्तार है और मेरे लिए काम कर रहा है।

public String encryptMsg(String message, SecretKey secret) 
      throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidParameterSpecException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException { 
     Cipher cipher = null; 
     cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
     cipher.init(Cipher.ENCRYPT_MODE, secret); 
     byte[] cipherText = cipher.doFinal(message.getBytes("UTF-8")); 
     return Base64.encodeToString(cipherText, Base64.NO_WRAP); 
    } 

public String decryptMsg(String cipherText, SecretKey secret) 
     throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidParameterSpecException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException { 
    Cipher cipher = null; 
    cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, secret); 
    byte[] decode = Base64.decode(cipherText, Base64.NO_WRAP); 
    String decryptString = new String(cipher.doFinal(decode), "UTF-8"); 
    return decryptString; 
}