java - AESWrap 和 to-wrap-key 长度长度/填充问题

标签 java encryption aes

我需要用 AESWrap 包装私有(private)值。由于我的私有(private)值字符串(要包装的 key )的长度,我对此操作遇到问题。

这是我的实现:

final byte[] kek = // ... generate SHA-256 key via `PBKDF2WithHmacSHA256`        
SecretKey sKey = new SecretKeySpec(kek, "AES");

Cipher c = Cipher.getInstance("AESWrap", "SunJCE");
c.init(Cipher.WRAP_MODE, sKey);

byte[] bytes = privateValue.getBytes();
SecretKeySpec wk = new SecretKeySpec(bytes, "AES");
byte[] result = c.wrap(wk);

由于 SunJCE 提供程序不支持任何 key 包装填充,因此私有(private)值应该是 8 字节的倍数,这是我需要解决的问题。

问题:当私有(private)值长度不够时如何解决这种情况。有一些推荐的方法如何自己进行填充吗?

附注我想避免像 BC 等外部库。


关于@Maarten的回答,我创建了这个实现。它可以工作(它成功地包装和解开我的私有(private)值),但是这个实现安全吗?

换行

byte[] salt = .... // 32 random bytes...
byte[] kek = ... // PBKDF2WithHmacSHA256 hash from private value and salt

SecretKey sKey = new SecretKeySpec(kek, "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");

SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[c.getBlockSize()];
rng.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);

c.init(Cipher.WRAP_MODE, sKey, iv);
SecretKeySpec wk = new SecretKeySpec(privateValue.getBytes(), "AES");
byte[] result = c.wrap(wk); // wrapped private value

展开

byte[] kek = ... // PBKDF2WithHmacSHA256 hash from private value and previous salt

SecretKey sKey = new SecretKeySpec(kek, "AES");
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");

IvParameterSpec iv = new IvParameterSpec(parsed.getIv()); // previously created iv
c.init(Cipher.UNWRAP_MODE, sKey, iv);

SecretKeySpec wk = new SecretKeySpec(privateValue.getBytes(), "AES");
Key result = c.unwrap(parsed.getKey(), "AES", Cipher.SECRET_KEY);

byte[] pv = result.getEncoded(); // unwrapped private value

最佳答案

可以使用正常的操作模式,而不是 AES 的专用填充模式。填充模式更好,但只需 CBC 和 PKCS#7 填充就足够了。

明智的做法是使用 IV 并将其与包装的 key 一起存储。私钥通常不仅仅是二进制数据,而且具有结构,如果以这种方式包装多个 key ,则可能会泄漏一点点信息。对于 RSA,随机模数位于私有(private)指数/CRT 参数之前,因此 IV 为零也应该是安全的。

// --- key pair with private key for testing
KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
gen.initialize(4096);
KeyPair kp = gen.generateKeyPair();

// --- create KEK
final byte[] kek = new byte[16]; // test value
SecretKey sKey = new SecretKeySpec(kek, "AES");

// --- the cipher, not a special wrapping algorithm
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");

// --- create IV
// not really necessary because the modulus comes first, but nicer
SecureRandom rng = new SecureRandom();
byte[] ivBytes = new byte[c.getBlockSize()];
rng.nextBytes(ivBytes);
IvParameterSpec iv = new IvParameterSpec(ivBytes);

// --- init & wrap by normal encryption
c.init(Cipher.WRAP_MODE, sKey, iv);
byte[] result = c.wrap(kp.getPrivate());

AES-SIV 会更好,但这不包含在 SunJCE 提供程序中。您可以使用 AES-GCM 来宣传完整性,但请注意,为此重复 12 字节 IV(随机数)对于该模式可能会造成灾难性的后果。

关于java - AESWrap 和 to-wrap-key 长度长度/填充问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50318355/

相关文章:

java - 处理 Java 加密异常

Java PBE 加密字符串长度与输入相同

java - 如何在 Python 中指定 AES key ?

java - 使用 NetBeans 生成的 dist jar 中的错误字符编码

java - Hibernate:如何从 Hibernate 测试套件开始单个测试?

java - Netbeans:安装 IMlet 时出错....模拟器错误

php mcrypt_encrypt 到 C/C++/MFC equalivilent

java - 尽管我有权访问该文件,但 Files.isExecutable(...) 给出 false

java - 在 Java 中使用 PBEWithHmacSHA256AndAES_256 加密要存储在文件中的密码

ffmpeg - 如何使用 ffmpeg 加密 AES-128 HLS m3u8 播放列表?