【问题标题】:How do I match phpseclib1 Rijndael.php CBC AES encryption in golang?如何在 golang 中匹配 phpseclib1 Rijndael.php CBC AES 加密?
【发布时间】:2016-09-01 13:33:40
【问题描述】:

我正在像这样加密:

  plaintextstr := "0000000000000thankustackoverflow"
  plaintext := []byte(plaintextstr)

  key := []byte("abcdefghijklmnop")
  block, _ := aes.NewCipher(key)

  ciphertext := make([]byte, aes.BlockSize+len(plaintext))
  iv := ciphertext[:aes.BlockSize]

  mode := cipher.NewCBCEncrypter(block, iv)
  mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
  fmt.Printf("%x\n", ciphertext)

输出是:

00000000000000000000000000000000d77aa6646bb541808ed23c88d4b06d30f42b01d6e806a02b29086bc82892334f

但是用 PHP 编写的这段代码的另一个版本的输出是:

d77aa6646bb541808ed23c88d4b06d30f42b01d6e806a02b29086bc82892334fbf21ea861abbc3d72e44731978bb76c2

请注意,00000000000000000000000000000000 是末尾缺失数据的确切长度。它是 32,即原始纯文本字符串的大小。知道如何在 golang 中左移所有内容并获取丢失的数据吗?

PHP:

<?php

include('Crypt/AES.php');

$aes = new Crypt_AES();

$aes->setKey('abcdefghijklmnop');
echo bin2hex($aes->encrypt("0000000000000thankustackoverflow"));

https://github.com/andrewarrow/phpseclib1/blob/master/Crypt/AES.php https://github.com/andrewarrow/phpseclib1/blob/master/Crypt/Rijndael.php

调试php输出:

00000000000000000000000000000000 <--- IV
30303030303030303030303030746861 block 0
d77aa6646bb541808ed23c88d4b06d30 crypted 0
6e6b75737461636b6f766572666c6f77 block 16
f42b01d6e806a02b29086bc82892334f crypted 16
10101010101010101010101010101010 block 32
bf21ea861abbc3d72e44731978bb76c2 crypted 32

【问题讨论】:

标签: php go cryptography aes


【解决方案1】:

这不是一个移位问题,这是一个输出缓冲区大小问题,因为 iv 是加密数据的前缀。

IV 是一个空块 (0x00),因为它从未设置为值。它被添加到加密数据之前,这很常见。需要添加一个填充块,因为输入数据是块大小的精确倍数。

这个输出缓冲区需要是 iv 的大小 + 数据的大小 + 填充块的大小。 (16 + 32 + 16 = 64)

向输出缓冲区添加另一个块大小:

ciphertext := make([]byte, aes.BlockSize + len(plaintext) + aes.BlockSize)

【讨论】:

  • 我最后得到了更多的零,但仍然没有得到 php 丢失的数据。
  • 我用示例 php 代码更新了问题以显示问题
【解决方案2】:

PHP 版本正在编码一个额外的 16 字节的“空”字符串,该字符串用 16 秒填充!

  p1 := "0000000000000tha"
  p2 := "nkustackoverflow"

  p1b := []byte(p1)
  p2b := []byte(p2)
  p3b, _ := hex.DecodeString("10101010101010101010101010101010")
  fmt.Println(p3b)

  key := []byte("abcdefghijklmnop")
  block, _ := aes.NewCipher(key)
  ciphertext := make([]byte, aes.BlockSize+16)
  iv := ciphertext[:aes.BlockSize]
  mode := cipher.NewCBCEncrypter(block, iv)

  i := 0
  for {
    if i == 0 {
      mode.CryptBlocks(ciphertext[aes.BlockSize:], p1b)
    } else if i == 1 {
      mode.CryptBlocks(ciphertext[aes.BlockSize:], p2b)
    } else if i == 2 {
      mode.CryptBlocks(ciphertext[aes.BlockSize:], p3b)
    }
    fmt.Printf("%x\n", ciphertext[16:])
    i += 1
    if i > 2 {
      break
    }
  }

这段代码在 golang 中打印 php 中的 identical 内容。

【讨论】:

  • 即[PKCS#7 padding](PKCS#7 padding)。 AES 是一种分组密码,要求输入是分组大小(16 字节)的精确倍数。当输入不是块大小的精确倍数时需要填充,并且当使用填充时,必须填充每个加密,这意味着即使输入是块的精确倍数也要添加填充。填充字节是填充字节数的整数值。在您的情况下,正在添加一个填充块,16 个字节,tyhat 就是为什么有 16 个字节的填充,值为 16。
猜你喜欢
  • 2018-11-18
  • 2021-06-07
  • 1970-01-01
  • 2013-08-11
  • 2019-11-17
  • 2018-09-20
  • 1970-01-01
  • 2017-09-28
  • 2015-09-16
相关资源
最近更新 更多