使用带填充和块密码模式的散列
Using hashing with padding and blockcipher modes
我正在编写一个密码程序,并希望将几种密码块和流模式与散列机制一起使用。我在使用像 OFB 这样的流模式加密、解密和验证消息时没有任何问题,但是当他们使用填充时,我在使用 blockcipher moder 解密和验证消息时遇到问题。
例如,我将 ECB(我知道它不是很好)与 PKCS7Padding 和 SHA-256 一起使用。在我解密消息后,它的末尾有一些字符。除此之外,我收到消息,哈希摘要不等于原始摘要。
当我不使用填充时,不会发生此问题。
这是我的代码:
@Override
public byte[] encrypt(byte[] input) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/" + getPadding(), "BC");
cipher.init(Cipher.ENCRYPT_MODE, getKey());
byte[] output = getBytesForCipher(cipher, input);
int ctLength = cipher.update(input, 0, input.length, output, 0);
updateHash(input);
cipher.doFinal(getDigest(), 0, getDigest().length, output, ctLength);
return output;
}
protected byte[] getBytesForCipher(Cipher cipher, byte[] input) {
return new byte[cipher.getOutputSize(input.length + hash.getDigestLength())];
}
protected void updateHash(byte[] input) {
hash.update(input);
}
public byte[] decrypt(byte[] input) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/" + getPadding(), "BC");
cipher.init(Cipher.DECRYPT_MODE, getKey());
byte[] output = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, output, 0);
cipher.doFinal(output, ctLength);
return removeHash(output);
}
protected byte[] removeHash(byte[] output) {
int messageLength = output.length - hash.getDigestLength();
hash.update(output, 0, output.length - hash.getDigestLength());;
byte[] realOutput = new byte[messageLength];
System.arraycopy(output, 0, realOutput, 0, messageLength);
messageValid = isValid(output);
return realOutput;
}
private boolean isValid(byte[] output) {
int messageLength = output.length - hash.getDigestLength();
byte[] messageHash = new byte[hash.getDigestLength()];
System.arraycopy(output, messageLength, messageHash, 0, messageHash.length);
return MessageDigest.isEqual(hash.digest(), messageHash);
}
我正在使用 bouncycastle 提供商。
如果您查看 Cipher
的 getOutputSize
方法,您将从文档中获得以下内容:
The actual output length of the next update
or doFinal
call may be smaller than the length returned by this method.
而这正是困扰您的地方。由于密码实例无法确定解密前的填充量,因此它将假定输出/明文大小与明文大小相同。实际上,由于始终执行 PKCS#7 填充,因此在 JCE 实现中可能会假设多一个字节。
所以你不能忽略doFinal
的回复;您需要调整数组的大小(例如使用 Arrays
class)或从缓冲区中的正确位置获取明文和散列。
显然流密码不会有这个问题,因为明文大小和密文大小相同。
通常使用加密哈希(即 MAC 或 HMAC)或经过身份验证的密码来确保密文不被更改。在明文上使用哈希可能无法完全保护您的明文。
我正在编写一个密码程序,并希望将几种密码块和流模式与散列机制一起使用。我在使用像 OFB 这样的流模式加密、解密和验证消息时没有任何问题,但是当他们使用填充时,我在使用 blockcipher moder 解密和验证消息时遇到问题。
例如,我将 ECB(我知道它不是很好)与 PKCS7Padding 和 SHA-256 一起使用。在我解密消息后,它的末尾有一些字符。除此之外,我收到消息,哈希摘要不等于原始摘要。
当我不使用填充时,不会发生此问题。
这是我的代码:
@Override
public byte[] encrypt(byte[] input) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/" + getPadding(), "BC");
cipher.init(Cipher.ENCRYPT_MODE, getKey());
byte[] output = getBytesForCipher(cipher, input);
int ctLength = cipher.update(input, 0, input.length, output, 0);
updateHash(input);
cipher.doFinal(getDigest(), 0, getDigest().length, output, ctLength);
return output;
}
protected byte[] getBytesForCipher(Cipher cipher, byte[] input) {
return new byte[cipher.getOutputSize(input.length + hash.getDigestLength())];
}
protected void updateHash(byte[] input) {
hash.update(input);
}
public byte[] decrypt(byte[] input) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/" + getPadding(), "BC");
cipher.init(Cipher.DECRYPT_MODE, getKey());
byte[] output = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, output, 0);
cipher.doFinal(output, ctLength);
return removeHash(output);
}
protected byte[] removeHash(byte[] output) {
int messageLength = output.length - hash.getDigestLength();
hash.update(output, 0, output.length - hash.getDigestLength());;
byte[] realOutput = new byte[messageLength];
System.arraycopy(output, 0, realOutput, 0, messageLength);
messageValid = isValid(output);
return realOutput;
}
private boolean isValid(byte[] output) {
int messageLength = output.length - hash.getDigestLength();
byte[] messageHash = new byte[hash.getDigestLength()];
System.arraycopy(output, messageLength, messageHash, 0, messageHash.length);
return MessageDigest.isEqual(hash.digest(), messageHash);
}
我正在使用 bouncycastle 提供商。
如果您查看 Cipher
的 getOutputSize
方法,您将从文档中获得以下内容:
The actual output length of the next
update
ordoFinal
call may be smaller than the length returned by this method.
而这正是困扰您的地方。由于密码实例无法确定解密前的填充量,因此它将假定输出/明文大小与明文大小相同。实际上,由于始终执行 PKCS#7 填充,因此在 JCE 实现中可能会假设多一个字节。
所以你不能忽略doFinal
的回复;您需要调整数组的大小(例如使用 Arrays
class)或从缓冲区中的正确位置获取明文和散列。
显然流密码不会有这个问题,因为明文大小和密文大小相同。
通常使用加密哈希(即 MAC 或 HMAC)或经过身份验证的密码来确保密文不被更改。在明文上使用哈希可能无法完全保护您的明文。