如何用CBC实现Java 256位AES加密

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (37)

Java 256位AES加密

基本上,我正在做的是编写一个程序来加密要通过TCP / IP发送的请求,然后通过服务器程序进行解密。加密将需要AES,并做了一些研究,我发现我需要使用CBC和PKCS5Padding。所以基本上我需要一个密钥和一个IV。

我正在开发的应用程序是用于手机的,所以我想使用java安全包来减小尺寸。我已经完成了设计,但不确定IV和共享密钥的实现。

以下是一些代码:

// My user name
byte[] loginId = "login".getBytes();

byte[] preSharedKey128 = "ACME-1234AC".getBytes();
byte[] preSharedKey192 = "ACME-1234ACME-1234A".getBytes();
// 256 bit key
byte[] preSharedKey256 = "ACME-1234ACME-1234ACME-1234".getBytes();
byte[] preSharedKey = preSharedKey256;

// Initialization Vector
// Required for CBC
byte[] iv ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
IvParameterSpec ips = new IvParameterSpec(iv);


byte[] encodedKey = new byte[loginId.length + preSharedKey.length];

System.arraycopy(loginId, 0, encodedKey, 0, loginId.length);
System.arraycopy(preSharedKey, 0, encodedKey, loginId.length, preSharedKey.length);

// The SecretKeySpec provides a mechanism for application-specific generation
// of cryptography keys for consumption by the Java Crypto classes.

// Create a key specification first, based on our key input.
SecretKey aesKey = new SecretKeySpec(encodedKey, "AES");

// Create a Cipher for encrypting the data using the key we created.
Cipher encryptCipher;

encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Initialize the Cipher with key and parameters
encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey, ips);

// Our cleartext
String clearString = "33,8244000,9999,411,5012022517,0.00,0,1,V330";
byte[] cleartext = clearString.getBytes();

// Encrypt the cleartext
byte[] ciphertext = encryptCipher.doFinal(cleartext);

// Now decrypt back again...
// Decryption cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Initialize PBE Cipher with key and parameters
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ips);

// Decrypt the cleartext
byte[] deciphertext = decryptCipher.doFinal(ciphertext);

简而言之,它应该做的是加密一些可以被服务器解密的消息,而服务器不需要从手机获取密钥或IV。有没有一种方法可以做到这一点,我可以在手机上保护IV和密钥,并且仍然拥有服务器所知道的密钥和IV密钥?如果他们不是,请随时告诉我更清楚。

提问于
用户回答回答于

代码有几个问题。首先,你应该使用密钥生成器来生成密钥。直接使用某些文本可能适用于某些算法,但其他算法则具有弱密钥等,需要进行测试。

即使您想要进行基于密码的加密,也应该通过密钥派生算法来运行密码以生成密钥,如对您已经引用的问题的回答所示。

另外,你不应该使用no-arg getBytes()方法String。这取决于平台。如果所有正在编码的字符串仅包含US-ASCII字符集中的字符,请通过明确指定该编码来清除它。否则,如果电话和服务器平台使用不同的字符编码,则密钥和IV将不会相同。

对于CBC模式,最好对您发送的每封邮件使用新的IV。通常,CBC IV是随机生成的。其他模式如CFB和OFB 需要每个消息都有独特的IV。IV通常与密文一起发送-IV不需要保密,但是如果使用可预测的IV,许多算法将会中断。

服务器不需要直接从手机获取秘密或IV。您可以使用秘密密钥(或密码,从中导出密钥)配置服务器,但在许多应用程序中,这将是一个糟糕的设计。

例如,如果应用程序将被部署到多人的电话中,那么使用相同的密钥并不是一个好主意。一个恶意用户可以恢复密钥并为每个人打破系统。

更好的方法是在手机上生成新的密钥,并使用密钥协商算法与服务器交换密钥。Diffie-Hellman密钥协议可以用于此,或者密钥可以用RSA加密并发送到服务器。

只要服务器的公钥已嵌入到应用程序中,Diffie-Hellman在“短暂 - 静态”模式下(以及“静态 - 静态”模式也是如此,尽管这不太理想),而不需要从服务器到手机的初始消息。

服务器公钥不会像在手机中嵌入公共密钥一样带来相同的风险。由于它是一个公钥,威胁将是攻击者利用手机(或远程窃听)手机并用虚假密钥替换真实公钥,从而冒充服务器。

可以使用静态 - 静态模式,但实际上它更复杂,不太安全。每部手机都需要自己的唯一密钥对,否则你就会陷入秘密密钥问题。至少服务器不需要跟踪哪个电话具有哪个密钥(假设应用程序级别有一些身份验证机制,例如密码)。

我不知道手机有多快。在我的桌面上,生成临时密钥对需要大约1/3秒。生成Diffie-Hellman参数非常缓慢; 你一定要重新使用服务器密钥中的参数。

用户回答回答于

之前在midlet中完成类似的项目,我为您提供以下建议:

  1. 没有安全的方式在手机上存储共享密钥。您可以使用它,但这属于一个名为“ 通过默认安全”的类别。这就像一个“钥匙垫下”的安全。
  2. 不要使用不可用的256位AES。您可能需要安装另一个JCE。128位AES或TripleDES仍被认为是安全的。考虑到#1,你不应该担心这一点。
  3. 使用密码进行加密(每个用户不同)会更安全。但是您不应该使用密码作为示例中显示的密钥。请使用PBEKeySpec(基于密码的加密)生成密钥。
  4. 如果您只是担心MITM(中间人)攻击,请使用SSL。

扫码关注云+社区