解密URL参数的问题

时间:2014-05-15 12:06:48

标签: java encryption

这是我的困境。我试图从URL参数解密一些值。我的代码在

之下
import java.net.URLDecoder;
import java.net.URLEncoder;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class EncTest {

public static String decryptString(String str, String key) throws Exception {

    str = URLDecoder.decode(str, "UTF-8");
    String result = java.net.URLDecoder.decode(str, "UTF-8");
    byte[] keyBytes = key.getBytes("UTF-8");

    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "DESede");
    Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, keySpec);
    BASE64Decoder base64decoder = new BASE64Decoder();

    byte[] clrtxt = base64decoder.decodeBuffer(result);
    byte[] cphtxt = cipher.doFinal(clrtxt);

    StringBuffer sBuffer = new StringBuffer();

    for (int i = 0; i < cphtxt.length; i++) {
        sBuffer.append((char) cphtxt[i]);
    }

    return sBuffer.toString();

}

public static String encryptString(String str, String key) throws Exception {

    byte[] keyBytes = key.getBytes("UTF-8");
    SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "DESede");
    Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, keySpec);

    byte[] clrtxt = str.getBytes("UTF8");
    byte[] cphtxt = cipher.doFinal(clrtxt);

    BASE64Encoder base64encoder = new BASE64Encoder();

    return URLEncoder.encode(base64encoder.encode(cphtxt), "UTF-8");
}

我在其他一些帖子中读到我不应该使用sun.misc.BASE64 *但我不知道如何使用Apache版本。现在,当我解密该值时,问题就出现了。我看到一些时髦的字符:+ T ?? td?我通过加密一些字符串然后解密相同的字符串来运行一些测试,并出现这些奇怪的字符。

我在这里做错了什么?

1 个答案:

答案 0 :(得分:1)

编码问题:

  1. 您对decryptString的输入进行了两次URL解码。一次就够了。
  2. 在构造解码后的字符串时,您将字符转换为字符,而您应该使用new String(byte[],"UTF-8")来执行此操作。
  3. 加密问题:

    1. 您正在将ECB密码模式用于非随机数据。使用任何其他模式会更好。
    2. 您使用的是基于字符的密钥,基本上是密码。至少哈希它而不是使用password.getBytes(),最好使用正确的密钥派生函数,如PBKDF2(在SO上搜索PBKDF2WithHmacSHA1)。
    3. 使用CTR密码模式和SHA-1密码哈希的示例:

      public static void main( String[] args ) throws Exception {
          String password = "a lovely password of any length";
      
          // source file encoding should be UTF-8 to support this literal
          String plain = "á pláïn téxt wîth non-ascii characters";
          System.out.println( plain );
      
          // proper cipher modes need iv
          byte[] ivBytes = new byte[ 8 ];
          SecureRandom.getInstance( "SHA1PRNG" ).nextBytes( ivBytes );
      
          String encrypted = encryptString( plain, password, ivBytes );
          System.out.println( encrypted );
      
          String decrypted = decryptString( encrypted, password, ivBytes );
          System.out.println( decrypted );
      }
      
      public static String encryptString( String plainText, String password, byte[] ivBytes ) throws Exception {
          MessageDigest sha1 = MessageDigest.getInstance( "SHA1" );
          byte[] keyBytes = Arrays.copyOf( sha1.digest( password.getBytes( "UTF-8" ) ), 24 );
          SecretKeySpec key = new SecretKeySpec( keyBytes, "DESede" );
      
          IvParameterSpec iv = new IvParameterSpec( ivBytes );
      
          Cipher cipher = Cipher.getInstance( "DESede/CTR/PKCS5Padding" );
          cipher.init( Cipher.ENCRYPT_MODE, key, iv );
      
          byte[] plainBytes = plainText.getBytes( "UTF-8" );
          byte[] encryptedBytes = cipher.doFinal( plainBytes );
          String encryptedBase64 = new BASE64Encoder().encode( encryptedBytes );
          String urlEncodedEncryptedBase64 = URLEncoder.encode( encryptedBase64, "UTF-8" );
      
          return urlEncodedEncryptedBase64;
      }
      
      public static String decryptString( String urlEncodedEncryptedBase64, String password, byte[] ivBytes ) throws Exception {
          MessageDigest sha1 = MessageDigest.getInstance( "SHA1" );
          byte[] keyBytes = Arrays.copyOf( sha1.digest( password.getBytes( "UTF-8" ) ), 24 );
          SecretKeySpec key = new SecretKeySpec( keyBytes, "DESede" );
      
          IvParameterSpec iv = new IvParameterSpec( ivBytes );
      
          Cipher cipher = Cipher.getInstance( "DESede/CTR/PKCS5Padding" );
          cipher.init( Cipher.DECRYPT_MODE, key, iv );
      
          // exact mirror of encryption sequence
          String encryptedBase64 = URLDecoder.decode( urlEncodedEncryptedBase64, "UTF-8" );
          byte[] encryptedBytes = new BASE64Decoder().decodeBuffer( encryptedBase64 );
          byte[] decryptedBytes = cipher.doFinal( encryptedBytes );
          String decryptedText = new String( decryptedBytes, "UTF-8" );
      
          return decryptedText;
      }