2014-10-16 157 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