Хорошо, мне удалось получить выход go, соответствующий вашим другим выводам, но я не на 100% ясен во всех деталях - в частности, почему версии PHP и Node ведут себя так, как они (ваш вывод изкак я объясню, версия Go кажется мне «правильным» результатом.
Моим первым наблюдением было то, что ваш вывод из Node и PHP был длиннее, чем версия Go, примерно на одну длину блокаи только хвостовой конец отличается.Это сказало мне, что каким-то образом эти версии дополняются на больше , чем версия Go.
Итак, я попытался дополнить версию Go в соответствии со схемой заполнения по умолчанию, используемой PHP и Node, PKCS # 7 .По сути, если вам нужно заполнить 5 байтами, то каждый из байтов заполнения должен быть равен 0x05, 6 байтов дополнены 0x06 и т. Д. Go по умолчанию aes.BlockSize
равно 16, поэтому я попытался заполнить вашу входную строку с помощью16 0x10 байт.Это привело к правильному ответу!
Честно говоря, не заполнение ввода вообще, если оно уже выровнено по блокам, понятное поведение, но, по-видимому, Node и PHP следуют RFC 5652 и всегда добавляют заполнение (см. Редактирование), дажеесли им нужно добавить еще один целый блок только для заполнения.
Вот код Go, чтобы ваши выходные данные совпали:
package main
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"fmt"
"io"
)
// Based on Wikipedia: https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7
func PadToBlockSize(input string) string {
paddingNeeded := aes.BlockSize - (len(input) % aes.BlockSize)
if paddingNeeded >= 256 {
panic("I'm too lazy to handle this case for the sake of an example :)")
}
if paddingNeeded == 0 {
paddingNeeded = aes.BlockSize
}
// Inefficient, once again, this is an example only!
for i := 0; i < paddingNeeded; i++ {
input += string(byte(paddingNeeded))
}
return input
}
// (Identical to your code, I just deleted comments to save space)
func EncryptString(plainstring string, keystring string, encFormat int, ivOverride bool) string {
key := []byte(keystring)
plaintext := []byte(plainstring)
if len(plaintext)%aes.BlockSize != 0 {
panic("plaintext is not a multiple of the block size")
}
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
ciphertext := make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(bytes.NewReader([]byte("97iEhhtgVjoVwdUw")), iv); err != nil {
panic(err)
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
return base64.StdEncoding.EncodeToString(ciphertext)
}
func main() {
plaintext := "hello big worldshello big worlds"
key := "jJr44P3WSM5F8AC573racFpzU5zj7Rg5"
phpText := "OTdpRWhodGdWam9Wd2RVd0OgJ+Z7pSCVioYq41721jarxqLKXN3PcnnY6/AOrHeEfsTxXfCgm2uUi+vmCAdpvw=="
fmt.Println("Go : " + EncryptString(PadToBlockSize(plaintext), key, 0, false))
fmt.Println("PHP: " + phpText)
}
Редактировать:
На самом деле это выглядит такNode и PHP просто следуют RFC 5652 правильно, что требует дополнения всего ввода.Тот факт, что заполнение всегда будет присутствовать, даже если вход был выровнен по блокам, устраняет неоднозначность дешифрования.Go просто оставляет шаг заполнения для пользователя.