<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      golang實現aes-cbc-256加密解密

      我為什么吃撐了要實現go的aes-cbc-256加密解密功能?

      之前的項目是用php實現的,現在準備用go重構,需要用到這個功能,這么常用的功能上網一搜一大把現成例子,于是基于go現有api分分鐘實現一對加密解密函數,你想得沒錯,一跑就失敗,好了不廢話了,go的aes-cbc實現由兩個限制

      1:面臨兩個問題

      1:go秘鑰長度必須是16/24/32

      go源碼如下,我們的秘鑰長度是72,不符合啊

      // NewCipher creates and returns a new cipher.Block.
      // The key argument should be the AES key,
      // either 16, 24, or 32 bytes to select
      // AES-128, AES-192, or AES-256.
      func NewCipher(key []byte) (cipher.Block, error) {
         k := len(key)
         switch k {
         default:
            return nil, KeySizeError(k)
         case 162432:
            break
         }
         return newCipher(key)
      }

      2:go根本不支持256位的aes-cbc加密解密

      好脾氣的我再次貼一下go的相關源碼,赫然寫著const BlockSize = 16,還他媽是個常量,也就是說go一次只能加密16*8=128位,我的php256位怎么遷移

      const BlockSize = 16  //你一眼就看到這么帥的我
       
      type aesCipherAsm struct {
         aesCipher
      }
       
      var useAsm = cipherhw.AESGCMSupport()
       
      func newCipher(key []byte) (cipher.Block, error) {
         if !useAsm {
            return newCipherGeneric(key)
         }
         n := len(key) + 28
         c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}}
         rounds := 10
         switch len(key) {
         case 128 8:
            rounds = 10
         case 192 8:
            rounds = 12
         case 256 8:
            rounds = 14
         }
         expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0])
         if hasGCMAsm() {
            return &aesCipherGCM{c}, nil
         }
       
         return &c, nil
      }
       
      func (c *aesCipherAsm) BlockSize() int { return BlockSize }
       
      func (c *aesCipherAsm) Encrypt(dst, src []byte) {
         if len(src) < BlockSize {
            panic("crypto/aes: input not full block")
         }
         if len(dst) < BlockSize {
            panic("crypto/aes: output not full block")
         }
         encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0])
      }
       
      func (c *aesCipherAsm) Decrypt(dst, src []byte) {
         if len(src) < BlockSize {
            panic("crypto/aes: input not full block")
         }
         if len(dst) < BlockSize {
            panic("crypto/aes: output not full block")
         }
         decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0])
      }

      2:哥開始思考了

      問題一個個擊破,想辦法看能不能繞過去,由于是在NewCipher的時候對必要長度做了限制,我自己new不就行了,一看傻眼了,只有接口是public,實現對象都是private的,要想實例化對象只能通過NewCipher,繞不過去啊,大不了我把你的源碼拷出來,自己在改改,再次沖進go源碼,并復制了出來,給個位看看先

      //加密實現
      TEXT ·encryptBlockAsm(SB),NOSPLIT,$0
          MOVQ nr+0(FP), CX
          666...
      Lenc256:
          MOVUPS 0(AX), X1
          666...
      Lenc196:
          MOVUPS 0(AX), X1
          666...
      Lenc128:
          MOVUPS 0(AX), X1
          666..
          RET
       
      //解密實現
      // func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
      TEXT ·decryptBlockAsm(SB),NOSPLIT,$0
          MOVQ nr+0(FP), CX
          666...
      Ldec256:
          MOVUPS 0(AX), X1
          666...
      Ldec196:
          MOVUPS 0(AX), X1
          666...
      Ldec128:
          MOVUPS 0(AX), X1
          666...
          RET
       
      //通過key和iv初始化加密解密所需的數據結構
      // func expandKeyAsm(nr int, key *byte, enc, dec *uint32) {
      // Note that round keys are stored in uint128 format, not uint32
      TEXT ·expandKeyAsm(SB),NOSPLIT,$0
          MOVQ nr+0(FP), CX
          JE Lexp_enc196   //完全不知道是兩個什么鬼命令
          JB Lexp_enc128   //同上,所以說是兩個鬼命令
      Lexp_enc256:
          MOVUPS 16(AX), X2
          666...

      首長:同志們,跟我一起喊:源碼在手,天下我有,666...

      小弟:大哥,這源碼好像有點不對勁啊

      我去:匯編,強做鎮靜,先找一下相關資料,好久沒研究匯編的我,再次研究起了匯編,找了一些資料:https://juejin.im/entry/5a39d646f265da431a435476,資料不錯就是看不懂

      把部分代碼拷出來,試著改了一下匯編代碼,運行了一下,沒成功

      其實go也有非匯編實現的go代碼,但每次也是加密16字節,不符合要求,我要每次處理32字節的源碼,之后還嘗試過把NewCipher出的對象包一層,讓BlockSize()返回32,自然也是不行

      第一階段以失敗告終

      3:想用go調PHP

      人有多大膽,go調毛PHP啊,上網一搜還真有這么一位大膽的大神,實現了go調PHP:https://github.com/deuill/go-php,小弟我感覺像是找到寶了,搞過來一跑,你還別說真成功了,當我看到go調PHP輸出hello world得那一刻,淚牛滿面,方案就這么定了:go調php實現aes-cbc-256加密解密

      以上成功只是幻想,其實是go調c成功了,并不興奮,調php并沒有,滿電腦沒找到libphp.so,原來在編譯php的時候沒有生成這個lib庫,go調php就是想把php實現編譯到你的程序中讓你調用,于是又開始找資料,找到這個:https://github.com/taowen/go-php,好熟悉的名字,這是我們公司的大神陶師傅啊,鄭重聲明:大神可是帶我做過項目的。于是厚著臉皮向大神請教,大神說不建議用go調PHP,這條路不太靠譜,建議直接rpc調用,當我告訴大神我的需求和go的現狀時,大神建議:把代碼從標準庫拷出來,兩邊對照著調試,你是大神還是我是大神,讓我用go把c的aes-cbc-256從新實現,我怎么可能做得到!當然你是大神,我照做

      4:golang實現aes-cbc-256加密解密正式開始

      第一步看PHP源碼。按照入口一步步看下去,主要是以下幾個函數

      mcrypt_module_open
      mcrypt_generic_init
      mcrypt_generic
      mdecrypt_generic

      實現都在PHP的擴展模塊mcrypt中,這個模塊也是只是對另一標準庫的封裝,地址:https://sourceforge.net/projects/mcrypt/files/Libmcrypt/,于是把代碼下下來看,代碼還挺多,由于我只需要實現aes-cbc-256,其他的直接略過,最終發現我只需要關注兩個文件:modules/algorithms/rijndael-256.c,modules/modes/cbc.c,各位觀眾有沒有發現這個標準庫的命名很給力,幾遍下來發現并不復雜,總共代碼不到600+行,于是將代碼復制過來,開始將c語言翻譯成go語言,很是小心翼翼,一回兒的功夫就翻譯完了(其實用了兩個多小時),翻譯很快那是相對debug階段來說的,一加密發現不對,也不知道錯在哪,代碼都快看吐了,都沒發現問題,于是只好按照大神說的兩邊對比調試,c語言已經兩年多沒搞了,于是安裝了Clion,簡單研究了一下,由于之前是搞windows的,mac上也沒搞過,還好挺好用,開始也是編譯不過,于是簡單復習了一下c語言,最后終于跑通了,由于libmcrypt的實現到處都是指針,很多數據都看不到,只能打印出來看,后來發現,秘鑰長度搞錯了,我是傳的32,其實秘鑰長度是這么計算的

      //獲取加密key長度
      func getKeySize(size int) int {
         for _, val := range keySizes {
            if size <= val {
               return val
            }
         }
         return BLOCK_SIZE
      }

      搞了好久終于解決了加密問題,我那個喜啊(聽不懂就當是方言吧),真的特別有成就感,然后就開始搞解密,發現不對,又是半天找不到原因,在這個過程中又找了一個庫:https://github.com/mfpierre/go-mcrypt,這個庫實現了go的各種加密解密,其實只是對c標準庫mcrypt的封裝,考慮到線上環境不一定有,或是環境不一樣,就沒考慮這個庫,我他媽褲子都脫了(實現了一半加密),你讓我放棄。還有這個庫干嘛要對秘鑰長度進行限制,標準庫本身沒有任何限制好不好。

      5:含著淚也要解決問題

      實現完加密的時候,我就向大神吹牛說,我已經實現,現在解密沒解決,怎么辦?

      又是一陣看代碼,沒發現任何問題,只好使出終極殺手锏:單步對比調試,其實之前已經發現static word32 rtable[256];初始化不對了,為什么加密能成解密就不行,這個變量還真是只在解密用到,同步對比調試終于發現了問題,一個go語言不同于c語言的問題,且看下面這個函數:

      //c語言實現
      static byte bmul(byte x, byte y)
      {        
         if (x && y)
            return ptab[(ltab[x] + ltab[y]) % 255];
         else
            return 0;
      }
      bmul(200,200) == 145
       
      //go語言實現
      func bmul(x, y byte) byte {
         if x > 0 && y > 0 {
            return ptab[(ltab[x]+ltab[y])%255]
         }
         return 0
      }
      bmul(200,200) == 144

      朋友們啊,看到區別沒有,前面說了,我是把c語言直接翻譯成go語言的,但是c語言和go語言不一樣啊,兩個完全一樣的函數,竟然不一樣,c語言400%255=145好理解,go怎么就變成144了呢,200+200=144,我們來看看400的二進制表示110010000,去掉最前面的1,就是010010000,剛好144,也就是說c語言byte超過了255根本沒關系,而go超過了255就給截斷了,說好的互聯網時代的c語言呢!

      6:最后厚顏無恥的掛到了github.com

      https://github.com/chentaihan/aesCbc

       

      posted @ 2018-10-25 20:24  古文觀芷  閱讀(14134)  評論(6)    收藏  舉報
      主站蜘蛛池模板: 综合色综合色综合色综合| 少妇人妻偷人一区二区| 色欲av亚洲一区无码少妇| gogo无码大胆啪啪艺术| 妓院一钑片免看黄大片| 亚洲www永久成人网站| 亚洲人成网线在线播放VA| 人人澡超碰碰97碰碰碰| 国产精品亚洲mnbav网站| 一本高清码二区三区不卡| 亚洲2区3区4区产品乱码2021| 婷婷久久香蕉五月综合加勒比 | 日韩卡1卡2卡三卡免费网站| 动漫av网站免费观看| 色先锋av影音先锋在线| 欧美丰满熟妇bbbbbb| 成人性生交大片免费看r老牛网站 中文字幕一区二区三区四区五区 久久久久久毛片免费播放 | 亚洲熟女精品一区二区| 亚洲午夜香蕉久久精品| 激,情四虎欧美视频图片| 免费AV片在线观看网址| 日本一区二区三区在线 |观看 | 国产无遮挡又黄又爽又色| 亚洲欧美国产精品久久久久久久| 欧美丰满熟妇xxxx性| 国产狂喷潮在线观看| 四虎永久精品在线视频| 精品国产午夜福利在线观看| 国产精品午夜福利91| 国产美女久久久亚洲综合| 国产一国产精品免费播放| 国产麻豆剧传媒精品国产av| 亚洲 另类 小说 国产精品无码| 一区二区和激情视频| 亚洲国产欧美一区二区好看电影| 一个色综合色综合色综合| 18岁日韩内射颜射午夜久久成人| 国产成人精品永久免费视频| 另类专区一区二区三区| 亚洲婷婷综合色高清在线 | 在线涩涩免费观看国产精品|