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 算法仍然有效。