• 加解密和签名校验工具


    目录

    一、RSA简介

    二、工程目录

    三、RSA Utils

    1、加密与解密

    2、签名与验证签名

    四、其他

    1、不可逆的密码加密工具

    2、JWT

    五、测试

    六、GUI

    七、sys

    八、界面

    1、测试加密

    2、测试解密

    3、测试签名 

    4、验证签名 

    九、浅应用

    十、改进

    十一、参考


    一、RSA简介

    RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制 。
    在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK 。
    正是基于这种理论,1978年出现了著名的RSA算法,它通常是先生成一对RSA密钥,其中之一是保密密钥,由用户保存;另一个为公开密钥,可对外公开,甚至可在网络服务器中注册。为提高保密强度,RSA密钥至少为500位长。这就使加密的计算量很大。为减少计算量,在传送信息时,常采用传统加密方法与公开密钥加密方法相结合的方式,即信息采用改进的DES或IDEA对话密钥加密,然后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不同的密钥解密并可核对信息摘要 。

    ——摘自百度百科

    本文将基于RSA算法实现可视化窗体的加密、解密、签名、校验工具。

    二、工程目录

    ├─cmd 主入口
    ├─files RSA 密钥、加解密后的文件
    ├─gui 可视化窗体
    ├─sys 系统配置
    ├─test 测试
    └─utils 工具

    三、RSA Utils

    1、加密与解密

    需要用到的库

    1. import (
    2. "crypto/rand"
    3. "crypto/rsa"
    4. "crypto/x509"
    5. "encoding/pem"
    6. "io/ioutil"
    7. "log"
    8. "os"
    9. )

     首先生成密钥对

    1. //生成RSA私钥和公钥,保存到文件中
    2. func GenerateRSAKey(bits int) {
    3. //GenerateKey函数使用随机数据生成器random生成一对具有指定字位数的RSA密钥
    4. //Reader是一个全局、共享的密码用强随机数生成器
    5. privateKey, err := rsa.GenerateKey(rand.Reader, bits)
    6. if err != nil {
    7. log.Fatalln(err)
    8. }
    9. //保存私钥
    10. //通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
    11. X509PrivateKey := x509.MarshalPKCS1PrivateKey(privateKey)
    12. //使用pem格式对x509输出的内容进行编码
    13. //创建文件保存私钥
    14. privateFile, err := os.Create("./files/private.pem")
    15. if err != nil {
    16. log.Fatalln(err)
    17. }
    18. defer privateFile.Close()
    19. //构建一个pem.Block结构体对象
    20. privateBlock := pem.Block{Type: "RSA Private Key", Bytes: X509PrivateKey}
    21. //将数据保存到文件
    22. pem.Encode(privateFile, &privateBlock)
    23. //保存公钥
    24. //获取公钥的数据
    25. publicKey := privateKey.PublicKey
    26. //X509对公钥编码
    27. X509PublicKey, err := x509.MarshalPKIXPublicKey(&publicKey)
    28. if err != nil {
    29. log.Fatalln(err)
    30. }
    31. //pem格式编码
    32. //创建用于保存公钥的文件
    33. publicFile, err := os.Create("./files/public.pem")
    34. if err != nil {
    35. log.Fatalln(err)
    36. }
    37. defer publicFile.Close()
    38. //创建一个pem.Block结构体对象
    39. publicBlock := pem.Block{Type: "RSA Public Key", Bytes: X509PublicKey}
    40. //保存到文件
    41. pem.Encode(publicFile, &publicBlock)
    42. }

    RSAEncrypt 函数使用公钥对信息进行加密,RSADecrypt 函数使用密钥对信息进行解密,加密和解密都进行一次 BASE64 处理。

    1. //RSA加密
    2. func RSAEncrypt(plainText []byte, saveFilePath, path string) []byte {
    3. //打开文件
    4. file, err := os.Open(path)
    5. if err != nil {
    6. log.Fatalln(err)
    7. }
    8. defer file.Close()
    9. //读取文件的内容
    10. info, _ := file.Stat()
    11. buf := make([]byte, info.Size())
    12. file.Read(buf)
    13. //pem解码
    14. block, _ := pem.Decode(buf)
    15. //x509解码
    16. publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
    17. if err != nil {
    18. log.Fatalln(err)
    19. }
    20. //类型断言
    21. publicKey := publicKeyInterface.(*rsa.PublicKey)
    22. //对明文进行加密
    23. cipherText, err := rsa.EncryptPKCS1v15(rand.Reader, publicKey, plainText)
    24. if err != nil {
    25. log.Fatalln(err)
    26. }
    27. //保存密文
    28. encode := Base64Encode(cipherText)
    29. log.Println("base64 ", encode)
    30. saveCipherText(encode, saveFilePath)
    31. //返回密文
    32. return encode
    33. }

    保存密文

    1. // 保存密文
    2. func saveCipherText(cipherText []byte, path string) {
    3. cipherFile, err := os.Create(path)
    4. if err != nil {
    5. log.Fatalln(err)
    6. return
    7. }
    8. defer cipherFile.Close()
    9. _, err = cipherFile.Write(cipherText)
    10. if err != nil {
    11. log.Fatalln(err)
    12. return
    13. }
    14. log.Println("CipherText has been save as ", path)
    15. }

    解密

    1. //RSA解密
    2. func RSADecrypt(cipherText []byte, path string) []byte {
    3. //打开文件
    4. file, err := os.Open(path)
    5. if err != nil {
    6. log.Fatalln(err)
    7. }
    8. defer file.Close()
    9. //获取文件内容
    10. info, _ := file.Stat()
    11. buf := make([]byte, info.Size())
    12. file.Read(buf)
    13. //pem解码
    14. block, _ := pem.Decode(buf)
    15. //X509解码
    16. privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    17. if err != nil {
    18. log.Fatalln(err)
    19. }
    20. //对密文进行解密
    21. decode, err := Base64Decode(cipherText)
    22. if err != nil {
    23. log.Fatalln(err)
    24. }
    25. plainText, _ := rsa.DecryptPKCS1v15(rand.Reader, privateKey, decode)
    26. //返回明文
    27. return plainText
    28. }

    从文件中读取密文并解密

    1. // 从文件中读取密文并解密
    2. func RSADecryptFromFile(cipherFilePath string, path string) []byte {
    3. f, err := os.Open(cipherFilePath)
    4. if err != nil {
    5. log.Fatalln(err)
    6. return nil
    7. }
    8. defer f.Close()
    9. all, err := ioutil.ReadAll(f)
    10. if err != nil {
    11. log.Fatalln(err)
    12. return nil
    13. }
    14. return RSADecrypt(all, path)
    15. }

    2、签名与验证签名

    需要用到的库

    1. import (
    2. "crypto"
    3. "crypto/rand"
    4. "crypto/rsa"
    5. "crypto/x509"
    6. "encoding/base64"
    7. "encoding/pem"
    8. "errors"
    9. "io/ioutil"
    10. )

    解析密钥对

    1. //读取公钥文件,解析出公钥对象
    2. func ReadParsePublicKey(filename string) (*rsa.PublicKey, error) {
    3. //--1.读取公钥文件,获取公钥字节
    4. publicKeyBytes, err := ioutil.ReadFile(filename)
    5. if err != nil {
    6. return nil, err
    7. }
    8. //--2.解码公钥字节,生成加密对象
    9. block, _ := pem.Decode(publicKeyBytes)
    10. if block == nil {
    11. return nil, errors.New("公钥信息错误")
    12. }
    13. //--3.解析DER编码的公钥,生成公钥接口
    14. publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
    15. if err != nil {
    16. return nil, err
    17. }
    18. //--4.公钥接口转型成公钥对象
    19. publicKey := publicKeyInterface.(*rsa.PublicKey)
    20. return publicKey, nil
    21. }
    22. //读取私钥文件,解析出私钥对象
    23. func ReadParsePrivateKey(filename string) (*rsa.PrivateKey, error) {
    24. //--1.读取私钥文件,获取私钥字节
    25. privateKeyBytes, _ := ioutil.ReadFile(filename)
    26. //--2.对私钥文件进行编码,生成加密对象
    27. block, _ := pem.Decode(privateKeyBytes)
    28. if block == nil {
    29. return nil, errors.New("私钥信息错误")
    30. }
    31. //3.解析DER编码的私钥,生成私钥对象
    32. privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
    33. if err != nil {
    34. return nil, err
    35. }
    36. return privateKey, err
    37. }

    使用 RSASign 函数进行私钥签名

    1. func RSASign(data []byte, filename string) (string, error) {
    2. //1.选择hash算法,对需要签名的数据进行hash运算
    3. myhash := crypto.SHA256
    4. hashInstance := myhash.New()
    5. hashInstance.Write(data)
    6. hashed := hashInstance.Sum(nil)
    7. //2.读取私钥文件,解析出私钥对象
    8. privateKey, err := ReadParsePrivateKey(filename)
    9. if err != nil {
    10. return "", err
    11. }
    12. //3.RSA数字签名
    13. bytes, err := rsa.SignPKCS1v15(rand.Reader, privateKey, myhash, hashed)
    14. if err != nil {
    15. return "", err
    16. }
    17. return base64.StdEncoding.EncodeToString(bytes), nil
    18. }

    RSAVerify 函数进行公钥验证签名

    1. //公钥验证数据签名是否正确
    2. func RSAVerify(data []byte, base64Sig, filename string) error {
    3. //- 对base64编码的签名内容进行解码,返回签名字节
    4. bytes, err := base64.StdEncoding.DecodeString((base64Sig))
    5. if err != nil {
    6. return err
    7. }
    8. //- 选择hash算法,对需要签名的数据进行hash运算
    9. myhash := crypto.SHA256
    10. hashInstance := myhash.New()
    11. hashInstance.Write(data)
    12. hashed := hashInstance.Sum(nil)
    13. //- 读取公钥文件,解析出公钥对象
    14. publicKey, err := ReadParsePublicKey(filename)
    15. if err != nil {
    16. return err
    17. }
    18. //- RSA验证数字签名
    19. return rsa.VerifyPKCS1v15(publicKey, myhash, hashed, bytes)
    20. }

    四、其他

    1、不可逆的密码加密工具

    通常用于密码的加密保存,使用 CompareHashAndPassword 函数校验密码,而不能解密密码。

    1. package utils
    2. import (
    3. "fmt"
    4. "golang.org/x/crypto/bcrypt"
    5. )
    6. // 不可逆的密码加密工具封装
    7. // 加密使用 bcrypt.GenerateFromPassword
    8. // 比对密码时使用 bcrypt.CompareHashAndPassword
    9. //加密处理
    10. func EncodePassword(password string) (string, error) {
    11. hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
    12. if err != nil {
    13. fmt.Println(err)
    14. return "", err
    15. }
    16. // 保存在数据库的密码,虽然每次生成都不同,只需保存一份即可
    17. return string(hash), nil
    18. }
    19. func ComparePassword(databasePwd, loginPwd string) bool {
    20. // 密码验证
    21. err := bcrypt.CompareHashAndPassword([]byte(databasePwd), []byte(loginPwd))
    22. if err != nil {
    23. fmt.Println("pwd wrong")
    24. return false
    25. } else {
    26. fmt.Println("pwd ok")
    27. return true
    28. }
    29. }

    2、JWT

    1. package utils
    2. import (
    3. "encryptTool/sys"
    4. "fmt"
    5. "github.com/dgrijalva/jwt-go"
    6. )
    7. // 定义一个jwt对象
    8. type JWT struct {
    9. // 声明签名信息
    10. SigningKey []byte
    11. }
    12. // 初始化jwt对象
    13. func NewJWT() *JWT {
    14. return &JWT{
    15. []byte(sys.SigningKey),
    16. }
    17. }
    18. // 自定义有效载荷(这里采用自定义的 UserCode 和 UserRole 作为有效载荷的一部分)
    19. type CustomClaims struct {
    20. UserCode string `json:"userCode"`
    21. UserRole string `json:"userRole"`
    22. // StandardClaims结构体实现了Claims接口(Valid()函数)
    23. jwt.StandardClaims
    24. }
    25. // 调用jwt-go库生成token
    26. // 指定编码的算法为jwt.SigningMethodHS512
    27. func (j *JWT) CreateToken(claims CustomClaims) (string, error) {
    28. // https://gowalker.org/github.com/dgrijalva/jwt-go#Token
    29. // 返回一个token的结构体指针
    30. token := jwt.NewWithClaims(jwt.SigningMethodHS512, claims)
    31. return token.SignedString(j.SigningKey)
    32. }
    33. // token解码
    34. func (j *JWT) ParserToken(tokenString string) (*CustomClaims, error) {
    35. // https://gowalker.org/github.com/dgrijalva/jwt-go#ParseWithClaims
    36. // 输入用户自定义的Claims结构体对象,token,以及自定义函数来解析token字符串为jwt的Token结构体指针
    37. // Keyfunc是匿名函数类型: type Keyfunc func(*Token) (interface{}, error)
    38. // func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) {}
    39. token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
    40. return j.SigningKey, nil
    41. })
    42. if err != nil {
    43. // https://gowalker.org/github.com/dgrijalva/jwt-go#ValidationError
    44. // jwt.ValidationError 是一个无效token的错误结构
    45. if ve, ok := err.(*jwt.ValidationError); ok {
    46. // ValidationErrorMalformed是一个uint常量,表示token不可用
    47. if ve.Errors&jwt.ValidationErrorMalformed != 0 {
    48. return nil, fmt.Errorf(sys.TokenDisabled)
    49. // ValidationErrorExpired表示Token过期
    50. } else if ve.Errors&jwt.ValidationErrorExpired != 0 {
    51. return nil, fmt.Errorf(sys.TokenExpired)
    52. // ValidationErrorNotValidYet表示无效token
    53. } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
    54. return nil, fmt.Errorf(sys.TokenInvalid)
    55. } else {
    56. return nil, fmt.Errorf(sys.TokenDisabled)
    57. }
    58. }
    59. }
    60. // 将token中的claims信息解析出来并断言成用户自定义的有效载荷结构
    61. if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
    62. return claims, nil
    63. }
    64. return nil, fmt.Errorf(sys.TokenInvalid)
    65. }

    五、测试

    1. // SIGN => VERIFY
    2. func TestV1() {
    3. str := "will be best"
    4. base64Sig, _ := utils.RSASign([]byte(str), sys.PRIVATE_KEY_PATH)
    5. fmt.Println("签名后信息", base64Sig)
    6. err := utils.RSAVerify([]byte(str), base64Sig, sys.PUBLIC_KEY_PATH)
    7. if err == nil {
    8. fmt.Println("验证签名ok!")
    9. } else {
    10. fmt.Println("验证失败!")
    11. }
    12. }
    13. // ENCODE => DECODE
    14. func TestV2() {
    15. //生成密钥对,保存到文件;若已有密钥对则无需再生成
    16. // utils.GenerateRSAKey(2048)
    17. // 需要加密的明文
    18. message := []byte("hello,world")
    19. fmt.Println("加密原文:", string(message))
    20. //加密
    21. cipherText := utils.RSAEncrypt(message, sys.CIPHER_FILE_PATH, sys.PUBLIC_KEY_PATH)
    22. fmt.Println("加密后为:")
    23. for _, v := range cipherText {
    24. fmt.Printf("%s", string(v))
    25. }
    26. //解密
    27. plainText := utils.RSADecrypt(cipherText, sys.PRIVATE_KEY_PATH)
    28. fmt.Println("解密后为:", string(plainText))
    29. // 读取加密文件进行解密
    30. msg := utils.RSADecryptFromFile(sys.CIPHER_FILE_PATH, sys.PRIVATE_KEY_PATH)
    31. fmt.Println("文件解密后为:", string(msg))
    32. }
    33. func TestV3() {
    34. loginPassword := "123456"
    35. password, err := utils.EncodePassword(loginPassword)
    36. if err != nil {
    37. fmt.Println(err)
    38. }
    39. fmt.Println("EncodePassword ", password)
    40. if utils.ComparePassword(password, loginPassword) {
    41. fmt.Println("password match")
    42. } else {
    43. fmt.Println("password error")
    44. }
    45. }
    46. func TestV4() {
    47. jwt := utils.NewJWT()
    48. token, err := jwt.CreateToken(utils.CustomClaims{UserCode: "user", UserRole: "role"})
    49. if err != nil {
    50. fmt.Println(err)
    51. }
    52. fmt.Println("CreateToken ", token)
    53. parserToken, err := jwt.ParserToken(token)
    54. if err != nil {
    55. fmt.Println(err)
    56. }
    57. fmt.Println("ParserToken ", parserToken)
    58. }
    59. //aGVsbG8gd29ybGQ=
    60. //hello world
    61. func TestBase64() {
    62. // 标准Base64编码
    63. src := "hello world"
    64. res := base64.StdEncoding.EncodeToString([]byte(src))
    65. fmt.Println(res) // aGVsbG8gd29ybGQ=
    66. // 标准Base64解码
    67. s, err := base64.StdEncoding.DecodeString(res)
    68. fmt.Println(string(s), err) // hello world
    69. }

    六、GUI

    1. package gui
    2. import (
    3. "encryptTool/sys"
    4. "encryptTool/utils"
    5. "fmt"
    6. "fyne.io/fyne/app"
    7. "fyne.io/fyne/container"
    8. "fyne.io/fyne/layout"
    9. "fyne.io/fyne/widget"
    10. "log"
    11. "strings"
    12. )
    13. func InitGui() {
    14. application := app.New()
    15. // 输入框
    16. input := widget.NewMultiLineEntry()
    17. // 输出框
    18. output := widget.NewMultiLineEntry()
    19. // 加密
    20. encode := widget.NewButton("Encode", func() {
    21. log.Println("encode", input.Text)
    22. message := []byte(input.Text)
    23. //加密
    24. cipherText := utils.RSAEncrypt(message, sys.CIPHER_FILE_PATH, sys.PUBLIC_KEY_PATH)
    25. fmt.Println("加密后为:")
    26. n := 1
    27. outStr := ""
    28. for _, v := range cipherText {
    29. if n > 50 {
    30. outStr = outStr + "\n"
    31. fmt.Print("\n")
    32. n = 0
    33. }
    34. outStr = outStr +string(v)
    35. fmt.Printf("%s", string(v))
    36. n++
    37. }
    38. output.SetText(outStr)
    39. })
    40. // 解密
    41. decode := widget.NewButton("Decode", func() {
    42. log.Println("decode", input.Text)
    43. //解密
    44. plainText := utils.RSADecrypt([]byte(strings.TrimSpace(input.Text)), sys.PRIVATE_KEY_PATH)
    45. log.Println("解密后为:", string(plainText))
    46. output.SetText(string(plainText))
    47. })
    48. // 签名
    49. sign := widget.NewButton("Sign", func() {
    50. log.Println("sign", input.Text)
    51. base64Sig, _ := utils.RSASign([]byte(input.Text), sys.PRIVATE_KEY_PATH)
    52. log.Println("签名后信息", base64Sig)
    53. n := 1
    54. outStr := ""
    55. for _, v := range base64Sig {
    56. if n > 50 {
    57. outStr = outStr + "\n"
    58. fmt.Print("\n")
    59. n = 0
    60. }
    61. outStr = outStr +string(v)
    62. fmt.Printf("%s", string(v))
    63. n++
    64. }
    65. output.SetText(outStr)
    66. })
    67. // 认证
    68. verify := widget.NewButton("Verify", func() {
    69. log.Println("verify", input.Text)
    70. err := utils.RSAVerify([]byte(strings.TrimSpace(input.Text)), output.Text, sys.PUBLIC_KEY_PATH)
    71. if err == nil {
    72. fmt.Println("验证签名ok!")
    73. output.SetText("验证签名ok!")
    74. } else {
    75. fmt.Println("验证失败!")
    76. output.SetText("验证签名失败!")
    77. }
    78. })
    79. // 新窗口
    80. w := application.NewWindow("EncryptTool")
    81. w.SetContent(container.NewVBox(
    82. widget.NewLabel("Input"),
    83. input,
    84. widget.NewLabel("Output"),
    85. output,
    86. container.NewCenter(
    87. container.NewHBox(
    88. encode,
    89. decode,
    90. sign,
    91. verify,
    92. ),
    93. ),
    94. layout.NewSpacer(),
    95. widget.NewButton("Quit", func() {
    96. application.Quit()
    97. }),
    98. ))
    99. // 居中显示
    100. w.CenterOnScreen()
    101. // 重置窗口大小
    102. w.SetFixedSize(true)
    103. //w.Resize(fyne.NewSize(400, 400))
    104. w.ShowAndRun()
    105. }

    七、sys

    1. package sys
    2. const CIPHER_FILE_PATH string = "./files/TestCipherFile"
    3. const PUBLIC_KEY_PATH string = "./files/public.pem"
    4. const PRIVATE_KEY_PATH string = "./files/private.pem"
    5. const SigningKey string = ""
    6. const TokenDisabled string = "token disabled" // token 不可用
    7. const TokenInvalid string = "token invalid" // token 无效
    8. const TokenExpired string = "token expired" // token 过期

    八、界面

    1、测试加密

    2、测试解密

    3、测试签名 

    4、验证签名 

    九、浅应用

    构建一个签证Center、令牌Center、加解密Center,采用MySQL、Redis等中间件,实现定期动态新增密钥对,Center随机调用密钥对,记录密钥对 ID ,以便后续用相同密钥对进行操作,因此每个使用者调用的加密密钥对都是不同的。

    十、改进

    使用QT、WinForm、Web等前端工具构建更加友好的操作页面;采用多种加密方式供用户选择,而不只是局限于一种加密方式。

    十一、参考

    Go实现RSA数字签名算法(附代码)

    Go语言实现RSA加密解密

    golang gui库fyne的简单尝试

  • 相关阅读:
    英语六级-day3
    ArcGIS制作某村土地利用现状图
    Vue中使用Switch开关用来控制商品的上架与下架情况、同时根据数据库商品的状态反应到前台、前台修改商品状态保存到数据库
    云计算:shell脚本
    vue开启splitChunks分包处理
    ‘conda‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
    pear admin 新增模块流程
    Pytoch随笔(光速入门篇)
    力扣:106. 从中序与后序遍历序列构造二叉树(Python3)
    关于DNS的一些认识
  • 原文地址:https://blog.csdn.net/weixin_47560078/article/details/126042242