ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

区块链 - 密码学

2021-10-09 21:03:14  阅读:179  来源: 互联网

标签:src return nil err byte 区块 密码学 block


第一章 密码学

第一节 密码介绍

一、为什么要加密?

保证数据的安全

小明–>小红:

  • 原文:放学后,学校后门小树林见

  • 密钥:+2

  • 密文:让他放引入学恩替后,润如学请问校嗯嗯后学校门抽成小版本树版本林你能见

  • 密钥(密码):-2

  • 解密:让他放引入学恩替后,润如学请问校嗯嗯后学校门抽成小版本树版本林你能见

    • 放学后,学校后门小树林见

二、常见的几种加密算法

1.编码解码

2.哈希加密

3.对称加密

4.非对称加密

5.数字签名

三、加密三要素

1.明文/密文

2.密钥

3.加密算法/解密算法

第二节 解码编码

一、常见的编码

  1. base64:26个小写字母、26个大写字母、10个数字、/、+

  2. base58(区块链):去掉6个容易混淆的,去掉0,大写O、大写I、小写L、/、+(64位-6位,还剩58位)

    • /、+影响双击选择

二、go实现base64编码、解码

  • 编码

使用:encoding/base64

input := []byte(“hello world”)

encodeString := base64.StdEncoding.EncodeToString(input)

在url中使用:

uEnc := base64.URLEncoding.EncodeToString([]byte(input))

  • 解码

decodeBytes, err := base64.StdEncoding.DecodeString(encodeString)

在url中使用:

uDec, err := base64.URLEncoding.DecodeString(uEnc)

三、go实现base58编码解码、解码

base58编码表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xwtlfxQk-1633784349826)(file:///C:/Users/ZHOUWE~1/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg)]

字符1代表0,字符2代表1,…,字符z代表57

  • 编码

  • 流程:

    • 将字符串的每个字节换算成ASCII**(256进制,2^8(二进制)**),字符串实际上就是256进制的数字组合
    • 将256进制的数字转换成10进制数字
    • 将10进制数字转换成58进制数字(对比10进制转2进制,不断取余,0用编码1来代表)
    • 将58进制数字对照58编码表找到对应的字符
  • 256进制转十进制:

    • h:104
    • a:97
    • 104*256+97=26721
  • package utils
    import (
      "fmt"
      "math/big"
      "bytes"
    )
    //58进制规则
    var b58 = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
    // base58编码
    func Base58Encoding(src string) (string) {
      // he : 104 101 --> 104*256 + 101 = 26725
      // 26725 / 58 =  15 16 17
      //1.将字符串换算成ASCII码
      src_byte := []byte(src)
      // 转成十进制
      i := big.NewInt(0).SetBytes(src_byte)
       var mod_slice []byte
       // 循环取余
       //for i.Cmp(big.NewInt(0)) != 0 {
       for i.Cmp(big.NewInt(0)) > 0 {
        mod := big.NewInt(0)
         i58 := big.NewInt(58)
         // 取余
         i.DivMod(i,i58,mod)
         // 将余数添加到数组中
         mod_slice = append(mod_slice, b58[mod.Int64()])
       }
       // 把0使用字节'1'代替
       for _,s := range src_byte {
         if s != 0 {
           break
        }
         mod_slice = append(mod_slice, byte('1'))
       }
      // 反转byte数组
      //ret_mod_slice := ReverseByteArr(mod_slice)
      ret_mod_slice := ReverseByteArr2(mod_slice)
      fmt.Println(ret_mod_slice)
      return string(ret_mod_slice)
    }
    
    // byte数组进行反转方式
    func ReverseByteArr(b []byte) []byte{
      for i:=0; i<len(b)/2;i++ {
        b[i],b[len(b)-1-i] = b[len(b)-1-i],b[i]
      }
      return b
    }
    // byte数组进行反转方式2
    func ReverseByteArr2(b []byte) []byte{
      for i,j:=0,len(b)-1;i<j;i,j = i+1,j-1{
        b[i] ,b[j] = b[j],b[i]
      }
      return b
    }
    - 解码
    // base58解码(将编码流程反过来)
    func Base58Decoding(src string) string{
      // 转成byte数组
      src_byte := []byte(src)
      // 这里得到的是十进制
      ret := big.NewInt(0)
      for _, b := range src_byte {
        i := bytes.IndexByte(b58,b)
        fmt.Println(i)
        // 乘回去
        ret.Mul(ret,big.NewInt(58))
        // 相加
        ret.Add(ret,big.NewInt(int64(i)))
      }
      return string(ret.Bytes())
    }
    

第三节 哈希算法

一、特点

**不可逆:**无法从一个哈希值恢复原始数据,哈希并不加密

**唯一性:**对于特定的数据 只能有一个哈希 并且这个哈希是唯一的

防篡改:改变输入数据中的一个字节 导致输出一个完全不同的哈希值

注册:账号,密码 存到数据库中的密码是md5加密后的

登录:将密码经过md5编码比对数据库中的密码

二、常用的哈希算法

  • MD4
  • MD5
  • hash1
  • sha224
  • sha256
  • sha384
  • sha512

性能 : md4>md5>sha224>sha256>sha384>sha512

内存消耗:md5>md4>sha512>sha384>sha256=sha224

建议平常使用sha256即可,安全性可靠且消耗资源不高。

三、go实现MD4加密

src_byte := []byte(src)
//md4计算
md4_new := md4.New()
md4Bytes := md4_new.Sum(src_byte)
md4String := hex.EncodeToString(md4Bytes)

四、go实现MD5加密

src_byte := []byte(src)
//md5计算
md5_new := md5.New()
md5Bytes := md5_new.Sum(src_byte)
md5String := hex.EncodeToString(md5Bytes)

五、go实现SHA256加密

func GenSha256(src string) string {
  src_byte := []byte(src)
  hash := sha256.New()
  sha256Bytes := hash.Sum(src_byte)
  sha256String := hex.EncodeToString(sha256Bytes[:])
  return sha256String
 }

第四节 对称加密

一、特点

加密和解密使用的是同一个密钥

数据私密性双向保证,也就是加密和解密都不能泄露密码

二、优点

加密效率高,适合大些的数据加密

三、缺点

安全性相对非对称低

四、具体的加密方式

1. AES加密

  • AES-128加密:key长度16字节
  • AES-192加密:key长度24字节
  • AES-256加密:key长度32字节
package utils
import (
  "crypto/aes"
  "fmt"
  "bytes"
  "encoding/base64"
  "errors"
)
//key可以为16,24,32位的
var key []byte = []byte("hallenhallenhall") //key首字母小写,其他包不能引用(这里就是密钥)
// 填充密码长度,填充依据为,block.BlockSize(),密码长度必须为block.BlockSize()的整数倍
func PadPwd(src_byte []byte,block_size int) []byte{
  // 假设密码长度16,区块长度 13    需要填充个数16-13 = 10
  pad_num := block_size - len(src_byte) % block_size
  ret := bytes.Repeat([]byte{byte(pad_num)},pad_num) //ret是要填充的数组成的数组
  src_byte = append(src_byte, ret...) //拼接 ret...就是取数组中所有的值
  return src_byte
}
// 加密
func AesEncoding(src string) (string,error) {
  src_byte := []byte(src)
  // safer
  block,err := aes.NewCipher(key) //block是对象,里面是很多块
  if err != nil {
     return src,err
  }
  // 密码填充,加密的字符串不够block.BlockSize整数倍,要进行填充
  new_src_byte := PadPwd(src_byte,block.BlockSize())
  dst := make([]byte,len(new_src_byte)) //用于存放加密后的结果,这里使用切片
  block.Encrypt(dst,new_src_byte) //加密dst存放结果,其为byte数组
  // base64编码
  pwd := base64.StdEncoding.EncodeToString(dst)
  return pwd,nil
}
// 解密
func AesDecoding(pwd string) (string,error) {
  pwd_byte := []byte(pwd)
  pwd_byte,err := base64.StdEncoding.DecodeString(pwd)
  if err != nil {
    return pwd,err
  }
  block,err_block := aes.NewCipher(key)
  if err_block != nil {
    return pwd,err_block
  }
  dst := make([]byte,len(pwd_byte))
  block.Decrypt(dst,pwd_byte) //解密 dst存放结果,其为byte数组
  // 填充的要去掉
  dst,_ = UnPadPwd(dst)
  return string(dst),nil
}
//用于解密 去掉填充的部分
func UnPadPwd(dst []byte) ([]byte,error) {
  if len(dst) <= 0 {
    return dst,errors.New("长度有误")
  }
 // 去掉的长度 填充的值就是要填充的长度,所有取最好一个值,他肯定就是填充的长度
  unpad_num := int(dst[len(dst)-1])
  return dst[:(len(dst)-unpad_num)],nil //切片
}

2. des 加密:支持字节长度是8

package utils
import (
  "crypto/des"
  "encoding/base64"
)
// 只支持8字节的长度
var des_key []byte = []byte("hallenha")//key首字母小写,其他包不能引用(这里就是密钥)
// 加密
func DesEncoding(src string) (string,error) {
  src_byte := []byte(src)
  block ,err := des.NewCiphe(des_key)
  if err != nil {
   return src,err
  }
  // 密码填充
  new_src_byte := PadPwd(src_byte,block.BlockSize())
  dst := make([]byte,len(new_src_byte))
  block.Encrypt(dst,new_src_byte)
  // base64编码
  pwd := base64.StdEncoding.EncodeToString(dst)
  return pwd,nil
}
// 解密
func DesDecoding(pwd string) (string,error) {
  pwd_byte,err := base64.StdEncoding.DecodeString(pwd)
  if err != nil {
   return pwd,err
  }
  block,err_block := des.NewCipher(des_key)
  if err_block != nil {
    return pwd,err_block
  }
  dst := make([]byte,len(pwd_byte))
  block.Decrypt(dst,pwd_byte)
  // 填充的要去掉
  dst,_ = UnPadPwd(dst)
  return string(dst),nil
}

3. 3des加密——CBC模式,key长度必须为24

package utils
import (
  "crypto/des"
  "encoding/base64"
)
// 3des的key,长度是24
var tdes_key []byte = []byte("hallenhallenhallenhallen")
// 3des加密
func TDesEncoding(src string) (string,error) {
  src_byte := []byte(src)
  block ,err := des.**NewTripleDESCipher**(tdes_key) // 和des的区别
  if err != nil {
    return src,err
  }
  // 密码填充
  new_src_byte := PadPwd(src_byte,block.BlockSize())
  dst := make([]byte,len(new_src_byte))
  block.Encrypt(dst,new_src_byte)
  // base64编码
  pwd := base64.StdEncoding.EncodeToString(dst)
  return pwd,nil
}
// 3des解密
func TDesDecoding(pwd string) (string,error) {
  pwd_byte,err := base64.StdEncoding.DecodeString(pwd)
  if err != nil {
   return pwd,err
  }
  block,err_block := des.**NewTripleDESCipher**(tdes_key) // 和des的区别
  if err_block != nil {
    return pwd,err_block
  }
  dst := make([]byte,len(pwd_byte))
  block.Decrypt(dst,pwd_byte)
  // 填充的要去掉
  dst,_ = UnPadPwd(dst)
  return string(dst),nil
}

第五节 非对称加密

一、特点

加密和解密的密钥不同,有两个密钥(公钥和私钥)

公钥:可以公开的密钥;公钥加密,私钥解密

私钥:私密的密钥;私钥加密,公钥解密

私密单方向保证,只要有一方不泄露就没问题

二、优点

安全性相对对称加密高

三、缺点

加密效率低,适合小数据加密

四、场景分析

对哪一方更重要,哪一方就拿私钥

  1. 登录认证

私钥在客户端,个人信息在客户端保存

公钥在服务器,获取个人数据

假如:不成立的

​ 公钥在用户手里

​ 私钥在服务端

  1. A和B两个人,信息只允许B阅读

公钥在A

私钥在B

假如:所有人都可以阅读

​ 公钥在B

​ 私钥在A

五、具体的加密方式

RSA:三位作者的首字母

消息发送方利用对方的公钥进行加密,消息接受方收到密文时使用自己的私钥进行解密

注意:

  • 公钥和密钥生成的时候要有一种关联
  • 要把密钥和公钥保存起来
package utils
import (
  "crypto/rsa"
  "crypto/rand"
  "fmt"
  "crypto/x509"
  "encoding/pem"
  "os"
)
// 保存生成的公钥和密钥
func SaveRsaKey(bits int) (error){
//privateKey是指针结构
  privateKey,err := rsa.GenerateKey(rand.Reader,bits)
  if err != nil {
    fmt.Println(err)
    return err
}
//公钥要和私钥产生关联,//privateKey是一个结构体
  publicKey := privateKey.PublicKey
  // 使用x509标准对私钥进行编码,AsN.1编码字符串
  x509_privete := x509.MarshalPKCS1PrivateKey(privateKey)
  // 使用x509标准对公钥进行编码,AsN.1编码字符串
  x509_public := x509.MarshalPKCS1PublicKey(&publicKey)//这里参数为指针类型
  // 对私钥封装block 结构数据
  block_private := pem.Block{Type:"private key",Bytes:x509_privete}
  // 对公钥封装block 结构数据
  block_public := pem.Block{Type:"public key",Bytes:x509_public}
  // 创建存放私钥的文件,文件名后缀为.pem
  privateFile,err_pri := os.Create("privateKey.pem")
  if err_pri != nil {
    return err_pri
}
//defer释放资源,将文件关闭
  defer privateFile.Close()
//将私钥写入文件,block_private为指针类型,取地址符获得其内容
pem.Encode(privateFile,&block_private)
  // 创建存放公钥的文件,文件名后缀为.pem
  publicFile,err_pub := os.Create("publicKey.pem")
  if err_pub != nil {
    return err_pub
}
//defer释放资源,将文件关闭
defer publicFile.Close()
//将公钥写入文件,block_public为指针类型,取地址符获得其内容
  pem.Encode(publicFile,&block_public)
  return nil
}
// 加密
func RsaEncoding(src ,file_path string) ([]byte,error){
  src_byte := []byte(src)
  // 打开文件
  file,err := os.Open(file_path)
  if err != nil {
    return src_byte,err
  }
  // 获取文件信息
  file_info,err_info := file.Stat()
  if err_info != nil {
    return src_byte,err_info
  }
  // 存储读取文件内容所用的切片
  key_bytes := make([]byte,file_info.Size())
  // 读取内容到容器里面
  file.Read(key_bytes)
  // pem解码
  block,_ := pem.Decode(key_bytes)
  // x509解码
  publicKey ,err_pb := x509.ParsePKCS1PublicKey(block.Bytes)
  if err_pb != nil {
    return src_byte,err_pb
  }
  // 使用公钥对明文进行加密
  ret_byte,err_ret := rsa.EncryptPKCS1v15(rand.Reader,publicKey,src_byte)
  if err_ret != nil {
    return src_byte,err_ret
  }
  return ret_byte,nil
}
// 解密
func RsaDecoding(src_byte []byte,file_path string) ([]byte,error) {
  // 打开文件
  file,err := os.Open(file_path)
  if err != nil {
    return src_byte,err
  }
  // 获取文件信息
  file_info,err_info := file.Stat()
  if err_info != nil {
    return src_byte,err_info
  }
  // 读取文件内容
  key_bytes := make([]byte,file_info.Size())
  // 读取内容到容器里面
  file.Read(key_bytes)
  // pem解码
  block,_ := pem.Decode(key_bytes)
  // x509解码
  privateKey ,err_pb := x509.ParsePKCS1PrivateKey(block.Bytes)
  if err_pb != nil {
    return src_byte,err_pb
  }
  // 进行解密
  ret_byte, err_ret := rsa.DecryptPKCS1v15(rand.Reader,privateKey,src_byte)
  if err_ret != nil {
    return src_byte,err_ret
  }
  return ret_byte,nil
}

第六节 数字签名

一、数字签名介绍

数字签名相当于纸质合同的签字章盖

防篡改、防伪装、防否认

rsa

  • 公钥加密
  • 私钥解密

rsa数字签名:(数字签名与rsa加密正好相反,更具作用的目的不同)

  • 私钥签名
  • 公钥验证签名

二、go实现数字签名算法

package utils
 import (
  "crypto"
  "crypto/rand"
  "crypto/rsa"
  "crypto/sha256"
  "crypto/x509"
  "encoding/pem"
  "os"
 )
 //保存生成的公钥和密钥
 func SaveRsaSignKey(bits int)error{
  //privateKey是指针结构
  privateKey, err := rsa.GenerateKey(rand.Reader, bits)
  if err!=nil{
    return err
  }
  //privateKey是一个结构体,公钥要和私钥产生关联
  publicKey := privateKey.PublicKey
  // 使用x509标准对私钥进行编码,AsN.1编码字符串
  x509_privete := x509.MarshalPKCS1PrivateKey(privateKey)
  // 使用x509标准对公钥进行编码,AsN.1编码字符串,参数为指针
  x509_public := x509.MarshalPKCS1PublicKey(&publicKey)
  // 对私钥封装block 结构数据
  block_private := pem.Block{Type:"private key",Bytes:x509_privete}
  // 对公钥封装block 结构数据
  block_public := pem.Block{Type:"public key",Bytes:x509_public}
  // 创建存放私钥的文件,文件名后缀为.pem
  privateFile,err_pri := os.Create("privateKey.pem")
  if err_pri != nil {
    return err_pri
  }
  //defer释放资源,将文件关闭
  defer privateFile.Close()
  //将私钥写入文件,block_private为指针类型,取地址符获得其内容
  pem.Encode(privateFile,&block_private)
  // 创建存放公钥的文件,文件名后缀为.pem
  publicFile,err_pub := os.Create("publicKey.pem")
  if err_pub != nil {
    return err_pub
  }
  //defer释放资源,将文件关闭
  defer publicFile.Close()
  //将公钥写入文件,block_public为指针类型,取地址符获得其内容
  pem.Encode(publicFile,&block_public)
  return nil
 }
 
 //获取私钥
 func GetPivateKey(file_path string)(*rsa.PrivateKey,error) {
  // 打开文件
  file,err := os.Open(file_path)
  if err != nil {
    return &rsa.PrivateKey{},err
  }
  // 获取文件信息
  file_info,err_info := file.Stat()
  if err_info != nil {
    return &rsa.PrivateKey{},err_info
  }
  // 读取文件内容
  key_bytes := make([]byte,file_info.Size())
  // 读取内容到容器里面
  file.Read(key_bytes)
  // pem解码
  block,_ := pem.Decode(key_bytes)
  // x509解码
  privateKey ,err_pb := x509.ParsePKCS1PrivateKey(block.Bytes)
  if err_pb != nil {
    return &rsa.PrivateKey{},err_pb
  }
  return privateKey,nil
 }
 //获取公钥
 func GetPublicKey(file_path string)(*rsa.PublicKey,error){
  //打开文件
  file, err := os.Open(file_path)
  if err!=nil{
    return &rsa.PublicKey{},err
  }
  // 获取文件信息
  file_info, err_info := file.Stat()
  if err_info != nil {
    return &rsa.PublicKey{},err_info
  }
  // 存储读取文件内容所用的切片
  key_bytes := make([]byte,file_info.Size())
  // 读取内容到容器里面
  file.Read(key_bytes)
  // pem解码
  block,_ := pem.Decode(key_bytes)
  // x509解码
  publicKey ,err_pb := x509.ParsePKCS1PublicKey(block.Bytes)
  if err_pb != nil {
    return &rsa.PublicKey{},err_pb
  }
  return publicKey,nil
 }
 //数组签名,使用私钥
 func RsaGetSign(file_path string,src string)([]byte,error){
  //拿到私钥
  privateKey, err := GetPivateKey(file_path)
  if err!=nil{
    return []byte{},err
  }
  hash := sha256.New()
  src_byte := []byte(src)
  hash.Write(src_byte)
  sha_bytes := hash.Sum(nil)
  //签名
  signPKCS1v15, err_sign := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.*SHA256*, sha_bytes)
  if err!=nil{
    return []byte{},err_sign
  }
  return signPKCS1v15,nil
 }
 
 //验证签名,使用的是公钥
 func RsaVarifySign(sign []byte,file_path string,src string)(bool,error){
  publicKey, err := GetPublicKey(file_path)
  if err!=nil{
    return false,nil
  }
  hash := sha256.New()
  src_byte := []byte(src)
  hash.Write(src_byte)
  sha_bytes := hash.Sum(nil)
  err_verify := rsa.VerifyPKCS1v15(publicKey, crypto.*SHA256*, sha_bytes, sign)
  if err_verify!=nil{
    return false,nil
  }
  return true,nil
 }

标签:src,return,nil,err,byte,区块,密码学,block
来源: https://blog.csdn.net/weixin_51490695/article/details/120679070

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有