我需要用AESWrap
包装私有值。我有这个操作的问题,因为我的私有值字符串的长度(要包装的键)。
这是我的实施:
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
提供程序不支持密钥包装的任何填充,因此私有值应该是8字节的倍数,这是我需要解决的问题。
问题:如果私有值长度不够,如何解决这种情况。是否有一些推荐的方法如何自己填充?
P.S。我想避免使用BC等外部库。
关于@ Maarten的回答,我创建了这个实现。它有效(它成功地包装和解开我的私人价值),但这个实现安全?
包装
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
答案 0 :(得分:3)
可以使用正常操作模式而不是AES的专用填充模式。填充模式更好,但只有带有PKCS#7填充的CBC也应该足够了。
使用IV并将其与包装的密钥一起存储是明智的。私钥通常不仅仅是二进制数据,而且具有结构,如果以这种方式包装多个密钥,您可能会泄漏一小部分信息。对于RSA,随机模数在私有指数/ 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(nonce)对于该模式可能是灾难性的。