美文网首页
加密算法

加密算法

作者: 成功的失败者 | 来源:发表于2020-03-23 20:30 被阅读0次

    对比

    特点 对称算法 非对称加密算法 Hash算法
    密钥管理 比较难,不适合互联网,一般用于内部系统 密钥容易管理 没有秘钥(加盐时需要秘钥如:hmac)
    安全性
    加密速度 适中,适合大数据量的加解密处理 比较慢,适合 小数据量加解密或数据签名 最快,用于权限校验
    是否可逆 是,加密解密秘钥相同 是,加密解密秘钥不同

    一、对称加密

    加解密都使用的是同一个密钥。

    算法 对比
    DES 数据加密标准,速度较快,适用于加密大量数据的场合。
    3DES 是基于DES,对一块数据用三个不同的密钥进行三次加密,强度更高。
    AES 下一代的加密算法标准,速度快,安全级别高。用于替换DES
    • AES
      加密数据块分组长度必须为128bit(byte[16]),密钥长度可以是128bit(byte[16])、192bit(byte[24])、256bit(byte[32])中的任意一个。
      块:对明文进行加密的时候,先要将明文按照128bit进行划分。
      填充方式:因为明文的长度不一定总是128的整数倍,所以要进行补位,我们这里采用的是PKCS7填充方式

    AES实现的方式多样, 其中包括ECB、CBC、CFB、OFB等

    1. 电码本模式(Electronic Codebook Book (ECB))
      将明文分组加密之后的结果直接称为密文分组。
    package mysqlcrypto
    
    import (
        "crypto/aes"
    )
    
    func AESEncrypt(src []byte, key []byte) (encrypted []byte) {
        cipher, _ := aes.NewCipher(generateKey(key))
        length := (len(src) + aes.BlockSize) / aes.BlockSize
        plain := make([]byte, length*aes.BlockSize)
        copy(plain, src)
        pad := byte(len(plain) - len(src))
        for i := len(src); i < len(plain); i++ {
            plain[i] = pad
        }
        encrypted = make([]byte, len(plain))
        // 分组分块加密 
        for bs, be := 0, cipher.BlockSize(); bs <= len(src); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
            cipher.Encrypt(encrypted[bs:be], plain[bs:be])
        }
    
        return encrypted
    }
    
    func AESDecrypt(encrypted []byte, key []byte) (decrypted []byte) {
        cipher, _ := aes.NewCipher(generateKey(key))
        decrypted = make([]byte, len(encrypted))
        // 
        for bs, be := 0, cipher.BlockSize(); bs < len(encrypted); bs, be = bs+cipher.BlockSize(), be+cipher.BlockSize() {
            cipher.Decrypt(decrypted[bs:be], encrypted[bs:be])
        }
    
        trim := 0
        if len(decrypted) > 0 {
            trim = len(decrypted) - int(decrypted[len(decrypted)-1])
        }
    
        return decrypted[:trim]
    }
    
    func generateKey(key []byte) (genKey []byte) {
        genKey = make([]byte, 16)
        copy(genKey, key)
        for i := 16; i < len(key); {
            for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
                genKey[j] ^= key[i]
            }
        }
        return genKey
    }
    
    1. 密码分组链接模式(Cipher Block Chaining (CBC))
      将明文分组与前一个密文分组进行XOR运算,然后再进行加密。每个分组的加解密都依赖于前一个分组。而第一个分组没有前一个分组,因此需要一个初始化向量
    package main
    import(
        "bytes"
        "crypto/aes"
        "fmt"
        "crypto/cipher"
        "encoding/base64"
    )
    func main() {
        orig := "hello world"
        key := "0123456789012345"
        fmt.Println("原文:", orig)
        encryptCode := AesEncrypt(orig, key)
        fmt.Println("密文:" , encryptCode)
        decryptCode := AesDecrypt(encryptCode, key)
        fmt.Println("解密结果:", decryptCode)
    }
    func AesEncrypt(orig string, key string) string {
        // 转成字节数组
        origData := []byte(orig)
        k := []byte(key)
        // 分组秘钥
        // NewCipher该函数限制了输入k的长度必须为16, 24或者32
        block, _ := aes.NewCipher(k)
        // 获取秘钥块的长度
        blockSize := block.BlockSize()
        // 补全码
        origData = PKCS7Padding(origData, blockSize)
        // 加密模式
        blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
        // 创建数组
        cryted := make([]byte, len(origData))
        // 加密
        blockMode.CryptBlocks(cryted, origData)
        return base64.StdEncoding.EncodeToString(cryted)
    }
    func AesDecrypt(cryted string, key string) string {
        // 转成字节数组
        crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
        k := []byte(key)
        // 分组秘钥
        block, _ := aes.NewCipher(k)
        // 获取秘钥块的长度
        blockSize := block.BlockSize()
        // 加密模式
        blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
        // 创建数组
        orig := make([]byte, len(crytedByte))
        // 解密
        blockMode.CryptBlocks(orig, crytedByte)
        // 去补全码
        orig = PKCS7UnPadding(orig)
        return string(orig)
    }
    //补码
    //AES加密数据块分组长度必须为128bit(byte[16]),密钥长度可以是128bit(byte[16])、192bit(byte[24])、256bit(byte[32])中的任意一个。
    func PKCS7Padding(ciphertext []byte, blocksize int) []byte {
        padding := blocksize - len(ciphertext)%blocksize
        padtext := bytes.Repeat([]byte{byte(padding)}, padding)
        return append(ciphertext, padtext...)
    }
    //去码
    func PKCS7UnPadding(origData []byte) []byte {
        length := len(origData)
        unpadding := int(origData[length-1])
        return origData[:(length - unpadding)]
    }
    
    1. 计算器模式(Counter (CTR))
    2. 密码反馈模式(Cipher FeedBack (CFB))
      前一个密文分组会被送回到密码算法的输入端。在CBC和EBC模式中,明文分组都是通过密码算法进行加密的。而在CFB模式中,明文分组并没有通过加密算法直接进行加密,明文分组和密文分组之间只有一个XOR。
    func ExampleNewCFBDecrypter() {
        // Load your secret key from a safe place and reuse it across multiple
        // NewCipher calls. (Obviously don't use this example key for anything
        // real.) If you want to convert a passphrase to a key, use a suitable
        // package like bcrypt or scrypt.
        key, _ := hex.DecodeString("6368616e676520746869732070617373")
        ciphertext, _ := hex.DecodeString("7dd015f06bec7f1b8f6559dad89f4131da62261786845100056b353194ad")
    
        block, err := aes.NewCipher(key)
        if err != nil {
            panic(err)
        }
    
        // The IV needs to be unique, but not secure. Therefore it's common to
        // include it at the beginning of the ciphertext.
        if len(ciphertext) < aes.BlockSize {
            panic("ciphertext too short")
        }
        iv := ciphertext[:aes.BlockSize]
        ciphertext = ciphertext[aes.BlockSize:]
    
        stream := cipher.NewCFBDecrypter(block, iv)
    
        // XORKeyStream can work in-place if the two arguments are the same.
        stream.XORKeyStream(ciphertext, ciphertext)
        fmt.Printf("%s", ciphertext)
        // Output: some plaintext
    }
    
    func ExampleNewCFBEncrypter() {
        // Load your secret key from a safe place and reuse it across multiple
        // NewCipher calls. (Obviously don't use this example key for anything
        // real.) If you want to convert a passphrase to a key, use a suitable
        // package like bcrypt or scrypt.
        key, _ := hex.DecodeString("6368616e676520746869732070617373")
        plaintext := []byte("some plaintext")
    
        block, err := aes.NewCipher(key)
        if err != nil {
            panic(err)
        }
    
        // The IV needs to be unique, but not secure. Therefore it's common to
        // include it at the beginning of the ciphertext.
        ciphertext := make([]byte, aes.BlockSize+len(plaintext))
        iv := ciphertext[:aes.BlockSize]
        if _, err := io.ReadFull(rand.Reader, iv); err != nil {
            panic(err)
        }
    
        stream := cipher.NewCFBEncrypter(block, iv)
        stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
    
        // It's important to remember that ciphertexts must be authenticated
        // (i.e. by using crypto/hmac) as well as being encrypted in order to
        // be secure.
        fmt.Printf("%x\n", ciphertext)
    }
    
    1. 输出反馈模式(Output FeedBack (OFB))

    二、非对加解密

    加解密使用不同的密钥

    算法 对比
    RSA 可用于加密,也能用于签名
    DSA 数字签名算法,仅能用于签名,不能用于加解密。
    DSS 数字签名标准,既能用于签名,也可以用于加解密。
    ECC ECC优势在于密钥位数短,一般认为160位密钥的ECC安全性相当于1024位密钥的RSA,256位相当于3072位
    • RSA
    import (
        "crypto/rand"
        "crypto/rsa"
        "crypto/x509"
        "encoding/base64"
        "encoding/pem"
        "errors"
        "fmt"
    )
    
    // 私钥生成
    //openssl genrsa -out rsa_private_key.pem 1024
    var privateKey = []byte(`
    -----BEGIN RSA PRIVATE KEY-----
    MIICWwIBAAKBgQDcGsUIIAINHfRTdMmgGwLrjzfMNSrtgIf4EGsNaYwmC1GjF/bM
    h0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdTnCDPPZ7oV7p1B9Pud+6zPaco
    qDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Zy682X1+R1lRK8D+vmQIDAQAB
    AoGAeWAZvz1HZExca5k/hpbeqV+0+VtobMgwMs96+U53BpO/VRzl8Cu3CpNyb7HY
    64L9YQ+J5QgpPhqkgIO0dMu/0RIXsmhvr2gcxmKObcqT3JQ6S4rjHTln49I2sYTz
    7JEH4TcplKjSjHyq5MhHfA+CV2/AB2BO6G8limu7SheXuvECQQDwOpZrZDeTOOBk
    z1vercawd+J9ll/FZYttnrWYTI1sSF1sNfZ7dUXPyYPQFZ0LQ1bhZGmWBZ6a6wd9
    R+PKlmJvAkEA6o32c/WEXxW2zeh18sOO4wqUiBYq3L3hFObhcsUAY8jfykQefW8q
    yPuuL02jLIajFWd0itjvIrzWnVmoUuXydwJAXGLrvllIVkIlah+lATprkypH3Gyc
    YFnxCTNkOzIVoXMjGp6WMFylgIfLPZdSUiaPnxby1FNM7987fh7Lp/m12QJAK9iL
    2JNtwkSR3p305oOuAz0oFORn8MnB+KFMRaMT9pNHWk0vke0lB1sc7ZTKyvkEJW0o
    eQgic9DvIYzwDUcU8wJAIkKROzuzLi9AvLnLUrSdI6998lmeYO9x7pwZPukz3era
    zncjRK3pbVkv0KrKfczuJiRlZ7dUzVO0b6QJr8TRAA==
    -----END RSA PRIVATE KEY-----
    `)
    
    // 公钥: 根据私钥生成
    //openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
    var publicKey = []byte(`
    -----BEGIN PUBLIC KEY-----
    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcGsUIIAINHfRTdMmgGwLrjzfM
    NSrtgIf4EGsNaYwmC1GjF/bMh0Mcm10oLhNrKNYCTTQVGGIxuc5heKd1gOzb7bdT
    nCDPPZ7oV7p1B9Pud+6zPacoqDz2M24vHFWYY2FbIIJh8fHhKcfXNXOLovdVBE7Z
    y682X1+R1lRK8D+vmQIDAQAB
    -----END PUBLIC KEY-----
    `)
    
    // 加密
    func RsaEncrypt(origData []byte) ([]byte, error) {
        //解密pem格式的公钥
        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!")
        }
        //解析PKCS1格式的私钥
        priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
        if err != nil {
            return nil, err
        }
        // 解密
        return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
    }
    func main() {
        data, _ := RsaEncrypt([]byte("hello world"))
        fmt.Println(base64.StdEncoding.EncodeToString(data))
        origData, _ := RsaDecrypt(data)
        fmt.Println(string(origData))
    } 
    

    三、签名算法

    主要用于验证,防止信息被修改, 如:文件校验、数字签名、鉴权协议

    • MD5
    // md5加密 
    result := md5.Sum([]byte(str))
    fmt.Printf("MD5:%x\n", result)
    
    • SHA1
    // sha256加密字符串
    str := "hello world"
    sum := sha256.Sum256([]byte(str))
    fmt.Printf("SHA256:%x\n", sum)
    
    // sha256加密文件内容
    func fileSha156() {
        file, err := os.OpenFile("e:/test.txt", os.O_RDONLY, 0777)
        if err != nil {
            panic(err)
        }
        defer file.Close()
    
        h := sha256.New()
        // 将文件内容拷贝到sha256中
        io.Copy(h, file)
        fmt.Printf("%x\n", h.Sum(nil))
    }
    
    • HMAC
      哈希算法加盐
    • CRC
      用于差错校验

    Hash算法的作用

    1. 文件校验
    2. 数字签名
    3. 鉴权协议

    参考链接:

    相关文章

      网友评论

          本文标题:加密算法

          本文链接:https://www.haomeiwen.com/subject/ndtgyhtx.html