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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1440030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 12:17:27  来源:igfitidea点击:

How to implement Java 256-bit AES encryption with CBC

javaencryptionaes

提问by Steven

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 256 位 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. The encryption will need to be AES, and doing some research I found out I need to use CBC and PKCS5Padding. So basically I need a secret key and an IV as well.

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

The application I'm developing is for a phone, so I want to use the java security packages to keep the size down. I've got the design done, but unsure of the implementation of the IV and the shared key.

我正在开发的应用程序是用于手机的,所以我想使用 java 安全包来减小大小。我已经完成了设计,但不确定 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. 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? Feel free to tell me to make things more clear if they're not.

简而言之,它应该做的是加密一些可以由服务器解密的消息,而无需服务器从手机获取密钥或 IV。有没有办法做到这一点,我可以保护手机上的 IV 和密钥,并且服务器仍然知道密钥和 IV?如果不是这样,请随时告诉我让事情更清楚。

采纳答案by erickson

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 answerto the question that you cited already.

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

Also, you shouldn't use the no-arg getBytes()method of String. 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. Otherwise, if the phone and server platforms use different character encodings, the key and IV won't turn out the same.

此外,你不应该使用的无参数getBytes()的方法String。这是平台相关的。如果您编码的所有字符串仅包含来自 US-ASCII 字符集中的字符,请通过明确指定该编码来明确说明。否则,如果手机和服务器平台使用不同的字符编码,key 和 IV 将不会相同。

For CBC mode, it's best to use a new IV for every message you send. Usually, CBC IVs are generated randomly. Other modes like CFB and OFB requireunique IVs for every message. 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.

对于 CBC 模式,最好为您发送的每条消息使用新的 IV。通常,CBC IV 是随机生成的。其他模式(如 CFB 和 OFB)要求每条消息具有唯一的 IV。IV 通常与密文一起发送——IV 不需要保密,但如果使用可预测的 IV,许多算法就会失效。

The server doesn't need to get the secret or IV directly from the phone. You canconfigure 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.

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

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. Generating Diffie-Hellman parameters is very slow; you'd definitely want to re-use the parameters from the server key.

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

回答by ZZ Coder

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. It's like a "key under mat" kind of security.
  2. Don't use 256-bit AES, which is not widely available. You might have to install another JCE. 128-bit AES or TripleDES are still considered secure. Considering #1, you shouldn't worry about this.
  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.
  4. If you are just worried about MITM (man-in-the-middle) attacks, use SSL.
  1. 没有在手机上存储共享秘密的安全方法。您可以使用它,但这属于名为Security through Obscurity的类别。这就像“垫子下的钥匙”一样的安全性。
  2. 不要使用未广泛使用的 256 位 AES。您可能需要安装另一个 JCE。128 位 AES 或 TripleDES 仍然被认为是安全的。考虑到#1,你不应该担心这个。
  3. 使用密码(每个用户不同)进行加密要安全得多。但是您不应该像示例中显示的那样使用密码作为密钥。请使用 PBEKeySpec(基于密码的加密)来生成密钥。
  4. 如果您只是担心 MITM(中间人)攻击,请使用 SSL。