【问题标题】:Decrypt AES-CBC-256 Mcrypt_RIJNDAEL encrypted in PHP decrypt on GOLang在 GOLang 上解密用 PHP 加密的 AES-CBC-256 Mcrypt_RIJNDAEL
【发布时间】:2019-11-17 11:45:49
【问题描述】:

我尝试在 go 中重写一些用 php5.6 (CodeIgniter) 制作的旧代码,但我在 go 中用解密来敲我的脑袋。我设法从 php 解码 MCRYPT_RIJNDAEL_128,其中 iv 大小为 16 个字符,但我不能在 256 上执行 - iv 是 32。我不想使用 go_mcrypt 因为这对 libcrypt 标头很严格,所以我尝试了使用带有 CBC 模式的 go classic encrypt libs AES 密码,但在 256 上它抱怨 IV 长度...... php IV 有 32 个字符而不是预期的 16 个......

php部分运行良好...

private $CIPHER_KEY = "12345678901234567890123456789012";

    private function Encrypt($toEncrypt=null){
        $iv_size = $this->ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
        $iv = $this->ivKey = mcrypt_create_iv($iv_size, MCRYPT_RAND);
        $this->B64IV = base64_encode($iv);
        return base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $this->CIPHER_KEY, $toEncrypt, MCRYPT_MODE_CBC, $iv));
    }

这是 PHP 的结果:

KEY: 12345678901234567890123456789012
IV: Egu4tSySXluBLi5dcMzHbZHVSOS7jdNwUKUFlZ8dL1w=
ENC: Egu4tSySXluBLi5dcMzHbZHVSOS7jdNwUKUFlZ8dL1yATFjg26/Nav7cWtlJJL3djhUCND6KV8r/JL7owboKFA==
IV Size: 32

IV 包含在加密文本中...(并且有 32 个字符)

mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); return 32
func main(){
   key := []byte("12345678901234567890123456789012")

   iv,_ := base64.StdEncoding.DecodeString("Egu4tSySXluBLi5dcMzHbZHVSOS7jdNwUKUFlZ8dL1w=")
   encText,_  := base64.StdEncoding.DecodeString("Egu4tSySXluBLi5dcMzHbZHVSOS7jdNwUKUFlZ8dL1yATFjg26/Nav7cWtlJJL3djhUCND6KV8r/JL7owboKFA==")
//   iv := encText[:32] // also tried to get the iv from encoded string


   fmt.Printf("Key Len: %d\nIV  Len: %d\nENC Len: %d\n",len(key),len(iv),len(encText))

    block, err := aes.NewCipher(key)
    if err != nil {
        panic(err)
    }

    if len(encText) < aes.BlockSize {
        panic("cipherText too short")
    }

    cipherText := encText[32:]
    if len(cipherText)%aes.BlockSize != 0 {
        panic("cipherText is not a multiple of the block size")
    }

    mode := cipher.NewCBCDecrypter(block, iv)
    mode.CryptBlocks(cipherText, cipherText)

    cipherText, _ = pkcs7.Unpad(cipherText, aes.BlockSize)

   fmt.Printf("Dec: %s\n",cipherText)

}

关键镜头:32 四连:32 ENC 长度:64 恐慌:cipher.NewCB​​CDecrypter:IV 长度必须等于块大小

goroutine 1 [运行中]: crypto/cipher.NewCB​​CDecrypter(0x10e7c20, 0xc00009a030, 0xc00008a000, 0x20, 0x42, 0x0, 0x0)

IV 大小为 32,但块大小为 16。

【问题讨论】:

  • OK - 我重新阅读了文档,AES-256 仅使用 128 字节 IV(16 个字符)。AES 是 Rijndael 的变体,具有 128 位的固定块大小,密钥大小为 128、192 或 256 位。 Rijndael 文档指定块和密钥大小为 32 位的倍数,最小为 128 位,最大为 256 位,因此混淆 AES 不是 RIJNDAEL - 只是一个变体。我想唯一的解决方案是解密 php 中的敏感数据并使用 128 字节 IV 对其进行加密。任何人都知道另一个库 - 与 RIJNDAEL 250 兼容,适用于 256 字节(32 个字符)的 IV?

标签: php go aes rijndael cbc-mode


【解决方案1】:

我只是在我的 MacOS 上测试它,上面的代码在 Mohave 10.14.5 上运行。

我使用 MacPorts 安装 libmcrypt

sudo 端口安装 libmcrypt

mkdir mcrypt curl -o mcrypt/mcrypt.go https://raw.githubusercontent.com/tblyler/go-mcrypt/master/mcrypt.go

或者从你自己的 src/github.com/tblyler/go-mcrypt 复制到项目 mcrypt 文件夹中

现在编辑 mcrypt.go 并添加 C 标志:

package mcrypt

/*
#cgo LDFLAGS: -L/opt/local/lib -lmcrypt
#cgo CFLAGS: -I/opt/local/include
#include <stdlib.h>
...

修改上面例子中的 import 以在本地导入 mcrypt 版本,然后运行它...

package main

import (
  "fmt"
//"github.com/tblyler/go-mcrypt"
  "./mcrypt"
  "encoding/base64"
)

在运行代码时,它会添加有关链接的警告

ld: warning: building for macOS, but linking in object file (/var/folders/xz/7ng416ds5611ypt12c96g1_40000gn/T/go-link-754294955/go.o) built for
Key Len: 32
IV  Len: 32
Abra Cadabra

【讨论】:

    【解决方案2】:

    在将代码从 php 5.6 传输到 php 7.3 时,我一直在处理类似的问题。我发现的最简单和最可靠的方法就是用 php 5.6 解密所有值,然后用运行良好的新格式重新加密。搬家是一次性的事情,但可以省去很多麻烦。

    【讨论】:

      【解决方案3】:

      这适用于 Linux - 适合任何想用 IV 32 个字符解码的人

      安装 libmcrypt-dev

      去获取“github.com/tblyler/go-mcrypt”

      import (
        "fmt"
        "github.com/tblyler/go-mcrypt"
        "encoding/base64"
      )
      
      const (
         KEY = "12345678901234567890123456789012"
         ENC = "Egu4tSySXluBLi5dcMzHbZHVSOS7jdNwUKUFlZ8dL1yATFjg26/Nav7cWtlJJL3djhUCND6KV8r/JL7owboKFA=="
      )
      
      func main(){
          encText, _ := base64.StdEncoding.DecodeString(ENC)
      
          iv := encText[:32]
          toDecrypt := encText[32:]
      
          fmt.Printf("Key Len: %d\n",len(KEY))
          fmt.Printf("IV  Len: %d\n",len(iv))
      
          decText, err := mcrypt.Decrypt([]byte(KEY),iv,[]byte(toDecrypt))
          if err != nil { panic(err) }
      
          fmt.Printf("%s\n",decText)
      }
      

      【讨论】:

        猜你喜欢
        • 2021-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-28
        • 2013-08-11
        • 2014-02-06
        • 1970-01-01
        • 2020-01-14
        相关资源
        最近更新 更多