Domanda

Here is my dilemma. I am trying to decrypt some value from a URL parameter. My code is below

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");
}

I read in some other posts that I should not be using sun.misc.BASE64* but I don't know how to use the Apache version. Now, the problem starts when I decrypt the value. I see some funky chars like : +T??td? I run some tests by encrypting some string then decrypting the same string and these weird chars appear.

What am I doing wrong here?

È stato utile?

Soluzione

Coding problems:

  1. You are URL-decoding the input to the decryptString twice. Once will be enough.
  2. You are casting bytes to characters when constructing the decoded string, while you should use new String(byte[],"UTF-8") to do that.

Crypto problems:

  1. You are using ECB cipher mode for non-random data. Using just any other mode will be better.
  2. You are using character-based key, basically a password. At least hash it instead of using password.getBytes(), at best use proper key derivation function like PBKDF2 (search for PBKDF2WithHmacSHA1 on SO).

An example with CTR cipher mode and SHA-1 password hash:

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;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top