<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【GoCN酷Go推薦】crypto 官方加解密庫

          共 21600字,需瀏覽 44分鐘

           ·

          2021-08-05 06:02

          1. 為什么用官方crypto,不用第三方庫

          因為這個加解密庫實際很簡單,并不需要太多的配置以及學(xué)習(xí);且特別是比較敏感的數(shù)據(jù),如果代碼圈發(fā)現(xiàn)有一種算法的加密方式是有漏洞的,第三方庫真不一定會及時解決。

          2. 是什么原因?qū)е挛胰ビ盟?/strong>

          最近對接華立電表與立方停車,哎,看著java代碼發(fā)呆,還望這兩家公司提供多語言的SDK,特別是這幾年日漸火熱的golang。

          3. 怎么使用

          我先上java代碼吧,這樣比較有對比性:

          AESUtils.java

          package src.com.first;

          import java.security.Key;
          import java.security.NoSuchAlgorithmException;
          import java.util.Base64;

          import javax.crypto.Cipher;
          import javax.crypto.KeyGenerator;
          import javax.crypto.SecretKey;
          import javax.crypto.spec.SecretKeySpec;
          import sun.misc.BASE64Decoder;
          import sun.misc.BASE64Encoder;

          /**
           * AES加密類
           *
           */

          public class AESUtils {
              /**
               * 密鑰算法
               */

              private static final String KEY_ALGORITHM = "AES";

              private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";

              /**
               * 初始化密鑰
               *
               * @return byte[] 密鑰
               * @throws Exception
               */

              public static byte[] initSecretKey() {
                  // 返回生成指定算法的秘密密鑰的 KeyGenerator 對象
                  KeyGenerator kg = null;
                  try {
                      kg = KeyGenerator.getInstance(KEY_ALGORITHM);
                  } catch (NoSuchAlgorithmException e) {
                      e.printStackTrace();
                      return new byte[0];
                  }
                  // 初始化此密鑰生成器,使其具有確定的密鑰大小
                  // AES 要求密鑰長度為 128
                  kg.init(128);
                  // 生成一個密鑰
                  SecretKey secretKey = kg.generateKey();
                  return secretKey.getEncoded();
              }

              /**
               * 轉(zhuǎn)換密鑰
               *
               * @param key
               *            二進制密鑰
               * @return 密鑰
               */

              public static Key toKey(byte[] key) {
                  // 生成密鑰
                  return new SecretKeySpec(key, KEY_ALGORITHM);
              }

              /**
               * 加密
               *
               * @param data
               *            待加密數(shù)據(jù)
               * @param key
               *            密鑰
               * @return byte[] 加密數(shù)據(jù)
               * @throws Exception
               */

              public static byte[] encrypt(byte[] data, Key key) throws Exception {
                  return encrypt(data, key, DEFAULT_CIPHER_ALGORITHM);
              }

              /**
               * 加密
               *
               * @param data
               *            待加密數(shù)據(jù)
               * @param key
               *            密鑰
               * @param cipherAlgorithm
               *            加密算法/工作模式/填充方式
               * @return byte[] 加密數(shù)據(jù)
               * @throws Exception
               */

              public static byte[] encrypt(byte[] data, Key key, String cipherAlgorithm) throws Exception {
                  // 實例化
                  Cipher cipher = Cipher.getInstance(cipherAlgorithm);
                  // 使用密鑰初始化,設(shè)置為加密模式
                  cipher.init(Cipher.ENCRYPT_MODE, key);
                  // 執(zhí)行操作
                  return cipher.doFinal(data);
              }

              /**
               * 解密
               *
               * @param data
               *            待解密數(shù)據(jù)
               * @param key
               *            密鑰
               * @return byte[] 解密數(shù)據(jù)
               * @throws Exception
               */

              public static byte[] decrypt(byte[] data, Key key) throws Exception {
                  return decrypt(data, key, DEFAULT_CIPHER_ALGORITHM);
              }

              /**
               * 解密
               *
               * @param data
               *            待解密數(shù)據(jù)
               * @param key
               *            密鑰
               * @param cipherAlgorithm
               *            加密算法/工作模式/填充方式
               * @return byte[] 解密數(shù)據(jù)
               * @throws Exception
               */

              public static byte[] decrypt(byte[] data, Key key, String cipherAlgorithm) throws Exception {
                  // 實例化
                  Cipher cipher = Cipher.getInstance(cipherAlgorithm);
                  // 使用密鑰初始化,設(shè)置為解密模式
                  cipher.init(Cipher.DECRYPT_MODE, key);
                  // 執(zhí)行操作
                  return cipher.doFinal(data);
              }

              public static String showByteArray(byte[] data) {
                  if (null == data) {
                      return null;
                  }
                  StringBuilder sb = new StringBuilder("{");
                  for (byte b : data) {
                      sb.append(b).append(",");
                  }
                  sb.deleteCharAt(sb.length() - 1);
                  sb.append("}");
                  return sb.toString();
              }

              /**
               * 將16進制轉(zhuǎn)換為二進制
               *
               * @param hexStr
               * @return
               */

              public static byte[] parseHexStr2Byte(String hexStr) {

                  if (hexStr.length() < 1)
                      return null;
                  byte[] result = new byte[hexStr.length() / 2];
                  for (int i = 0; i < hexStr.length() / 2; i++) {
                      int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
                      int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
                      result[i] = (byte) (high * 16 + low);
                  }
                  return result;
              }

              /**
               * 將二進制轉(zhuǎn)換成16進制
               *
               * @param buf
               * @return
               */

              public static String parseByte2HexStr(byte buf[]) {
                  StringBuffer sb = new StringBuffer();
                  for (int i = 0; i < buf.length; i++) {
                      String hex = Integer.toHexString(buf[i] & 0xFF);
                      if (hex.length() == 1) {
                          hex = '0' + hex;
                      }
                      sb.append(hex.toUpperCase());
                  }
                  return sb.toString();
              }

              public static void main(String[] args) throws Exception {
                  /*byte[] key = initSecretKey();
                  System.out.println("key:" + Base64.getEncoder().encode(key));
                  System.out.println("key:" + showByteArray(key));*/


                  // 指定key
                  String kekkk = "cmVmb3JtZXJyZWZvcm1lcg==";
                  System.out.println("kekkk:" + showByteArray(Base64.getDecoder().decode(kekkk)));
                  Key k = toKey(Base64.getDecoder().decode(kekkk));


                  String data = "{\"carCode\":\"川A07E0M\",\"inTime\":\"2021-07-27 13:35:10\",\"passTime\":\"2021-07-27 16:50:34\",\"parkID\":\"88\",\"inOrOut\":\"1\",\"GUID\":\"f025e064c1864af68406c797b0999c70\",\"channelID\":\"2\",\"channelName\":\"1號門停車場(出場通道1)\",\"imagePath\":\"http://192.168.0.101:9988\\\\Capture_Images\\\\20210727\\\\川A07E0M\\\\川A07E0M_20210727165034406.jpg\"}";
                  System.out.println("加密前數(shù)據(jù): string:" + data);
                  System.out.println("加密前數(shù)據(jù): byte[]:" + showByteArray(data.getBytes("utf-8")));
                  System.out.println();

                  byte[] encryptData = encrypt(data.getBytes("utf-8"), k);
                  String encryptStr=parseByte2HexStr(encryptData);

                  System.out.println("加密后數(shù)據(jù): byte[]:" + showByteArray(encryptData));
                  System.out.println("加密后數(shù)據(jù): Byte2HexStr:" + encryptStr);
                  System.out.println();

                  byte[] decryptData = decrypt(parseHexStr2Byte(encryptStr), k);
                  System.out.println("解密后數(shù)據(jù): byte[]:" + showByteArray(decryptData));
                  System.out.println("解密后數(shù)據(jù): string:" + new String(decryptData,"utf-8"));

              }
          }

          開始上對比的golang代碼,請注意看我的注釋:

          package lib

          import (
           "bytes"
           "crypto/aes"
           "encoding/base64"
           "encoding/hex"
           "errors"
           "strings"
          )

          type liFangEncryptionInterface interface {
           LiFangEncrypt() (string, error) // 立方停車加密
           LiFangDecrypt() ([]byte, error) // 立方停車解密
          }

          type LiFangEncryptionStruct struct {
           Key               string // 立方密鑰
           NeedEncryptString string // 需要加密的字符串
           NeedDecryptString string // 需要解密的字符串
          }

          // NewLiFangEncryption 創(chuàng)建立方加解密對象
          func NewLiFangEncryption(lfs *LiFangEncryptionStruct) liFangEncryptionInterface {
           return &LiFangEncryptionStruct{
            Key:               lfs.Key,
            NeedEncryptString: lfs.NeedEncryptString,
            NeedDecryptString: lfs.NeedDecryptString,
           }
          }

          func (lfs *LiFangEncryptionStruct) LiFangEncrypt() (encodeStr string, err error) {
           decodeKey, err := base64.StdEncoding.DecodeString(lfs.Key) //這一行是說,將Key密鑰進行base64編碼,這一行與加密 AES/ECB/PKCS5Padding 沒有關(guān)系
           aseByte, err := aesEncrypt([]byte(lfs.NeedEncryptString), decodeKey)//這一行開始就是 AES/ECB/PKCS5Padding 的標準加密了
           encodeStr = strings.ToUpper(hex.EncodeToString(aseByte)) //把加密后的字符串變?yōu)榇髮?/span>
           return
          }

          func (lfs *LiFangEncryptionStruct) LiFangDecrypt() (lastByte []byte, err error) {
           hexStrByte, err := hex.DecodeString(lfs.NeedDecryptString) //這一行的意思,把需要解密的字符串從16進制字符轉(zhuǎn)為2進制byte數(shù)組
           decodeKey, err := base64.StdEncoding.DecodeString(lfs.Key) //這行還是將Key密鑰進行base64編碼
           lastByte, err = aesDecrypt(hexStrByte, decodeKey) // 這里開始就是 AES/ECB/PKCS5Padding 的標準解密了
           return
          }

          func aesEncrypt(src, key []byte) ([]byte, error) {
           block, err := aes.NewCipher(key) // 生成加密用的block對象
           if err != nil {
            return nil, err
           }
           bs := block.BlockSize() // 根據(jù)傳入的密鑰,返回block的大小,也就是俗稱的數(shù)據(jù)塊位數(shù),如128位,192位,256位
           src = pKCS5Padding(src, bs)// 這里是PKCS5Padding填充方式,繼續(xù)向下看
           if len(src)%bs != 0 { // 如果加密字符串的byte長度不能整除數(shù)據(jù)塊位數(shù),則表示當前加密的塊大小不適用
            return nil, errors.New("Need a multiple of the blocksize")
           }
           out := make([]bytelen(src))
           dst := out
           for len(src) > 0 {
            block.Encrypt(dst, src[:bs]) // 開始用已經(jīng)產(chǎn)生的key來加密
            src = src[bs:]
            dst = dst[bs:]
           }
           return out, nil
          }

          func aesDecrypt(src, key []byte) ([]byte, error) {
           block, err := aes.NewCipher(key)
           if err != nil {
            return nil, err
           }

           out := make([]bytelen(src))
           dst := out
           bs := block.BlockSize()
           if len(src)%bs != 0 {
            return nil, errors.New("crypto/cipher: input not full blocks")
           }
           for len(src) > 0 {
            block.Decrypt(dst, src[:bs])
            src = src[bs:]
            dst = dst[bs:]
           }
           out = pKCS5UnPadding(out)
           return out, nil
          }

          func pKCS5Padding(ciphertext []byte, blockSize int) []byte {
           padding := blockSize - len(ciphertext)%blockSize
           padtext := bytes.Repeat([]byte{byte(padding)}, padding)
           return append(ciphertext, padtext...)
          }

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

          之后附贈普通帶偏移量的AES加解密   AES/CBC/PKCS5Padding 的代碼:

          // aesEncrypt 加密
          func (hs *HuaLiServiceStruct) aesEncrypt() (string, error) {
           key := []byte(hs.DataSecret)
           encodeBytes := []byte(hs.EncodeStr)
           //根據(jù)key密鑰 生成密文
           block, err := aes.NewCipher(key)
           if err != nil {
            return "", err
           }
           blockSize := block.BlockSize()
           encodeBytes = pKCS5Padding(encodeBytes, blockSize)
           //添加偏移量
           blockMode := cipher.NewCBCEncrypter(block, []byte(hs.DataSecretIV)) // 其實這里就更簡單了,只需要創(chuàng)建一個CBC的加密對象,傳入偏移量即可
           crypted := make([]bytelen(encodeBytes))
           blockMode.CryptBlocks(crypted, encodeBytes)
           return base64.StdEncoding.EncodeToString(crypted), nil
          }

          // aesDecrypt 解密
          func (hs *HuaLiServiceStruct) aesDecrypt() ([]byte, error) {
           key := []byte(hs.DataSecret)
           //先解密base64
           decodeBytes, err := base64.StdEncoding.DecodeString(hs.DecodeStr)
           if err != nil {
            return nil, err
           }
           block, err := aes.NewCipher(key)
           if err != nil {
            return nil, err
           }
           blockMode := cipher.NewCBCDecrypter(block, []byte(hs.DataSecretIV)) // 其實這里就更簡單了,只需要創(chuàng)建一個CBC的解密對象,傳入偏移量即可
           origData := make([]bytelen(decodeBytes))

           blockMode.CryptBlocks(origData, decodeBytes)
           origData = pKCS5UnPadding(origData)
           return origData, nil
          }

          func pKCS5Padding(ciphertext []byte, blockSize int) []byte {
           padding := blockSize - len(ciphertext)%blockSize
           padtext := bytes.Repeat([]byte{byte(padding)}, padding)
           return append(ciphertext, padtext...)
          }

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

          再贈送兩種MD5加密寫法,也是利用了crypto庫:

          func TestMd5Create(t *testing.T) {
           CreateMd5Demo1("anyanfei")
           s := CreateMd5Demo2("anyanfei"// ca43e4338149bad344b75378ce5447ea
           fmt.Printf("%x\n", s)
          }

          func CreateMd5Demo1(s string){
           h := md5.New()
           io.WriteString(h, s)
           fmt.Printf("%x\n", h.Sum(nil)) // ca43e4338149bad344b75378ce5447ea
          }

          func CreateMd5Demo2(s string) [16]byte {
           data := []byte(s)
           return md5.Sum(data)
          }

          總結(jié)

          其實大部分加密方法都是前人栽樹后人乘涼,我們只需要知道最簡單的使用即可,至于里面的邏輯,真想了解可以自行看源碼解決,本次只寫了兩個案例,也是工作中用到最多的AES對稱加密

          AES/ECB/PKCS5Padding  ECB不需要帶偏移量的對稱加密寫法

          AES/CBC/PKCS5Padding  帶偏移量的對稱加密寫法

          MD5加密寫法

          參考資料

          • https://godoc.org/golang.org/x/crypto

          還想了解更多嗎?

          更多請查看:https://godoc.org/golang.org/x/crypto

          歡迎加入我們GOLANG中國社區(qū):https://gocn.vip/


          《酷Go推薦》招募:


          各位Gopher同學(xué),最近我們社區(qū)打算推出一個類似GoCN每日新聞的新欄目《酷Go推薦》,主要是每周推薦一個庫或者好的項目,然后寫一點這個庫使用方法或者優(yōu)點之類的,這樣可以真正的幫助到大家能夠?qū)W習(xí)到

          新的庫,并且知道怎么用。


          大概規(guī)則和每日新聞類似,如果報名人多的話每個人一個月輪到一次,歡迎大家報名!戳「閱讀原文」,即可報名


          掃碼也可以加入 GoCN 的大家族喲~





          瀏覽 29
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美视频手机在线 | 欧美色图小说 | 欧美大屌免费看视频 | 操逼www | 日日奸日日射日日舔日日干APP |