3

我必须在 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 的概念)。

4

2 回答 2

2

不要在浏览器 JS 中做加密;不可能安全地做到这一点。

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

如果成本是您的问题,有免费的 SSL 证书

于 2013-02-22T15:28:37.723 回答
1

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

所以可以做到!只需在 javascript 端使用 Gibberish AES ( https://github.com/mdp/gibberish-aes ) 并在 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());
    }
}
于 2013-06-24T14:57:09.653 回答