也许我的期望是错误的。我不是密码学专家,我只是一个普通用户。到目前为止,我已经竭尽全力地尝试使这项工作成功。
背景信息:
我正在尝试从使用 Blowfish 引擎 (TCipher_Blowfish_) 和 CTS 操作模式 (cmCTS) 的 Delphi Encryption Compendium 移植旧版加密。私钥通过RipeMD256(THash_RipeMD256)散列。
问题:
输入的纯文本字节数组需要与 CIPHER_BLOCK 大小相同。据我所知,它不应该。
来自维基百科:
In cryptography, ciphertext stealing (CTS) is a general method of using a block cipher mode of operation that allows for processing of messages that are not evenly divisible into blocks without resulting in any expansion of the ciphertext, at the cost of slightly increased complexity.
输出与老套路不一样:
我正在使用:
旧应用程序使用 ANSI 字符串,新应用程序使用 Unicode,因此对于我调用的每个输入字符串 Encoding.ASCII.GetBytes("plainText"),Encoding.ASCII .GetBytes("privatepassword").
然后用 RipeMD256 对私有(private)密码字节进行哈希处理,我检查了输出字节,它们是相同的。
我可以确认问题在 Bouncy ClaSTLe 中是特定的(操作模式或缺少配置/步骤),因为我已经下载了第二个库 Blowfish.cs 并使用了 8 字节的输入(与密码 block 大小相同)并使用了具有相同 IV 的 Encrypt_CBC(bytes[]) 产生与旧格式相同的输出。
这是我用于 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);
I assume that CTS and CBC will always have the same result if the input is 8 bits length. Is this just lucky/coincidence or is fundamentally truth?
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 转发实现。
我不知道:
最佳答案
I assume that CTS and CBC will always have the same result if the input is 8 bits length. Is this just lucky/coincidence or is fundamentally truth?
不,这是一个错误的陈述。
这是来自 Wikipedia 的引述:
Ciphertext stealing for CBC mode doesn't necessarily require the plaintext to be longer than one block. In the case where the plaintext is one block long or less, the Initialization vector (IV) can act as the prior block of ciphertext.
因此,即使对于 8 字节输入的情况,CTS 算法也会发挥作用并影响输出。基本上你关于 CTS 和 CBS 平等的陈述可以颠倒过来:
CTS and CBC will always have the same result up to last two blocks.
您可以使用以下示例进行验证:
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));
}
所以这基本上就是您主要问题的答案。您不应该期望 CTS 和 CBC 在 8 字节输入上有相同的输出。
以下是您其他问题的答案(我希望如此):
If the CTS Mode used in Delphi Encryption Compendium uses CBC along with CTS. I Couldn't find documented anywhere.
我也没有在 Delphi Encryption Compendium 中找到任何关于 CTS 模式的文档,但是在 source code 中有这样的评论:
cmCTSx = double CBC, with CFS8 padding of truncated final block
Modes cmCTSx, cmCFSx, cmCFS8 are proprietary modes developed by me. These modes works such as cmCBCx, cmCFBx, cmCFB8 but with double XOR'ing of the inputstream into Feedback register.
所以 CTS 模式似乎是在 Delphi Encryption Compendium 中以自定义方式实现的,这与 Bouncy CaSTLe 的标准实现不兼容。
The difference between calling just DoFinal() and ProcessBytes() then DoFinal() in Bouncy Castle, I imagine that is required when the input block is larger than engine block size, in this case they are the same size.
如果您按顺序加密数据,则需要调用对 ProcessBytes()/DoFinal()。例如,如果流式传输大量数据,则可能需要它。但是,如果您有一个采用整个字节数组进行加密的例程,您可以只调用以下方便的 DoFinal() 重载一次:
var encryptedData = inCipher.DoFinal(plainText);
此 DoFinal() 重载将计算输出缓冲区的大小并进行所需的 ProcessBytes() 和 DoFinal() under the hood 调用。
If Delphi Encryption Compendium is correct/wrong or If Bouncy Castle is correct/wrong. I don't have enough knowledge in cryptography to understand the implementation, otherwise I wouldn't ask a question here (I need guidance).
总结一下:
更新
(有关 Delphi Encryption Compendium 在 3.0 版中实现的更多详细信息)
这是来自 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
步骤F[i] = F[i-1] xor C[i]是DEC作者发明的,使得加密结果不同。对于 CTS 模式至关重要的最后两个 block 的处理也不是通过标准实现的。
这是来自 DEC v 3.0 ReadMe.txt 的评论,描述了作者添加此类修改的原因:
cmCTS Mode, XOR's the Data before and now after the encryption. This has better Securityeffect when using a InitVector, the Output is secure when a bad InitVector is used, ca 1% Speed lossed
当安全库的作者试图通过这种幼稚的修改使底层算法“更安全”时,这是一个非常常见的错误。在许多情况下,此类更改会产生相反的效果并降低保护强度。 当然,另一个缺点是加密数据无法被根据标准实现的其他库解密,就像您的情况一样。
关于c# - Blowfish 引擎的 Bouncy CaSTLe CTS 模式未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42249867/
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request
在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL