如何使用CBC实现Java 256位AES加密 [英] How to implement Java 256-bit AES encryption with CBC

查看:155
本文介绍了如何使用CBC实现Java 256位AES加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了以下内容,他们已经帮助了一点,但我正在寻找更多的信息。



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



Java 256bit AES加密



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



我正在开发的应用程序是一部电话,所以我想使用java安全软件包来保持大小。我完成了设计,但不确定IV和共享密钥的实现。



以下是一些代码:

  //我的用户名
byte [] loginId =login.getBytes();

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

//初始化向量
//需要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);

// SecretKeySpec为Java Crypto类消费的加密密钥提供了特定于应用程序的生成机制
//。

//根据我们的关键输入,首先创建一个密钥规范。
SecretKey aesKey = new SecretKeySpec(encodedKey,AES);

//使用我们创建的密钥创建加密数据的密码。
密码加密密码;

encryptCipher = Cipher.getInstance(AES / CBC / PKCS5Padding);
//用密钥和参数初始化密码
encryptCipher.init(Cipher.ENCRYPT_MODE,aesKey,ips);

//我们的明文
String clearString =33,8244000,9999,411,5012022517,0.00,0,1,V330;
byte [] cleartext = clearString.getBytes();

//加密明文
byte [] ciphertext = encryptCipher.doFinal(cleartext);

//现在再次解密...
//解密密码
密码解密Cipher = Cipher.getInstance(AES / CBC / PKCS5Padding);
//用键和参数初始化PBE密码
decryptCipher.init(Cipher.DECRYPT_MODE,aesKey,ips);

//解密cleartext
byte [] deciphertext = decryptCipher.doFinal(ciphertext);

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

解决方案

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



即使您要进行基于密码的加密,密码也应该通过密钥推导算法运行,以生成密钥,如我的回答您已经引用的问题。



此外,您不应该使用 String 的no-arg getBytes()方法。这是平台依赖的。如果您编码的所有字符串仅包含US-ASCII字符集中的字符,请通过明确指定该编码来清除。否则,如果电话和服务器平台使用不同的字符编码,则键和IV将不会相同。



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



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



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



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






<更新:



Diffie-Hellman在临时静态模式(和静态模式下,虽然这不太可取),只要服务器的公共密钥嵌入到应用程序中,就可能没有从服务器到手机的初始消息。



服务器公钥并不构成在手机中嵌入公用密钥的风险。由于它是一个公共密钥,威胁将是一个攻击者手中(或远程黑客入侵)手机,并用假钥匙替换真正的公钥,允许他假冒服务器。



可以使用静态模式,但实际上更复杂,安全性更低。每个手机都需要自己独特的密钥对,或者你回到秘密的关键问题。至少不需要服务器跟踪哪个电话具有哪个密钥(假设在应用程序级别有一些认证机制,如密码)。



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


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

Java 256bit AES Encryption

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.

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.

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.

解决方案

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. 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.

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 require unique 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.

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


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.

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.

这篇关于如何使用CBC实现Java 256位AES加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆