密码学基础

密码学基础

1.前言

工作需要密码学的东西,在这做一下笔记

2.加密算法

2.1.对称加密

单密钥的加密算法,由明文,加密算法和密钥组成。加密解密中只用一个密钥(常见:des,aes,rc4)。

2.2.非对称加密

双密钥的加密算法,由明文,加密算法,公钥和私钥组成。私钥加密的明文,必须用公钥解密,用公钥加密的明文,必须要用对应私钥解密。(常见:RSA)[所以公钥和私钥是一对,ssh的密钥登入就是用的这个,本地是私钥,服务器存公钥,两个秘钥匹配成功就可以登入]

对称加密的安全在于密钥,密钥不能对外公开。而对称加密公钥是公开的,私钥是保密的

对比:非对称加密加密成本高,耗时长,加密内容小,所以一般先使用非对称加密将单个密钥传给对方,然后再使用对称加密传输通信内容。

2.3.HASH算法

MD5,SHA1,SHA256 特点:不可逆

3.数字签名

数字签名是用于标记数字文件的拥有者,创造者的字符串。
就是用了对称加密。如我发表某可执行文件(wilson.exe),我用私钥加密了wilson.exe的文件哈希,得到就是数字签名,并打到wilson.exe上面。
然后我把公钥和wilson.exe给你,你可以用公钥解密就可以知道,这个是不是我给你的。

但是如果有人做中间人攻击,把我的公钥和wilson.exe改了,然后发给你怎么办?这时候就需要ca了,我先把我的公钥放到ca上,当我把公钥给你的时候,你需要去ca查一下这个公钥是不是我的,是的话继续,不是的话就停止。

4.https

详情参考:http://blog.csdn.net/clh604/article/details/22179907 这个详细了
握手过程:
1.浏览器将自己支持的一套加密规则发送给服务端。
2.服务端从中选出一组加密算法和HASH算法(两个算法后面都有用),并将自己的身份信息以证书的形式发回给浏览器。证书里面包含了网站地址,加密公钥,以及证书的颁发机构等信息。
3.浏览器获得网站证书之后浏览器要做以下工作:

  • a) 验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等),如果证书受信任,则浏览器栏里面会显示一个小锁头,否则会给出证书不受信的提示。 这个是前面说的防止服务端给人伪造了
  • b) 如果证书受信任,或者是用户接受了不受信的证书,浏览器会生成一串随机数的密码,并用证书中提供的公钥进行加密。
  • c) 使用约定好的HASH算法计算握手消息hash值,并使用随机数对握手消息进行对称加密,最后将之前生成的所有信息发送给网站。
    最后浏览器发给服务端的消息有:用公钥加密随机值的密文,握手包的hash值,握手包的密文(这个是对称加密的)

4.服务端接收浏览器发来的数据之后要做以下的操作:

  • a) 使用自己的私钥将信息解密取出随机数,使用随机数解密发来的握手包的密文,再做hash计算得到握手包的hash值, 并验证HASH是否与浏览器发来的一致。 不一致就握手失败了
  • b) 使用随机值加密一段握手消息,并将握手消息密文和握手hash发送给浏览器。
    5.浏览器使用随机值解密并使用对称加密来计算握手消息的HASH,如果与服务端发来的HASH一致,此时握手过程结束。否则握手失败

6.之后所有的通信数据将由之前浏览器生成的随机密码并利用对称加密算法进行加密。
问:为什么要用hash值?我直接发公钥加密的随机值密文不行么?
不用hash值,我还是可以中间人,伪造客户端给服务端发送随机值加密的密文,和服务器连接链接。

5.代码时间

下面是golang的加密代码:

golang 对称加密 des 代码:
package main

import (
    "bytes"
    "crypto/cipher"
    "crypto/des"
    "fmt"
)

//DES是分组算法,每个分组是8字节,加密的时候,如果明文不是8的整数倍,需要被填充到8的整数倍,这个时候的密文长度会和填充后的明文长度相同。
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
    padding := blockSize - len(ciphertext)%blockSize
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(ciphertext, padtext...)
}

func ZeroUnPadding(origData []byte) []byte {
    length := len(origData)
    unpadding := int(origData[length-1])
    return origData[:(length - unpadding)]
}

// des加密
func DesEncrypt(origData, key []byte) ([]byte, error) {
    block, err := des.NewCipher(key)
    if err != nil {
        return nil, err
    }
    origData = PKCS5Padding(origData, block.BlockSize())
    blockMode := cipher.NewCBCEncrypter(block, key)
    crypted := make([]byte, len(origData))
    blockMode.CryptBlocks(crypted, origData)
    return crypted, nil
}

//des解密
func DesDecrypt(crypted, key []byte) ([]byte, error) {
    block, err := des.NewCipher(key)
    if err != nil {
        return nil, err
    }
    blockMode := cipher.NewCBCDecrypter(block, key)
    origData := crypted
    blockMode.CryptBlocks(origData, crypted)
    origData = ZeroUnPadding(origData)
    return origData, nil
}

func main() {
    data, err := DesEncrypt([]byte("wilson"), []byte("password"))
    if err != nil {
        panic(err)
    }
    fmt.Println("OK")
    fmt.Println(string(data))

    msg, err := DesDecrypt(data, []byte("password"))
    if err != nil {
        panic(err)
    }
    fmt.Println("解密完的数据")
    fmt.Println(string(msg))
}


golang 非对称加密 rsa 代码:(注意rsa对密文长度有要求的,太长会报错)


package main

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/x509"
    "encoding/pem"
    "errors"
    "fmt"
)

//加密
func RsaEncrypt(origData []byte) ([]byte, error) {
    //公钥
    block, _ := pem.Decode(publicKey)
    if block == nil {
        return nil, errors.New("public key error")
    }
    pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
    if err != nil {
        return nil, err
    }
    pub := pubInterface.(*rsa.PublicKey)
    return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}

//解密
func RsaDecrypt(ciphertext []byte) ([]byte, error) {
    //私钥
    block, _ := pem.Decode(privateKey)
    if block == nil {
        return nil, errors.New("private key error!")
    }
    priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    if err != nil {
        return nil, err
    }
    return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
}

// 公钥和私钥可以从文件中读取
var privateKey = []byte(`
-----BEGIN RSA PRIVATE KEY-----
我是私钥
-----END RSA PRIVATE KEY-----
`)

var publicKey = []byte(`
-----BEGIN PUBLIC KEY-----
我是公钥
-----END PUBLIC KEY-----
`)

func main() {
    //使用公钥加密数据
    data, err := RsaEncrypt([]byte("wilson23333"))
    if err != nil {
        panic(err)
    }
    fmt.Println("加密完的数据", string(data))

    //使用私钥解密数据
    origData, err := RsaDecrypt(data)
    if err != nil {
        panic(err)
    }
    fmt.Println("解密得到数据", string(origData))
}

6.参考文献

《go语言编程》人民邮电出版设 许式伟,吕桂花编著

http://blog.studygolang.com/2013/01/go%E5%8A%A0%E5%AF%86%E8%A7%A3%E5%AF%86%E4%B9%8Bdes/

http://blog.studygolang.com/2013/01/go%E5%8A%A0%E5%AF%86%E8%A7%A3%E5%AF%86%E4%B9%8Brsa/

标签: lightless@foxmail.com

暂无评论

  1. something

    路过学习 了~

添加新评论