EPr*_*und 17 c# delphi encryption bouncycastle
也许我的期望是错的.我不是加密专家,我只是一个简单的用户.到目前为止,我已经详尽地试图使这项工作取得成功.
背景资料:
我正在尝试从Delphi Encryption Compendium移植Legacy Encryption,它使用Blowfish Engine(TCipher_Blowfish_)和CTS操作模式(cmCTS).私钥由RipeMD256(THash_RipeMD256)进行哈希处理.
问题:
输入纯文本字节数组的大小必须相同CIPHER_BLOCK.据我所知,它不应该.
来自维基百科:
在密码学中,密文窃取(CTS)是使用分组密码操作模式的一般方法,其允许处理不可均分成块的消息而不会导致密文的任何扩展,代价是稍微增加了复杂性.
输出与旧例程不同:
我正在使用:
遗留应用程序使用ANSI String,新的使用Unicode,因此对于我调用的每个输入字符串Encoding.ASCII.GetBytes("plainText"),Encoding.ASCII.GetBytes("privatepassword").
然后由RipeMD256对私有密码字节进行散列,我检查了输出字节,它们是相同的.
我可以确认问题在Bouncy Clastle(操作模式或缺少配置/步骤)中是特定的,因为我已经下载了第二个库Blowfish.cs并使用8字节的输入(与密码块大小相同)并使用Encrypt_CBC(bytes[])with相同的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;
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
我假设如果输入长度为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
Run Code Online (Sandbox Code Playgroud)
正如我所说,我将CBC与CTS进行比较,假设给定8字节输入,输出将是相同的.如果使用相同的输入输出不相同,我无法使用Bouncy Castle转发实现.
我不知道:
Cod*_*ler 14
我假设如果输入长度为8位,CTS和CBC将始终具有相同的结果.这只是幸运/巧合还是从根本上说是真理?
不,这是一个错误的陈述.
以下是维基百科的引用:
用于CBC模式的密文窃取不一定要求明文长于一个块.在明文是一个块长或更短的情况下,初始化矢量(IV)可以用作先前的密文块.
因此,即使对于8字节输入的情况,CTS算法也会发挥作用并影响输出.基本上你关于CTS和CBS平等的陈述可以颠倒过来:
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));
}
Run Code Online (Sandbox Code Playgroud)
所以这基本上是你主要问题的答案.对于8字节输入,您不应期望CTS和CBC具有相同的输出.
以下是您对其他问题的答案(我希望如此):
如果Delphi Encryption Compendium中使用的CTS模式使用CBC和CTS.我无法在任何地方找到记录.
我还没有在Delphi Encryption Compendium中找到任何CTS模式的文档,但是在源代码中有这样的注释:
cmCTSx =双CBC,具有截断的最终块的CFS8填充
模式cmCTSx,cmCFSx,cmCFS8是我开发的专有模式.这些模式的工作原理如cmCBCx,cmCFBx,cmCFB8,但输入流的双XOR输入反馈寄存器.
因此,似乎CTS模式是在Delphi Encryption Compendium中以自定义方式实现的,这与Bouncy Castle的标准实现不兼容.
在Bouncy Castle中调用DoFinal()和ProcessBytes()然后调用DoFinal()之间的区别,我想当输入块大于引擎块大小时需要它,在这种情况下它们是相同的大小.
如果按顺序加密数据,则需要调用pair ProcessBytes()/ DoFinal().例如,如果流式传输大量数据,则可能需要它.但是,如果你有一个例程,它需要整个字节数组进行加密,你可以调用DoFinal()一次方便的重载:
var encryptedData = inCipher.DoFinal(plainText);
Run Code Online (Sandbox Code Playgroud)
这种DoFinal()过载将计算的输出缓冲区的大小,使所需的呼叫ProcessBytes()和DoFinal() 引擎盖下.
如果Delphi Encryption Compendium是正确/错误或者如果Bouncy Castle是正确/错误的.我没有足够的密码学知识来理解实现,否则我不会在这里问一个问题(我需要指导).
我们在这里总结一下:
UPDATE
(有关3.0版Delphi Encryption Compendium实现的更多详细信息)
这是来自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;
Run Code Online (Sandbox Code Playgroud)
在这里,我们看到DEC文档中提到的双XOR'ing.基本上这段代码实现了以下算法:
C[i] = Encrypt( P[i] xor F[i-1] )
F[i] = F[i-1] xor C[i]
F[0] = IV
Run Code Online (Sandbox Code Playgroud)
而标准算法将是:
C[i] = Encrypt( P[i] xor C[i-1] )
C[0] = IV
Run Code Online (Sandbox Code Playgroud)
该步骤F[i] = F[i-1] xor C[i]是DEC作者发明并使加密结果不同.对CTS模式至关重要的最后两个块的处理也不是通过标准实现的.
以下是DEC v 3.0 ReadMe.txt的评论,该评论描述了作者添加此类修改的原因:
cmCTS模式,XOR是加密之前和之后的数据.使用InitVector时,这具有更好的Securityeffect,当使用错误的InitVector时输出是安全的,ca 1%速度损失
当安全库的作者试图通过这种天真的修改使底层算法"更安全"时,这是一个非常常见的错误.在许多情况下,这种变化具有相反的效果并降低保护强度.当然,另一个缺点是加密数据无法通过根据标准实现的其他库解密,就像您的情况一样.