1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 21600字,需瀏覽 44分鐘

         ·

        2021-08-05 06:02

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

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

        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);
                // 生成一個(gè)密鑰
                SecretKey secretKey = kg.generateKey();
                return secretKey.getEncoded();
            }

            /**
             * 轉(zhuǎn)換密鑰
             *
             * @param key
             *            二進(jìn)制密鑰
             * @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 {
                // 實(shí)例化
                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 {
                // 實(shí)例化
                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進(jìn)制轉(zhuǎn)換為二進(jì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;
            }

            /**
             * 將二進(jìn)制轉(zhuǎn)換成16進(jìn)制
             *
             * @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號(hào)門停車場(出場通道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密鑰進(jìn)行base64編碼,這一行與加密 AES/ECB/PKCS5Padding 沒有關(guān)系
         aseByte, err := aesEncrypt([]byte(lfs.NeedEncryptString), decodeKey)//這一行開始就是 AES/ECB/PKCS5Padding 的標(biāo)準(zhǔn)加密了
         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進(jìn)制字符轉(zhuǎn)為2進(jìn)制byte數(shù)組
         decodeKey, err := base64.StdEncoding.DecodeString(lfs.Key) //這行還是將Key密鑰進(jìn)行base64編碼
         lastByte, err = aesDecrypt(hexStrByte, decodeKey) // 這里開始就是 AES/ECB/PKCS5Padding 的標(biāo)準(zhǔn)解密了
         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ù),則表示當(dāng)前加密的塊大小不適用
          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)]
        }

        之后附贈(zèng)普通帶偏移量的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)) // 其實(shí)這里就更簡單了,只需要?jiǎng)?chuàng)建一個(gè)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)) // 其實(shí)這里就更簡單了,只需要?jiǎng)?chuàng)建一個(gè)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)]
        }

        再贈(zèng)送兩種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é)

        其實(shí)大部分加密方法都是前人栽樹后人乘涼,我們只需要知道最簡單的使用即可,至于里面的邏輯,真想了解可以自行看源碼解決,本次只寫了兩個(gè)案例,也是工作中用到最多的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ū)打算推出一個(gè)類似GoCN每日新聞的新欄目《酷Go推薦》,主要是每周推薦一個(gè)庫或者好的項(xiàng)目,然后寫一點(diǎn)這個(gè)庫使用方法或者優(yōu)點(diǎn)之類的,這樣可以真正的幫助到大家能夠?qū)W習(xí)到

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


        大概規(guī)則和每日新聞?lì)愃疲绻麍?bào)名人多的話每個(gè)人一個(gè)月輪到一次,歡迎大家報(bào)名!戳「閱讀原文」,即可報(bào)名


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





        瀏覽 29
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

          <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            99视频在线精品免费观看2 | 男人操女人视频免费看 | 十八禁网站免费观看 | 涩涩涩蜜桃888wwww | 超级乱淫aⅴ片免费 | 人人艹人人 | 黄色91免费版 | 狠狠撸天天撸 | avwww. | 东京热在线免费观看 |