16

我已经阅读了以下主题,它们有所帮助,但我正在寻找更多信息。

如何使用 BlackBerry 的初始化向量参数编写 AES/CBC/PKCS5Padding 加密和解密

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?如果不是,请随时告诉我让事情更清楚。

4

2 回答 2

12

代码存在一些问题。首先,您确实应该使用密钥生成器来生成密钥。仅直接使用某些文本可能适用于某些算法,但其他算法具有弱键等需要测试。

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

此外,您不应该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 参数非常慢;您肯定想重新使用服务器密钥中的参数。

于 2009-09-17T17:22:48.517 回答
2

之前在 midlet 中做过类似的项目,我给你以下建议:

  1. 没有安全的方法可以在手机上存储共享机密。您可以使用它,但这属于称为Security through Obscurity的类别。这就像一种“垫子下的钥匙”的安全性。
  2. 不要使用未广泛使用的 256 位 AES。您可能必须安装另一个 JCE。128 位 AES 或 TripleDES 仍被认为是安全的。考虑到#1,您不必担心这一点。
  3. 使用密码(每个用户不同)进行加密更加安全。但是您不应该像示例中显示的那样使用密码作为密钥。请使用 PBEKeySpec(基于密码的加密)来生成密钥。
  4. 如果您只是担心 MITM(中间人)攻击,请使用 SSL。
于 2009-09-17T17:47:50.033 回答