AES between server (Java - Cipher) and client (Jav

2020-07-23 03:43发布

问题:

I have to make an app in JS which encodes a message with AES and passes it to a server via AJAX. Then the server and decodes the message using Java.

My question is: How to encrypt a message in JS and be able to decrypt it in Java using AES? Knowing that the communication between java and js is already established via webservices

Client-side, I use the Crypto JS library (http://code.google.com/p/crypto-js/). Server-side I use the Cipher class provided with Java (I use the Java Play framework but it doesn't matter here).

I'm totally new to cryptography. I've made researches all day long and still can't make this work.

The problem is that the key used to encrypt and decrypt the message must be the same, and I don't know how to do this.

From my searches, I understand there is different modes to use AES. By default Java uses ECB and CryptoJS uses CBC which is a problem, but which seems not so hard to fix, by telling CryptoJS to use the ECB mode too. But then there is a padding problem, it seems the only padding available in Java and CryptoJS is no padding at all. But when I use NoPadding in Java I get an exception.

But even if I manage to fix this, the huge problem is that the key generated by CryptoJS and the one generated by Java are not the same. If I encrypt a message in Java the result is always the same, in Hex. But in crypto JS it is in Base64 and it is never the same....

I understand this is caused by the key generation which isn't the same in Java and CryptoJS (then enters the notion of IV and Salt which are blur for me).

回答1:

Don't do encryption in browser JS; it's impossible to do securely.

Use SSL. Its intended purpose is to encrypt communication between a browser and a server.

If cost is your problem, there are free SSL certificates.



回答2:

I recently invested days in this problem. I tried a lot a lot of libraries on the java and javascript side. This blog saved my day: http://watchitlater.com/blog/tag/aes/ .

So it can be done! Just use Gibberish AES (https://github.com/mdp/gibberish-aes) an the javascript side and bouncycastle an on the java side.

The java side encryption might look like this(leaned on the above mentioned blog):

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.spec.InvalidKeySpecException;
import java.util.Random;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Encoder;


public class OpenSSLEncryption {

    private static final String CIPHER_ALG = "PBEWITHMD5AND256BITAES-CBC-OPENSSL";
    private static final Provider CIPHER_PROVIDER = new BouncyCastleProvider();
    private static final String PREFIX = "Salted__";
    private static final String UTF_8 = "UTF-8";
    private String password;
    private PBEKeySpec pbeSpec;
    private SecretKeyFactory keyFact;
    private Cipher cipher;
    private Random rand = new Random();
    private BASE64Encoder encoder = new BASE64Encoder();

    public OpenSSLEncryption(String password) throws NoSuchAlgorithmException, NoSuchPaddingException {
        this.password = password;
        pbeSpec = new PBEKeySpec(password.toCharArray());
        keyFact = SecretKeyFactory.getInstance(CIPHER_ALG, CIPHER_PROVIDER);
        cipher = Cipher.getInstance(CIPHER_ALG, CIPHER_PROVIDER);
    }  

    public synchronized String encrypt(String toEncrypt) throws InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException, UnsupportedEncodingException, IllegalBlockSizeException, BadPaddingException, IOException {
        byte[] salt = new byte[8];
        rand.nextBytes(salt);
        PBEParameterSpec defParams = new PBEParameterSpec(salt, 0);
        cipher.init(Cipher.ENCRYPT_MODE, keyFact.generateSecret(pbeSpec), defParams);
        byte[] cipherText = cipher.doFinal(toEncrypt.getBytes(UTF_8));

        ByteArrayOutputStream baos = new ByteArrayOutputStream(cipherText.length + 16);
        baos.write(PREFIX.getBytes(UTF_8));
        baos.write(salt);
        baos.write(cipherText);
        baos.close();
        return encoder.encode(baos.toByteArray());
    }
}