附近小店
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

crypto.go 2.6 KiB

2ヶ月前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. package weapp
  2. import (
  3. "bytes"
  4. "crypto/aes"
  5. "crypto/cipher"
  6. "crypto/rand"
  7. "crypto/sha1"
  8. "encoding/hex"
  9. "errors"
  10. "io"
  11. "sort"
  12. "strings"
  13. )
  14. const pkcs7blocksize = 32
  15. // pkcs7encode 对需要加密的明文进行填充补位
  16. // plaintext 需要进行填充补位操作的明文
  17. // 返回补齐明文字符串
  18. func pkcs7encode(plaintext []byte) []byte {
  19. //计算需要填充的位数
  20. pad := pkcs7blocksize - len(plaintext)%pkcs7blocksize
  21. if pad == 0 {
  22. pad = pkcs7blocksize
  23. }
  24. //获得补位所用的字符
  25. text := bytes.Repeat([]byte{byte(pad)}, pad)
  26. return append(plaintext, text...)
  27. }
  28. // pkcs7decode 对解密后的明文进行补位删除
  29. // plaintext 解密后的明文
  30. // 返回删除填充补位后的明文和
  31. func pkcs7decode(plaintext []byte) []byte {
  32. ln := len(plaintext)
  33. // 获取最后一个字符的 ASCII
  34. pad := int(plaintext[ln-1])
  35. if pad < 1 || pad > pkcs7blocksize {
  36. pad = 0
  37. }
  38. return plaintext[:(ln - pad)]
  39. }
  40. // 对加密数据包进行签名校验,确保数据的完整性。
  41. func validateSignature(signature string, parts ...string) bool {
  42. return signature == createSignature(parts...)
  43. }
  44. // 校验用户数据数据
  45. func validateUserInfo(signature, rawData, ssk string) bool {
  46. raw := sha1.Sum([]byte(rawData + ssk))
  47. return signature == hex.EncodeToString(raw[:])
  48. }
  49. // 拼凑签名
  50. func createSignature(parts ...string) string {
  51. sort.Strings(parts)
  52. raw := sha1.Sum([]byte(strings.Join(parts, "")))
  53. return hex.EncodeToString(raw[:])
  54. }
  55. // cbcEncrypt CBC 加密数据
  56. func cbcEncrypt(key, plaintext, iv []byte) ([]byte, error) {
  57. if len(plaintext)%aes.BlockSize != 0 {
  58. return nil, errors.New("plaintext is not a multiple of the block size")
  59. }
  60. block, err := aes.NewCipher(key)
  61. if err != nil {
  62. return nil, err
  63. }
  64. ciphertext := make([]byte, aes.BlockSize+len(plaintext))
  65. iv = iv[:aes.BlockSize]
  66. if _, err := io.ReadFull(rand.Reader, iv); err != nil {
  67. return nil, err
  68. }
  69. mode := cipher.NewCBCEncrypter(block, iv)
  70. mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
  71. return ciphertext, nil
  72. }
  73. // CBC解密数据
  74. func cbcDecrypt(key, ciphertext, iv []byte) ([]byte, error) {
  75. block, err := aes.NewCipher(key)
  76. if err != nil {
  77. return nil, err
  78. }
  79. size := aes.BlockSize
  80. iv = iv[:size]
  81. // ciphertext = ciphertext[size:] TODO: really useless?
  82. if len(ciphertext) < size {
  83. return nil, errors.New("ciphertext too short")
  84. }
  85. if len(ciphertext)%size != 0 {
  86. return nil, errors.New("ciphertext is not a multiple of the block size")
  87. }
  88. mode := cipher.NewCBCDecrypter(block, iv)
  89. mode.CryptBlocks(ciphertext, ciphertext)
  90. return pkcs7decode(ciphertext), nil
  91. }