1

ECMA-376 规范的第 1 部分 (参见 18.3.1.85 sheetProtection)详细说明了以下三个属性,以生成用于工作表保护的密码哈希:

算法名称

(默认为 SHA-1)

盐值

指定在使用上述属性值定义的散列算法对其进行散列以生成 hashValue 属性之前添加到用户提供的密码之前的盐,并且在尝试生成散列之前也应将其添加到用户提供的密码比较值。

自旋计数

当尝试比较用户提供的密码,其值存储在 hashValue 属性中。

我希望这样的工作:

def hash_password(v)
  require 'digest/sha1'
  spin_count = 10
  salt_value = Digest::SHA1.hexdigest(rand(36**8).to_s(36))
  salty = salt_value + v
  hash_value = nil
  spin_count.times do |count|
    hash_value = Digest::SHA1.hexdigest((hash_value ||= salty ) +  Array(count).pack('V'))
  end
 hash_value

结尾

如果有人能指出我在这里做错了什么,我将不胜感激。

编辑:提供更多背景信息:

此伪代码是从 axlsx gem 中提取的,用于创作 xlsx 电子表格。您可以在此处查看第 155 行左右的实际代码

我们已经能够根据 OpenOffice http://www.openoffice.org/sc/excelfileformat.pdf,修订版 1.42,第 115 页 (21.05.2012)的 Daniel Rentz 提供的算法实现更旧版本的密码散列但是,这与规范中列出的内容非常不同。

如果你 fork 存储库,你可以运行 examples/sheet_protection.rb 来创建一个包含两张工作表的工作簿,一张使用 ECMA 规范,另一张使用 OpenOffice 的版本。如果您单击“工具”->“保护”->“禁用保护”(此处从日语翻译,实际菜单文本可能不同)并输入密码 - ECMA 版本失败。

更新:2012.05.23

再深入一点,规范的第四部分(15.3.1.5、15.3.1.6)表明有一个可选的密码属性,它符合“过渡一致性类”的旧样式表保护生成

密码 (Password) 指定编辑此图表工作表所需的密码的哈希值。哈希是使用 workbookProtection 元素的 revisionPassword 属性中定义的逻辑生成的(第 1 部分,第 18.2.29 节)

这至少解释了为什么 OpenOffice 算法仍然有效。

4

2 回答 2

0

该算法是否假设您从零或一开始?

irb(main):006:0> 3.times do |t| p t; end
0
1
2
=> 3

也许试试

1.upto(10) do |count|

反而?

另外,你确定你的号码是小端序的吗?您可能需要一个不同的 pack 指令来确保 little-endian-ness。

https://img.skitch.com/20120522-gcsbh4eap247eh2jrubm4qm9tm.jpg

于 2012-05-22T01:30:42.443 回答
0

我在尝试重新实现 Excel 2013 的密码哈希算法时发现了这一点,所以我把它放在这里是为了将来帮助自己。

Excel 执行以下操作:

  • 连接saltValue+ 密码的字节(作为 UTF-16 字节)。
  • 根据algorithmNamesalt + 密码(现在默认为 SHA512)计算哈希。
  • 将循环计数(从 0 开始)作为四个 little-endian 字节附加到散列结果中。
  • 计算最后一个结果的哈希值 + 循环计数。
  • 重复计算spinCount次数。

最终的哈希结果是它存储在hashValue.

所以像下面这样的东西应该可以工作。

def hash_password(v)
  require 'digest/sha1'
  spin_count = 10
  salt_value = Digest::SHA1.hexdigest(rand(36**8).to_s(36))
  salty = salt_value + v
  hash_value = Digest::SHA1.hexdigest(salty)
  spin_count.times do |count|
    hash_value = Digest::SHA1.hexdigest(hash_value + Array(count).pack('V'))
  end
hash_value
于 2018-11-20T14:58:51.190 回答