简体   繁体   English

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

[英]How to implement Java 256-bit AES encryption with CBC

I've read the following threads and they've helped a little, but I'm looking for a little more info. 我已经阅读了以下主题并且他们帮助了一点,但我正在寻找更多信息。

How to write AES/CBC/PKCS5Padding encryption and decryption with Initialization Vector Parameter for BlackBerry 如何使用BlackBerry的初始化矢量参数编写AES / CBC / PKCS5Padding加密和解密

Java 256bit AES Encryption Java 256bit AES加密

Basically, what I am doing is writing a program that will encrypt a request to be sent over TCP/IP, and then decrypted by a server program. 基本上,我正在做的是编写一个程序,它将加密通过TCP / IP发送的请求,然后由服务器程序解密。 The encryption will need to be AES, and doing some research I found out I need to use CBC and PKCS5Padding. 加密需要是AES,并且做了一些研究我发现我需要使用CBC和PKCS5Padding。 So basically I need a secret key and an IV as well. 所以基本上我需要一个秘密密钥和一个IV。

The application I'm developing is for a phone, so I want to use the java security packages to keep the size down. 我正在开发的应用程序是用于手机,所以我想使用java安全包来减小尺寸。 I've got the design done, but unsure of the implementation of the IV and the shared key. 我已完成设计,但不确定IV和共享密钥的实现。

Here's some code: 这是一些代码:

// 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);

In a nutshell what it should do is encrypt some message that can decrypted by the server without the server needing to get a key or IV from the phone. 简而言之它应该做的是加密一些可以由服务器解密的消息,而无需服务器从手机获取密钥或IV。 Is there a way I could do this where I could secure the IV and key on the phone, and still have the key and IV known by the server as well? 有没有办法可以做到这一点,我可以保护手机上的IV和键,并且仍然有服务器知道的密钥和IV? Feel free to tell me to make things more clear if they're not. 如果他们不是,请随时告诉我更清楚。

There are a few problems with the code. 代码存在一些问题。 First of all, you really should use a key generator to generate secret keys. 首先,您确实应该使用密钥生成器来生成密钥。 Just using some text directly might work for some algorithms, but others have weak keys and so forth that need to be tested. 直接使用某些文本可能适用于某些算法,但其他算法则需要进行弱测试等等。

Even if you want to do password-based encryption, the password should be run through a key-derivation algorithm to produce a key, as shown in my answer to the question that you cited already. 即使您想要进行基于密码的加密,也应该通过密钥派生算法运行密码以生成密钥,如对您已引用的问题的回答所示。

Also, you shouldn't use the no-arg getBytes() method of String . 此外,您不应该使用String的no-arg getBytes()方法。 This is platform dependent. 这取决于平台。 If all of the strings that you are encoding contain only characters from the US-ASCII character set, make it clear by specifying that encoding explicitly. 如果您编码的所有字符串仅包含US-ASCII字符集中的字符,请通过明确指定该编码来使其清楚。 Otherwise, if the phone and server platforms use different character encodings, the key and IV won't turn out the same. 否则,如果电话和服务器平台使用不同的字符编码,则密钥和IV将不会相同。

For CBC mode, it's best to use a new IV for every message you send. 对于CBC模式,最好为发送的每条消息使用新的IV。 Usually, CBC IVs are generated randomly. 通常,CBC IV是随机生成的。 Other modes like CFB and OFB require unique IVs for every message. 其他模式如CFB和OFB 需要为每条消息提供唯一的IV。 IVs are usually sent with along the ciphertext—IVs don't need to be kept secret, but many algorithms will break if a predictable IV is used. IV通常沿着密文发送 - IV不需要保密,但是如果使用可预测的IV,许多算法将会中断。

The server doesn't need to get the secret or IV directly from the phone. 服务器不需要直接从手机获取秘密或IV。 You can configure the server with the secret key (or password, from which the secret key is derived), but in many applications, this would be a bad design. 可以使用密钥(或密码,从中派生密钥)配置服务器,但在许多应用程序中,这将是一个糟糕的设计。

For example, if the application is going to be deployed to the phones of multiple people, it isn't a good idea for them to use the same secret key. 例如,如果将应用程序部署到多个人的电话上,那么他们使用相同的密钥并不是一个好主意。 One malicious user can recover the key and break the system for everyone. 一个恶意用户可以恢复密钥并为每个人破坏系统。

A better approach is to generate new secret keys at the phone, and use a key agreement algorithm to exchange the key with the server. 更好的方法是在电话上生成新的密钥,并使用密钥协商算法与服务器交换密钥。 Diffie-Hellman key agreement can be used for this, or the secret key can be encrypted with RSA and sent to the server. Diffie-Hellman密钥协议可以用于此,或者密钥可以用RSA加密并发送到服务器。


Update: 更新:

Diffie-Hellman in "ephemeral-static" mode (and "static-static" mode too, though that's less desirable) is possible without an initial message from the server to the phone, as long as the server's public key is embedded in the application. 只要服务器的公钥嵌入应用程序中,Diffie-Hellman处于“短暂 - 静态”模式(以及“静态 - 静态”模式,尽管不太理想)也可以在没有从服务器到电话的初始消息的情况下实现。 。

The server public key doesn't pose the same risk as embedding a common secret key in the phone. 服务器公钥与在电话中嵌入公共密钥的风险不同。 Since it is a public key, the threat would be an attacker getting his hands on (or remotely hacking into) the phone and replacing the real public key with a fake key that allows him to impersonate the server. 由于它是一个公钥,威胁将是攻击者接触(或远程入侵)手机并用假密钥替换真正的公钥,允许他冒充服务器。

Static-static mode could be used, but it's actually more complicated and a little less secure. 可以使用静态静态模式,但实际上它更复杂,安全性稍差。 Every phone would need its own unique key pair, or you fall back into the secret key problem. 每部手机都需要自己独特的密钥对,否则您会回到密钥问题中。 At least there would be no need for the server to keep track of which phone has which key (assuming there is some authentication mechanism at the application level, like a password). 至少不需要服务器跟踪哪个电话具有哪个密钥(假设在应用程序级别存在一些认证机制,如密码)。

I don't know how fast phones are. 我不知道手机有多快。 On my desktop, generating an ephemeral key pair takes about 1/3 of a second. 在我的桌面上,生成一个短暂的密钥对大约需要1/3秒。 Generating Diffie-Hellman parameters is very slow; 生成Diffie-Hellman参数非常慢; you'd definitely want to re-use the parameters from the server key. 你肯定想重新使用服务器密钥中的参数。

Done similar projects in a midlet before, I have following advice for you: 之前在midlet做过类似的项目,我有以下建议:

  1. There is no secure way to store shared secret on the phone. 没有安全的方法来存储手机上的共享密钥。 You can use it but this falls into a category called Security through Obscurity . 您可以使用它,但这属于一个名为Security through Obscurity的类别。 It's like a "key under mat" kind of security. 这就像是一种“垫下密钥”的安全性。
  2. Don't use 256-bit AES, which is not widely available. 不要使用256位AES,因为它没有广泛使用。 You might have to install another JCE. 您可能必须安装另一个JCE。 128-bit AES or TripleDES are still considered secure. 128位AES或TripleDES仍然被认为是安全的。 Considering #1, you shouldn't worry about this. 考虑到#1,你不应该担心这一点。
  3. Encryption using a password (different for each user) is much more secure. 使用密码加密(每个用户不同)更加安全。 But you shouldn't use password as the key like you are showing in the example. 但是你不应该像在示例中那样使用密码作为密钥。 Please use PBEKeySpec (password-based encryption) to generate the keys. 请使用PBEKeySpec(基于密码的加密)生成密钥。
  4. If you are just worried about MITM (man-in-the-middle) attacks, use SSL. 如果您只是担心MITM(中间人)攻击,请使用SSL。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM