服务器(Java - Cipher)和客户端之间的AES(Javascript - CryptoJS)

时间:2013-02-22 15:21:40

标签: java javascript client-server aes

我必须在JS中创建一个应用程序,它使用AES对消息进行编码,并通过AJAX将其传递给服务器。然后服务器使用Java解码消息。

我的问题是:如何在JS中加密消息并能够使用AES在Java中解密它?知道java和js之间的通信已经通过webservices建立

客户端,我使用Crypto JS库(http://code.google.com/p/crypto-js/)。服务器端我使用Java提供的Cipher类(我使用的是Java Play框架,但这并不重要。)

我对密码学完全陌生。我整天都在进行研究,但仍然无法完成这项工作。

问题是用于加密和解密邮件的密钥必须相同,我不知道如何执行此操作。

从我的搜索中,我了解使用AES有不同的模式。默认情况下,Java使用ECB而CryptoJS使用CBC这是一个问题,但通过告诉CryptoJS也使用ECB模式,这似乎不太难修复。但是有一个填充问题,似乎Java中唯一可用的填充和CryptoJS根本就没有填充。但是当我在Java中使用NoPadding时,我得到了一个例外。

但即使我设法解决这个问题,最大的问题是CryptoJS生成的密钥和Java生成的密钥不一样。如果我用Java加密消息,结果总是相同的,用十六进制表示。但是在加密JS中,它在Base64中,它永远不会相同......

据我所知,这是由Java和CryptoJS中的密钥生成引起的(然后输入IV和Salt的概念对我来说很模糊)。

2 个答案:

答案 0 :(得分:2)

不要在浏览器JS中进行加密;安全地进行impossible

使用SSL。其目的是加密浏览器和服务器之间的通信。

如果费用是您的问题,则有free SSL certificates

答案 1 :(得分:1)

我最近在这个问题上投入了很多时间。我在java和javascript方面尝试了很多库。这个博客节省了我的一天:http://watchitlater.com/blog/tag/aes/

所以可以做到!只需使用Gibberish AES(https://github.com/mdp/gibberish-aes)作为javascript端,并在java端使用bouncycastle。

java端加密可能看起来像这样(靠上面提到的博客):

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