论坛首页 编程语言技术论坛

Digest and Encrypt

浏览 10916 次
该帖已经被评为精华帖
作者 正文
   发表时间:2010-11-01   最后修改:2011-03-21
这是10月31日 slide 上想写上去而没有写上去的部分 ……
因为 ppt 主要想写写 1.9.2 的一些改变,但是貌似 openssl 还是和 1.0 不太兼容,现在用的 0.9.8 只有椭圆函数电子签名可以用,椭圆函数加密还是很不方便。


要澄清的第一点:像 md5, sha1 之类的应该说是摘要算法,不是加密算法。
摘要算法是不能从结果还原的,往往结果长度固定,便于比较和验证。
加密算法是可以从结果还原的,密文长度随着输入的长度而增长。
这个知识库文章将摘要算法说成“单向加密” —— 是完全错误的 …… 单向加密指的是非对称加密算法,不要混淆了概念。

摘要算法

我们常用的有 CRC32(32), MD5(128), SHA1(160), RMD160(160), SHA2(256,384,512),括号中为摘要长度,以 bit 为单位,其中 CRC32 的结果为 32 位整数

由于 RMD160 结果长度和 SHA1 相同,而速度相应慢一点,用的人就比较少了。
但是有时用比较罕见的算法反而能增加安全性。

除了 CRC32 以外的摘要算法都有几种使用方法:
digest 输出2进制表示的结果
hexdigest 16进制字符表示的结果,可用文本传输
base64digest 2进制结果的base64编码,可用文本传输

# coding:utf8
# 用 zlib 的 CRC32
require 'zlib'
Zlib.crc32 'abcd'

module Digest; end
include Digest

require 'digest/md5'
MD5.digest 'abcd'

require 'digest/sha1'
SHA1.hexdigest 'abcd'

require 'digest/rmd160'
RMD160.base64digest 'abcd'

require 'digest/sha2'
SHA256.digest 'abcd'
SHA384.hexdigest 'abcd'
SHA512.base64digest 'abcd'


双向加密算法

双向加密算法,也称作对称键加密算法。
双向加密算法的特点是加密用的 算法 / key 和解密用的 算法 / key 很容易相互转换,甚至完全相同,只要知道其中一个,另一个很容易就能算出来。

最简单的双向加密算法就是 rot13,常用在论坛发帖时避免被搜索引擎或者 spam 收集信息 …… 所谓 rot,就是 rotate 的缩写,将 26 个字母用 13 位之后的替换掉。 rot13 的加密和解密算法就是同一个。
Ruby 标准库里没有明摆的 rot13,但是可以使用 nkf 的 rot13/rot47
require 'nkf'
def rot13 s
  NKF.nkf '-r -s', s
end
rot13 'abcd' #=> "nopq"
rot13 rot13 'abcd' #=> "abcd"

顺带一提,nkf 还有些好用的转换功能,像 line-ending 转换和某些编码转换。
NKF.guess 可以检测一些日文编码和 utf-8/utf-16。但是没有 tellenc 之类的工具能猜的编码多。

最常用的双向加密算法是 base64,因为 base64 的密文可以用纯 ascii 文本传输,所以广泛应用在很多文本协议上。中文邮件一般就是以 base64 密文来发送的。pem 格式就通过base64 保存公钥 / 密钥,便于网络传输。

再顺带一提,RFC4648 还提了一个 base32,它是大小写不敏感的,我用纯 Ruby 实现了一个:
http://github.com/luikore/rfc-base32

Base64 的使用灰常简单:
require 'base64'
puts s = Base64.encode64 '这个可以有'
#=> 1eK49r/J0tTT0A==
puts Base64.decode64 s
#=> 这个可以有


真正 "Hardcore" 一点的加密算法,就需要密钥(key)了。
基本要求是:不知道 key 就无法破译密文。

加密的过程:
把输入分成很多个固定大小的 block(如256byte),
对每块使用可逆函数计算出一个新的字节 block,
写到输出。

这个做法还有一点点问题,因为相同的输入可以获得相同的输出,从结果中就很容易看出哪两个 block 是完全一样的,就存在被猜出密钥的危险了。

解决方案之一是 Cipher Block Chaining (CBC),CBC 方法需要 Initialization Vector(IV)。
关于 CBC 等名词详见 wiki:
Block Cipher Modes of Operation

使用 AES 加密的示例如下:
require "openssl"
cipher = OpenSSL::Cipher::Cipher

# AES, block size = 256,使用 CBC
aes = cipher.new('aes-256-cbc').encrypt
# 随机生成密钥
key = aes.random_key
# 随机生成初始向量
iv = aes.random_iv

crypted = aes.update 'hello '
crypted.<< aes.update 'world'
crypted.<< aes.final

aes = cipher.new('aes-256-cbc').decrypt
aes.key = key
aes.iv = iv

result = aes.update crypted
result.<< aes.final

puts result #=> "hello world"


查看有多少种可以用的对称加密算法:
require "openssl"
puts OpenSSL::Cipher::Cipher.ciphers.uniq(&:upcase)


AES-128-CBC
AES-128-CFB
AES-128-CFB1
AES-128-CFB8
AES-128-ECB
AES-128-OFB
AES-192-CBC
AES-192-CFB
AES-192-CFB1
AES-192-CFB8
AES-192-ECB
AES-192-OFB
AES-256-CBC
AES-256-CFB
AES-256-CFB1
AES-256-CFB8
AES-256-ECB
AES-256-OFB
AES128
AES192
AES256
BF
BF-CBC
BF-CFB
BF-ECB
BF-OFB
CAST
CAST-cbc
CAST5-CBC
CAST5-CFB
CAST5-ECB
CAST5-OFB
DES
DES-CBC
DES-CFB
DES-CFB1
DES-CFB8
DES-ECB
DES-EDE
DES-EDE-CBC
DES-EDE-CFB
DES-EDE-OFB
DES-EDE3
DES-EDE3-CBC
DES-EDE3-CFB
DES-EDE3-CFB1
DES-EDE3-CFB8
DES-EDE3-OFB
DES-OFB
DES3
DESX
DESX-CBC
IDEA
IDEA-CBC
IDEA-CFB
IDEA-ECB
IDEA-OFB
RC2
RC2-40-CBC
RC2-64-CBC
RC2-CBC
RC2-CFB
RC2-ECB
RC2-OFB
RC4
RC4-40
blowfish

注: BF 为 blowfish,使用 64bit block 加密。

单向加密算法

单向加密算法也称非对称(键)加密算法,指的是就算你知道解密用的密钥,也几乎不可能算出加密用的密钥。如 RSA, Diffie-Hellman(DH),Elliptic Curve cryptography(ECC)。

RSA 应用超广泛,由于关于 RSA 的各种文章非常多,就不详细解释了。要注意的是一些遗留系统还在使用 128 位私钥,是非常危险的,至少 1024 以上才能保证加密数据的安全。

PKey 模块包含各种 public / private key 算法,RSA 的使用示例:
require "openssl"
rsa = OpenSSL::PKey::RSA

# RSA 公钥和密钥, 为 RSA 的实例
# pem 格式 base64 的内容
password = 'you shall not pass'

# 生成 pem 格式的私钥,参照 openssl 命令的用法
private_key = rsa.new(2048).to_pem des3, password

# 如果不给 password 参数,会要求在命令行中输入密码
public_key = rsa.new(private_key, password).public_key

# 注意 source 长度不能大于 key 的字节数 - 2
source = 'hello world'
crypted = rsa.new(public_key).public_encrypt source
decrypted = rsa.new(private_key, password).private_decrypt crypted

puts decrypted #=> hello world


非对称加密算法的运算量比较大,如果要对大文件进行加密,一般全文使用对称加密算法加密,只对(对称加密算法的键)使用非对称加密。这种简单组合就不演示了 ……

椭圆曲线加密算法

椭圆曲线加密算法也是一种单向加密算法,简单的说为什么 nb,就是:要实现相同的加密强度,椭圆曲线族比 RSA 需要的密钥长度小很多。

openssl 从 0.9.8 起,加入了各种椭圆函数曲线签名算法,还有 前-Sun公司 贡献的 ECDH (椭圆函数 key 到 Diffie-Hellman key 的转换)。

查看内建的椭圆曲线:
require "openssl"
puts OpenSSL::PKey::EC.builtin_curves.map{|x|x.join "\t"}


secp112r1       SECG/WTLS curve over a 112 bit prime field
secp112r2       SECG curve over a 112 bit prime field
secp128r1       SECG curve over a 128 bit prime field
secp128r2       SECG curve over a 128 bit prime field
secp160k1       SECG curve over a 160 bit prime field
secp160r1       SECG curve over a 160 bit prime field
secp160r2       SECG/WTLS curve over a 160 bit prime field
secp192k1       SECG curve over a 192 bit prime field
secp224k1       SECG curve over a 224 bit prime field
secp224r1       NIST/SECG curve over a 224 bit prime field
secp256k1       SECG curve over a 256 bit prime field
secp384r1       NIST/SECG curve over a 384 bit prime field
secp521r1       NIST/SECG curve over a 521 bit prime field
prime192v1      NIST/X9.62/SECG curve over a 192 bit prime field
prime192v2      X9.62 curve over a 192 bit prime field
prime192v3      X9.62 curve over a 192 bit prime field
prime239v1      X9.62 curve over a 239 bit prime field
prime239v2      X9.62 curve over a 239 bit prime field
prime239v3      X9.62 curve over a 239 bit prime field
prime256v1      X9.62/SECG curve over a 256 bit prime field
sect113r1       SECG curve over a 113 bit binary field
sect113r2       SECG curve over a 113 bit binary field
sect131r1       SECG/WTLS curve over a 131 bit binary field
sect131r2       SECG curve over a 131 bit binary field
sect163k1       NIST/SECG/WTLS curve over a 163 bit binary field
sect163r1       SECG curve over a 163 bit binary field
sect163r2       NIST/SECG curve over a 163 bit binary field
sect193r1       SECG curve over a 193 bit binary field
sect193r2       SECG curve over a 193 bit binary field
sect233k1       NIST/SECG/WTLS curve over a 233 bit binary field
sect233r1       NIST/SECG/WTLS curve over a 233 bit binary field
sect239k1       SECG curve over a 239 bit binary field
sect283k1       NIST/SECG curve over a 283 bit binary field
sect283r1       NIST/SECG curve over a 283 bit binary field
sect409k1       NIST/SECG curve over a 409 bit binary field
sect409r1       NIST/SECG curve over a 409 bit binary field
sect571k1       NIST/SECG curve over a 571 bit binary field
sect571r1       NIST/SECG curve over a 571 bit binary field
c2pnb163v1      X9.62 curve over a 163 bit binary field
c2pnb163v2      X9.62 curve over a 163 bit binary field
c2pnb163v3      X9.62 curve over a 163 bit binary field
c2pnb176v1      X9.62 curve over a 176 bit binary field
c2tnb191v1      X9.62 curve over a 191 bit binary field
c2tnb191v2      X9.62 curve over a 191 bit binary field
c2tnb191v3      X9.62 curve over a 191 bit binary field
c2pnb208w1      X9.62 curve over a 208 bit binary field
c2tnb239v1      X9.62 curve over a 239 bit binary field
c2tnb239v2      X9.62 curve over a 239 bit binary field
c2tnb239v3      X9.62 curve over a 239 bit binary field
c2pnb272w1      X9.62 curve over a 272 bit binary field
c2pnb304w1      X9.62 curve over a 304 bit binary field
c2tnb359v1      X9.62 curve over a 359 bit binary field
c2pnb368w1      X9.62 curve over a 368 bit binary field
c2tnb431r1      X9.62 curve over a 431 bit binary field
wap-wsg-idm-ecid-wtls1  WTLS curve over a 113 bit binary field
wap-wsg-idm-ecid-wtls3  NIST/SECG/WTLS curve over a 163 bit binary field
wap-wsg-idm-ecid-wtls4  SECG curve over a 113 bit binary field
wap-wsg-idm-ecid-wtls5  X9.62 curve over a 163 bit binary field
wap-wsg-idm-ecid-wtls6  SECG/WTLS curve over a 112 bit prime field
wap-wsg-idm-ecid-wtls7  SECG/WTLS curve over a 160 bit prime field
wap-wsg-idm-ecid-wtls8  WTLS curve over a 112 bit prime field
wap-wsg-idm-ecid-wtls9  WTLS curve over a 160 bit prime field
wap-wsg-idm-ecid-wtls10 NIST/SECG/WTLS curve over a 233 bit binary field
wap-wsg-idm-ecid-wtls11 NIST/SECG/WTLS curve over a 233 bit binary field
wap-wsg-idm-ecid-wtls12 WTLS curvs over a 224 bit prime field
Oakley-EC2N-3
        IPSec/IKE/Oakley curve #3 over a 155 bit binary field.
        Not suitable for ECDSA.
        Questionable extension field!
Oakley-EC2N-4
        IPSec/IKE/Oakley curve #4 over a 185 bit binary field.
        Not suitable for ECDSA.
        Questionable extension field!


下面是结合 ECC 和 DSA 的电子签名示例:
#! /bin/env ruby
# coding: utf-8

require "openssl"
require "digest/sha2"

# 要检验的 digest message
msg1 = Digest::SHA384.digest 'hello world'
msg2 = Digest::SHA384.digest 'goodbye world'

# 初始化参数为曲线名, 查看所有曲线: ec.builtin_curves
skey = OpenSSL::PKey::EC.new("c2tnb359v1").generate_key
puts "\bthe private key pem:", skey.to_pem

# 用 private key 签名
sign = skey.dsa_sign_asn1 msg1

# 将 private key 消除后,to_pem 就只打印 public key 了
skey.private_key = nil
public_pem = skey.to_pem

# to_bn means "to big number"
puts "\nthe public key number:", skey.public_key.to_bn
puts "\nthe public key pem:", public_pem

vkey = OpenSSL::PKey::EC.new public_pem

# 用 public key 检验
puts "\nverify:"
puts(vkey.dsa_verify_asn1 msg1, sign) # true
puts(vkey.dsa_verify_asn1 msg2, sign) # false


-------------------------------------------------------

参考

SSL and TLS:
http://horms.net/projects/ssl_and_tls/stuff/ssl_and_tls.pdf
   发表时间:2010-11-02  
不错的简介

为啥不发到综合版?
0 请登录后投票
   发表时间:2010-11-02  
Spike 写道
不错的简介

为啥不发到综合版?

这主要是介绍 Ruby 中如何算摘要和加密 …… 几乎不涉及各种算法的背景
0 请登录后投票
   发表时间:2010-11-02  
误解的原因是经常站点对密码做MD5处理....,所以很多人都认为是加密.

加密通常是要伴随着信息还原的,即揭秘过程。


ruby ms也没提供啥算法,基本都是openssl在唱戏。。
0 请登录后投票
   发表时间:2010-11-03  
http://coolshell.cn/wp-content/uploads/2010/10/rijndael_ingles2004.swf


看这个
0 请登录后投票
   发表时间:2010-11-03   最后修改:2010-11-03
CharlesCui 写道
http://coolshell.cn/wp-content/uploads/2010/10/rijndael_ingles2004.swf


看这个

就是这个 flash 害我算错了 mix columns …… 弄了很久才发现改正

那个是 GF(2^8) 上的乘法,不是整数乘法 > <

还有 RCON 部分有点错误,不是 RCON(4), RCON(8) ... 而是 RCON(1), RCON(2) ...
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics