也许我的期望是错误的。我不是密码学专家,我只是一个简单的用户。我已经尽了最大的努力使这项工作,但到目前为止还没有成功。
背景资料:
我正在尝试从Delphi Encryption Compendium移植一个遗留加密,它使用Blowfish引擎(TCIpher_Blowfish_
)和CTS操作模式(CMCTS
)。私钥由RipeMD256散列(thash_RIPEMD256
)。
输入的纯文本字节数组需要与cipher_block
的大小相同。据我所知不应该。
来自维基百科:
在密码学中,密文窃取(CTS)是使用分组密码操作模式的一种通用方法,它允许处理不能均匀地分割成块的消息,而不会导致密文的任何扩展,代价是略微增加复杂性。
我正在使用:
旧的应用程序使用ANSI字符串,新的应用程序使用Unicode,因此对于每个输入字符串,我都调用encoding.ascii.getBytes(“plaintext”)
、encoding.ascii.getBytes(“privatePassword”)
。
私有密码字节然后由RipeMD256散列,我检查了输出字节,它们是相同的。
我可以确认该问题是在Bouncy Clastle(操作模式或缺少配置/步骤)中出现的,因为我下载了第二个库blowfish.cs,并且使用了8字节的输入(与密码块大小相同),并且使用了encrypt_cbc(bytes[])
,其IV结果与旧格式的输出相同。
这是我用于blowfish.cs
和bouncy castle
的代码草图:
var
IV: Array [0..7] of Byte (1,2,3,4,5,6,7,8);
Key: String = '12345678';
with TCipher_Blowfish.Create('', nil) do
begin
try
InitKey(Key, @IV); //Key is auto hashed using RIPE256 here;
Result:= CodeString('12345678', paEncode, -1); //Output bytes is later encoded as MIME64 here, the result is the hash.
finally
Free;
end;
end;
var hashOfPrivateKey = HashValue(Encoding.ASCII.GetBytes("12345678"));
Blowfish b = new BlowFish(hashOfPrivateKey);
b.IV = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8};
var input = Encoding.ASCII.GetBytes("12345678");
var output = b.Encrypt_CBC(input);
我假设如果输入长度为8位,那么CTS和CBC的结果总是相同的。这仅仅是幸运/巧合还是根本上是事实?
IBufferedCipher inCipher = CipherUtilities.GetCipher("BLOWFISH/CTS");
var hashOfPrivateKey = HashValue(Encoding.ASCII.GetBytes("12345678"));
var key = new KeyParameter(hashOfPrivateKey);
var IV = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8};
var cipherParams = new ParametersWithIV(key, IV);
inCipher.Init(true, cipherParams);
var input = Encoding.ASCII.GetBytes("12345678");
//try one: direct with DoFinal
var output = inCipher.DoFinal(input);
// output bytes different from expected
inCipher.Reset();
//try two: ProcessBytes then DoFinal
var outBytes = new byte[input.Length];
var res = inCipher.ProcessBytes(input, 0, input.Length, outBytes, 0);
var r = inCipher.DoFinal(outBytes, res);
// outBytes bytes different from expected
正如我所说的,我比较CBC和CTS的前提是,给定8个字节的输入,输出将是相同的。如果即使有相同的输入,输出也不相同,我也不能用Bouncy Castle转发实现。
我假设如果输入长度为8位,那么CTS和CBC的结果总是相同的。这仅仅是幸运/巧合还是根本上是事实?
不,这是假的说法。
以下是维基百科中的一段话:
static byte[] EncryptData(byte[] input, string algorithm)
{
IBufferedCipher inCipher = CipherUtilities.GetCipher(algorithm);
var hashOfPrivateKey = HashValue(Encoding.ASCII.GetBytes("12345678"));
var key = new KeyParameter(hashOfPrivateKey);
var IV = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 };
var cipherParams = new ParametersWithIV(key, IV);
inCipher.Init(true, cipherParams);
return inCipher.DoFinal(input);
}
static void Main(string[] args)
{
var data = Encoding.ASCII.GetBytes("0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF");
var ctsResult = EncryptData(data, "BLOWFISH/CTS");
var cbcResult = EncryptData(data, "BLOWFISH/CBC");
var equalPartLength = data.Length - 2 * 8;
var equal = ctsResult.Take(equalPartLength).SequenceEqual(cbcResult.Take(equalPartLength));
}
所以这基本上是你主要问题的答案。您不应该期望8字节输入的CTS和CBC输出相同。
以下是你其他问题的答案(我希望):
如果Delphi加密简编中使用的CTS模式与CTS一起使用CBC。我到处都找不到文件。
这样看来CTS模式在Delphi加密简编中是以自定义的方式实现的,与Bouncy Castle的标准实现不兼容。
在Bouncy Castle中只调用DoFinal()和ProcessBytes()然后调用DoFinal()之间的区别,我想这是当输入块大于引擎块大小时需要的,在本例中,它们的大小相同。
如果按顺序加密数据,则需要调用对processBytes()
/DoFinal()
。例如,如果流式传输庞大的数据,则可能需要这样做。但是,如果您的例程采用整个字节数组进行加密,则只需调用dofinal()
的以下方便重载一次:
var encryptedData = inCipher.DoFinal(plainText);
此doFinal()
重载将计算输出缓冲区的大小,并在Hood下调用processBytes()
和doFinal()
。
如果Delphi加密简编是正确的/错误的,或者如果Bouncy Castle是正确的/错误的。我在密码学方面没有足够的知识来理解实现,否则我不会在这里提出一个问题(我需要指导)。
这里总结一下:
更新
(关于3.0版中Delphi加密简编实现的更多细节)
下面是DEC 3.0版的CTS编码代码:
S := @Source;
D := @Dest;
// ...
begin
while DataSize >= FBufSize do
begin
XORBuffers(S, FFeedback, FBufSize, D);
Encode(D);
XORBuffers(D, FFeedback, FBufSize, FFeedback);
Inc(S, FBufSize);
Inc(D, FBufSize);
Dec(DataSize, FBufSize);
end;
if DataSize > 0 then
begin
Move(FFeedback^, FBuffer^, FBufSize);
Encode(FBuffer);
XORBuffers(S, FBuffer, DataSize, D);
XORBuffers(FBuffer, FFeedback, FBufSize, FFeedback);
end;
end;
这里我们看到DEC文档中提到的双异或。基本上,这段代码实现了以下算法:
C[i] = Encrypt( P[i] xor F[i-1] )
F[i] = F[i-1] xor C[i]
F[0] = IV
而标准算法是:
C[i] = Encrypt( P[i] xor C[i-1] )
C[0] = IV
下面是DEC v 3.0 Readme.txt的注释,它描述了作者为什么要添加这样的修改:
cmCTS模式,对加密前和加密后的数据进行异或。当使用InitVector时,这具有更好的安全性,当使用错误的InitVector时,输出是安全的,会损失1%的速度
当安全库的作者试图通过这种幼稚的修改来使底层算法“更安全”时,这是一个非常常见的错误。在许多情况下,这种变化具有相反的效果并降低保护强度。当然,另一个缺点是加密的数据不能被根据标准实现的其他库解密,就像您的情况一样。
我使用的是角反应形式。在表单组的窗体控件中,我使用无法正常工作的正则表达式设置了验证器.模式,我不明白为什么。我已经验证了这个网站上的正则表达式 https://www.regextester.com/99144,以检查它,它工作正常 正则表达式(最少八个字符,至少一个大写字母,一个小写字母,一个数字和一个特殊字符) 这是表单组 因此,当我键入“World@20”时,它验证为真,但当我开始键入“W
我正在使用spring Roo并希望访问Controller类中的一个bean,该类在ApplicationContext.xml中具有以下配置: 配置类本身是: 在我的Controller中,我认为一个简单的Autowired注释应该可以完成这项工作 在启动过程中,spring在setSkipWeeks方法中打印消息。不幸的是,每当我在控制器中调用config.getSkipWeeks()时,它
当我运行以下程序时,它只打印 然而,从Java 8的equalsIgnoreCase文档中我们发现: 如果以下至少一项为真,则两个字符c1和c2被视为相同的忽略情况: •对每个字符应用java.lang.character.ToUpperCase(char)方法会产生相同的结果 所以我的问题是为什么这个程序不打印 在这两种操作中,都使用了大写字符。
我试图使用来传输我根据前面的问题设置的自定义标头。 我在文件中读到... 我的属性包括:
我正在和selenium一起工作,刮一些数据。 有一个按钮在页面上,我正在点击说“Custom_Cols”。这个按钮为我打开了一个窗口,我可以在那里选择我的列。 我的问题是为什么新窗口上的元素不可见,即使我正在等待元素的可见。补充一下,我已经尝试增加延迟时间,但我还是会偶尔出现这个错误。 我的密码在这里