当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Ruby Cipher类用法及代码示例


本文简要介绍ruby语言中 OpenSSL::Cipher类 的用法。

提供加密和解密的对称算法。可用的算法取决于安装的 OpenSSL 的特定版本。

列出所有支持的算法

可以通过以下方式获得支持的算法列表

puts OpenSSL::Cipher.ciphers

实例化 Cipher

有几种方法可以创建 Cipher 实例。通常, Cipher 算法按其名称、 key 长度(以位为单位)和要使用的密码模式进行分类。创建 Cipher 的最通用方法如下

cipher = OpenSSL::Cipher.new('<name>-<key length>-<mode>')

即,由各个组件名称、键长度和模式的连字符连接组成的字符串。可以使用全部大写或全部小写的字符串,例如:

cipher = OpenSSL::Cipher.new('aes-128-cbc')

选择加密或解密模式

对于对称算法,加密和解密通常是非常相似的操作,这反映在不必为任一操作选择不同的类,两者都可以使用相同的类来完成。尽管如此,在获得 Cipher 实例后,我们需要告诉实例我们打算用它做什么,所以我们需要调用

cipher.encrypt

或者

cipher.decrypt

Cipher 实例上。这应该是创建实例后的第一次调用,否则已经设置的配置可能会在此过程中丢失。

选择一把钥匙

对称加密要求加密方和解密方使用相同的 key ,并且在初始 key 建立后应作为私有信息保存。有很多方法可以创建不安全的 key ,最值得注意的是简单地将密码作为 key ,而无需进一步处理密码。为特定 Cipher 创建 key 的一种简单而安全的方法是

cipher = OpenSSL::Cipher.new('aes-256-cfb')
cipher.encrypt
key = cipher.random_key # also sets the generated key on the Cipher

如果您绝对需要使用密码作为加密 key ,则应使用基于密码的 key 派生函数 2 (PBKDF2),方法是借助 OpenSSL::PKCS5.pbkdf2_hmac_sha1 OpenSSL::PKCS5.pbkdf2_hmac 提供的函数生成 key 。

尽管有 Cipher#pkcs5_keyivgen ,但它的使用已被弃用,它只应在遗留应用程序中使用,因为它不使用较新的 PKCS#5 v2 算法。

选择静脉输液

密码模式 CBC、CFB、OFB 和 CTR 都需要 “initialization vector” 或简称 IV。 ECB 模式是唯一不需要 IV 的模式,但这种模式几乎没有合法的用例,因为它没有充分隐藏明文模式。所以

除非你绝对确定你绝对需要它,否则你永远不应该使用 ECB 模式

因此,您最终会得到一个在任何情况下都明确需要 IV 的模式。虽然 IV 可以被视为公共信息,即它一旦生成就可以公开传输,但它仍应保持不可预测性以防止某些类型的攻击。因此,理想情况下

始终为 Cipher 的每次加密创建一个安全的随机 IV

应该为每个数据加密创建一个新的随机 IV。将 IV 视为随机数(使用一次的数字)——它是公开的,但随机且不可预测。可以按如下方式创建安全随机 IV

cipher = ...
cipher.encrypt
key = cipher.random_key
iv = cipher.random_iv # also sets the generated IV on the Cipher

虽然 key 通常也是一个随机值,但作为 IV 是一个糟糕的选择。攻击者可以通过多种方式利用这种 IV。作为一般经验法则,应不惜一切代价避免直接或间接暴露 key ,并且只有在有充分理由的情况下才会出现例外情况。

调用 Cipher#final

ECB(不应使用)和 CBC 都是基于块的模式。这意味着与其他基于流的模式不同,它们对固定大小的数据块进行操作,因此它们需要 “finalization” 步骤来通过适当处理某种形式的填充来生成或正确解密最后一个数据块。因此,必须将 OpenSSL::Cipher#final 的输出添加到您的加密/解密缓冲区,否则您最终会遇到解密错误或截断数据。

虽然这对于streaming-mode 密码来说并不是真正必要的,但仍然建议应用相同的模式,即在那里添加 Cipher#final 的输出 - 它还使您将来可以更轻松地在模式之间切换。

加密和解密一些数据

data = "Very, very confidential data"

cipher = OpenSSL::Cipher.new('aes-128-cbc')
cipher.encrypt
key = cipher.random_key
iv = cipher.random_iv

encrypted = cipher.update(data) + cipher.final
...
decipher = OpenSSL::Cipher.new('aes-128-cbc')
decipher.decrypt
decipher.key = key
decipher.iv = iv

plain = decipher.update(encrypted) + decipher.final

puts data == plain #=> true

认证加密和相关数据 (AEAD)

如果使用的 OpenSSL 版本支持它,则应始终首选经过身份验证的加密模式(例如 GCM 或 CCM),而不是任何未经身份验证的模式。目前, OpenSSL 仅支持与关联数据 (AEAD) 结合使用的 AE,其中在加密过程中包含额外的关联数据以在加密结束时计算标签。该标签也将用于解密过程,并通过验证其有效性,确定给定密文的真实性。

这优于未经身份验证的模式,因为它允许检测是否有人在加密后有效地更改了密文。这可以防止对密文的恶意修改,否则可能会被利用以对潜在攻击者有利的方式修改密文。

如果有附加信息(例如标头或某些元数据)也必须经过身份验证,但不一定需要加密,则使用关联数据。如果加密和以后的解密不需要相关数据, OpenSSL 库仍然需要设置一个值 - 如果没有可用的值,可以使用“”。

使用 GCM(伽罗瓦/计数器模式)的示例。您有 16 个字节 key 、12 个字节(96 位) nonce 和相关数据 auth_data 。确保不要重复使用 keynonce 对。重用 nonce 会破坏 GCM 模式的安全保证。

cipher = OpenSSL::Cipher.new('aes-128-gcm').encrypt
cipher.key = key
cipher.iv = nonce
cipher.auth_data = auth_data

encrypted = cipher.update(data) + cipher.final
tag = cipher.auth_tag # produces 16 bytes tag by default

现在你是接收者。您知道 key 并已通过不受信任的网络收到 nonceauth_dataencryptedtag 。请注意,GCM 接受 1 到 16 个字节之间的任意长度标签。您可能还需要检查接收到的标签的长度是否正确,或者您允许攻击者以 1/256 的概率为被篡改的密文伪造一个有效的单字节标签。

raise "tag is truncated!" unless tag.bytesize == 16
decipher = OpenSSL::Cipher.new('aes-128-gcm').decrypt
decipher.key = key
decipher.iv = nonce
decipher.auth_tag = tag
decipher.auth_data = auth_data

decrypted = decipher.update(encrypted) + decipher.final

puts data == decrypted #=> true

相关用法


注:本文由纯净天空筛选整理自ruby-lang.org大神的英文原创作品 Cipher类。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。