2014-10-16 197 views
0

我試着按照SO上的一個例子來加密和解密一個字符串。加密和解密一個字符串

這是我到目前爲止有:

public static String encrypt(String value) { 
     byte[] encrypted = null; 
     String encrypted_string = null; 
     try { 

      byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'}; 
      Key skeySpec = new SecretKeySpec(raw, "AES"); 
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      byte[] iv = new byte[cipher.getBlockSize()]; 

      IvParameterSpec ivParams = new IvParameterSpec(iv); 
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec,ivParams); 
      encrypted = cipher.doFinal(value.getBytes()); 
      System.out.println("encrypted string:" + encrypted.length); 

      //Encrypted byte array 
      System.out.println("encrypted byte array:" + encrypted); 

      //Encrypted string 
      encrypted_string = new String(encrypted); 
      System.out.println("encrypted string: " + encrypted_string); 

     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     return encrypted_string; 
    } 

    public static String decrypt(String encrypted_string) { 
     byte[] original = null; 
     Cipher cipher = null; 
     String decrypted_string = null; 
     try { 
      byte[] raw = new byte[]{'T', 'h', 'i', 's', 'I', 's', 'A', 'S', 'e', 'c', 'r', 'e', 't', 'K', 'e', 'y'}; 
      Key key = new SecretKeySpec(raw, "AES"); 
      cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
      //the block size (in bytes), or 0 if the underlying algorithm is not a block cipher 
      byte[] ivByte = new byte[cipher.getBlockSize()]; 
      //This class specifies an initialization vector (IV). Examples which use 
      //IVs are ciphers in feedback mode, e.g., DES in CBC mode and RSA ciphers with OAEP encoding operation. 
      IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte); 
      cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec); 
      original= cipher.doFinal(encrypted_string.getBytes()); 

      //Converts byte array to String 
      decrypted_string = new String(original); 
      System.out.println("Text Decrypted : " + decrypted_string); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 
     return decrypted_string; 
    } 

我希望能夠加密字符串,然後返回一個加密的字符串。然後採取該加密的字符串,並將其傳遞給我的解密方法,該方法也會返回原始解密的字符串。

我跟着一個使用Byte []數組的例子,但我不想使用Byte數組,我只想使用字符串。

的問題與上述是我在這條線得到一個錯誤:

original= cipher.doFinal(encrypted_string.getBytes()); 

它說,「錯最後塊長度:IllegalBlockSizeException」。這讓我想我不能簡單地將我的字符串轉換爲一個字節數組並將其傳遞給final()方法。但是,我能做些什麼來以上面我想要的格式解決這個問題?

+3

幾乎所有的加密算法要對字節,而不是字符串的工作。接受你需要來回轉換。也就是說,您可以使用'string.getBytes(StandardCharsets.UTF_8)'和'new String(bytes,StandardCharsets.UTF_8)'在字符串及其字節數組表示之間進行有效轉換。 – 2014-10-16 19:27:46

+1

如果您更喜歡將字符串作爲字符串而不是字節來處理,您可能還想使用Base-64。 – rossum 2014-10-16 22:26:43

回答

1

將隨機字節數組(即典型簽名轉換爲字符串) 所有不可打印字符都將替換爲替換字符。 替代字符取決於使用的編碼。對於ASCII這是? (3F十六進制) ,對於UTF-8,這是 (EFBFBD十六進制)。

public String(byte[] bytes)使用默認編碼進行轉換,這可能是針對您的應用程序的UTF-8。然後String.getBytes()將字符串數據轉換回默認編碼,對於原始數據的每個不可打印字符,EFBFBD會得到很多 ,使其更長。 AES依次是分組密碼,它在16字節塊上運行。因此,所有密文 文本的長度都與16成正比。這就是爲什麼當數據源將數據破壞到AES解密時,您得到無效塊大小的原因, 。

將二進制數據轉換爲字符串表示形式的一種可能性是Base64編碼。 在Android上可以使用Base64類來完成:

String encryptedString = Base64.encodeToString(encrypted, Base64.DEFAULT); 
byte[] encrypted2 = Base64.decode(encryptedString, Base64.DEFAULT); 
+0

Java 8還具有Base64編碼(包括URL安全編碼)。使用十六進制編碼也是相當標準的。 – 2014-10-17 12:10:31

+0

是的,但是當Android將獲得Java 8支持? – divanov 2014-10-18 10:14:58

+0

沒有注意到標籤。反正可能有興趣。 – 2014-10-21 08:54:04