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

如何用CBC实现Java 256位AES加密,java,encryption,aes,Java,Encryption,Aes,我已经阅读了下面的帖子,它们对我有一点帮助,但我正在寻找更多的信息 基本上,我正在编写一个程序,对通过TCP/IP发送的请求进行加密,然后由服务器程序解密。加密将需要AES,做一些研究,我发现我需要使用CBC和PKCS5P。所以基本上我需要一把秘密钥匙和一个IV 我正在开发的应用程序是为手机开发的,所以我想使用java安全包来减小大小。我已经完成了设计,但不确定IV和共享密钥的实现 下面是一些代码: // My user name byte[] loginId = "login".getBy

我已经阅读了下面的帖子,它们对我有一点帮助,但我正在寻找更多的信息

基本上,我正在编写一个程序,对通过TCP/IP发送的请求进行加密,然后由服务器程序解密。加密将需要AES,做一些研究,我发现我需要使用CBC和PKCS5P。所以基本上我需要一把秘密钥匙和一个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已知的服务器呢?如果不清楚,请随时告诉我让事情变得更清楚。

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

即使您希望进行基于密码的加密,也应该通过密钥派生算法运行密码以生成密钥,如您前面提到的问题中所示

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

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

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

例如,如果应用程序要部署到多人的手机上,那么对他们来说使用相同的密钥不是一个好主意。一个恶意用户可以为每个人恢复密钥并破坏系统

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


更新:

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

服务器公钥与在手机中嵌入公共密钥的风险不同。由于这是一个公钥,威胁可能是攻击者获取(或远程入侵)手机,并用假密钥替换真实公钥,使其能够模拟服务器

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


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

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

  • 没有安全的方法在手机上存储共享秘密。您可以使用它,但它属于一个名为的类别。这就像“垫子下的钥匙”一样安全
  • 不要使用256位AES,这是不广泛可用的。您可能需要安装另一个JCE。128位AES或三元组仍然被认为是安全的。考虑到#1,你不应该担心这一点
  • 使用密码加密(每个用户的密码不同)更安全。但您不应该像示例中所示那样使用密码作为密钥。请使用PBEKeySpec(基于密码的加密)生成密钥
  • 如果您只是担心MITM(中间人)攻击,请使用SSL

  • 现在,我被告知要使用的设计是,我们可以在每部手机上使用相同的钥匙,但我不同意。Diffie-Hellman方法容易实现吗?不,Diffie-Hellman至少对我来说有点困惑。它使用KeyAgreement类。RSA加密更容易。它使用的密码与您当前使用的AES加密类似。RSA需要注意的一点是,密文将有数百个字节,如果明文只有几个字节,这将是一种浪费;不确定这在你的申请中是否重要。另一个要考虑的是,如果通信是非常短的消息(100到200字节),只从电话到服务器,你可以用RSA加密消息本身。我认为我所寻找的安全级别并不涉及真正复杂的事情。我会记住的。回到Diffie Hellman的事情,发送者是否需要先向服务器发送一些东西来建立密钥,然后用密钥加密后再发送?我喜欢这种方法,只是不知道如何处理