java - 即使输入弹簧长度变化,也产生具有固定长度的 AES 加密输出结果
问题描述
我有一个名为 user.that 的表,它有一列 firstName varchar(25)。
使用 AES 算法插入时,我正在加密名字值。(AES/CBC/PKCS5Padding)
但是每次我加密名字值时,我都没有得到具有相同长度的输出值(加密)。当名字值字符串长度变化时,加密输出长度不适合为列定义的 varchar 长度。
字符串输入=“测试”;//加密值:978fbfa24962827da56b1f00896a4f2cbfc25b744e836c2a22d4292fb16dd53a
String input = "这是测试"; //加密值:978fbfa24962827da56b1f00896a4f2cbfc25b744e836c22a22d4292fb16dd53aa22d4292fb16dd53a
我得到以下异常。
数据截断:数据对于列来说太长
我在这里添加了我的代码。
public String encrypt(String plainText) {
byte[] cipherBytes = null;
log.info("Started encryption...");
if (plainText != null && !plainText.isEmpty()) {
if (cipher != null && key != null) {
try {
byte[] ivByte = new byte[cipher.getBlockSize()];
IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
cipher.init(Cipher.ENCRYPT_MODE, key, ivParamsSpec);
cipherBytes = cipher.doFinal(plainText.getBytes());
plainText = Hex.encodeHexString(cipherBytes);
log.info("Completed encryption.");
log.info("Encrypted data : "
+ new String(cipherBytes, "UTF8"));
} catch (BadPaddingException | IllegalBlockSizeException
| InvalidKeyException
| InvalidAlgorithmParameterException
| UnsupportedEncodingException e) {
log.error("Encryption failed : " + e.getMessage());
e.printStackTrace();
throw new RuntimeException("Encryption failed : "
+ e.getMessage());
}
} else {
log.error("Encryption failed, cipher, key is null.");
throw new RuntimeException(
"Encryption failed, cipher, key is null.");
}
} else {
return plainText;
}
return plainText;
}
public String decrypt(String cipherHexString) throws AuthorizationException {
log.info("Started decryption...");
byte[] plainTextBytes = null;
String resource = "kk";
String resourceCatagory = "kk tables";
String accessType = "write";
try {
if (decryptionAuthorizer.authorize(resource, resourceCatagory,
accessType)) {
if (cipherHexString != null && !cipherHexString.isEmpty()) {
if (cipher != null && key != null) {
try {
byte[] ivByte = new byte[cipher.getBlockSize()];
IvParameterSpec ivParamsSpec = new IvParameterSpec(
ivByte);
cipher.init(Cipher.DECRYPT_MODE, key, ivParamsSpec);
plainTextBytes = cipher.doFinal(Hex
.decodeHex(cipherHexString.toCharArray()));
cipherHexString = new String(plainTextBytes);
log.info("Completed decryption.");
} catch (InvalidKeyException
| InvalidAlgorithmParameterException
| IllegalBlockSizeException
| BadPaddingException | DecoderException e) {
log.error("Decryption failed : " + e.getMessage());
e.printStackTrace();
throw new RuntimeException("Decryption failed : "
+ e.getMessage());
}
} else {
log.error("Decryption failed, cipher, key is null.");
throw new RuntimeException(
"Decryption failed, cipher, key is null.");
}
} else {
return cipherHexString;
}
}
} catch (AuthorizationException e) {
throw new AuthorizationException(
"User not authorized to decrypt data.");
}
return cipherHexString;
}
/**
* This method is used to manually override max key length permission, as an
* application level solution instead of configuration changes in
* security.policy.
*/
private void fixKeyLength() {
String errorString = "Failed manually overriding key-length permissions.";
int newMaxKeyLength;
try {
newMaxKeyLength = javax.crypto.Cipher.getMaxAllowedKeyLength("AES");
log.info("Initial max key size for AES : " + newMaxKeyLength);
if (newMaxKeyLength < 256) {
Class c = Class
.forName("javax.crypto.CryptoAllPermissionCollection");
Constructor con = c.getDeclaredConstructor();
con.setAccessible(true);
Object allPermissionCollection = con.newInstance();
Field f = c.getDeclaredField("all_allowed");
f.setAccessible(true);
f.setBoolean(allPermissionCollection, true);
c = Class.forName("javax.crypto.CryptoPermissions");
con = c.getDeclaredConstructor();
con.setAccessible(true);
Object allPermissions = con.newInstance();
f = c.getDeclaredField("perms");
f.setAccessible(true);
((Map) f.get(allPermissions)).put("*", allPermissionCollection);
c = Class.forName("javax.crypto.JceSecurityManager");
f = c.getDeclaredField("defaultPolicy");
f.setAccessible(true);
Field mf = Field.class.getDeclaredField("modifiers");
mf.setAccessible(true);
mf.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.set(null, allPermissions);
newMaxKeyLength = Cipher.getMaxAllowedKeyLength("AES");
log.info("Max key size permission changed, new max key size for AES : "
+ newMaxKeyLength);
}
} catch (Exception e) {
throw new RuntimeException(errorString, e);
}
if (newMaxKeyLength < 256)
throw new RuntimeException(errorString);
}
public String getAlgo() {
return algo;
}
public void setAlgo(String algo) {
this.algo = algo;
}
public String getKeyAlias() {
return keyAlias;
}
有没有办法加密产生具有相同长度的输出,即使输入字符串值长度是变化的。所以我不明白
数据截断:数据对于列来说太长
解决方案
很明显,您不会得到相同长度的结果,因为对称加密的结果是加密算法块大小的倍数(在 和 等非流模式的情况下ECB
)CBC
。
在您的情况下,您有一个varchar(25)
,因此最大大小为 50 个字节长(每个varchar
为 2 个字节)。然后加密结果最大为 32 字节,因为您使用的AES
算法具有 16 字节长的块大小。
如果您必须具有相同的大小,则需要使用流模式,例如CTR
. 但我建议将列保持足够长的时间以将加密数据保持在CBC
模式中。
无论如何,您的加密结果太长了。我猜(只是猜测,因为没有足够的代码)从数据库中获取字符串后,将其编码为十六进制字符串,然后将其用于加密功能。这就是为什么你会得到一个很长的加密结果:
varchar("test") -> 8 bytes long -> 16 bytes hex string -> 32 bytes after encrypting (with padding) -> 64 bytes hex string
varchar("test is test") -> 24 bytes long -> 48 bytes hex string -> 64 bytes after encrypting (with padding) -> 128 bytes hex string
推荐阅读
- html - 在 HTML 代码中找不到项目的 ID
- sql - 如何在不使用 sql 中的限制子句的情况下获取过去 6 周的数据?
- string - 需要帮助使用 masm 以 80x86 汇编语言连接两个字符串
- google-sheets - 谷歌表格/excel在行中重复高值->索引列问题
- python - 有没有一种好方法可以将 python 中的一系列 def 函数与 Tkinter 一个接一个地运行?
- java - 将指定区域的长纪元时间转换为 UTC 中的长纪元时间
- sql - 计算 AWS Athena 表中每个组的中位数
- java - 在 Spring Boot RestController 中区分带有查询参数的端点与没有查询参数的端点
- python - 如何为某个用户打开一个窗口 discord.py
- python - 安装 EmoPY 要求的问题