Blowfish 结果在 OpenSSL 和 Golang 之间是不同的

Blowfish results are different between OpenSSL and Golang

我想用 Go 读取 VIM 编码的文件。 This code 适用于小文件,所以我决定将其转换为 Go。密钥生成工作正常,但 Blowfish 编码没有。我已经将问题追溯到 BF_encrypt 和 cipher.Encrypt(...).

的不同结果

输入

key: c904a7a85bbd975324c5083ed96ff022f25e062da1d575b2462c2c98d8d64d9d
data: 538b7759834d3418

输出

Golang: b5cf33144acbc794
C:      90baa70ec3e44867

Golang 代码:

package main

import (
    "fmt"
    "golang.org/x/crypto/blowfish"
)

func main() {
    key := []byte{0xc9, 0x04, 0xa7, 0xa8, 0x5b, 0xbd, 0x97, 0x53, 0x24, 0xc5, 0x08, 0x3e, 0xd9, 0x6f, 0xf0, 0x22, 0xf2, 0x5e, 0x06, 0x2d, 0xa1, 0xd5, 0x75, 0xb2, 0x46, 0x2c, 0x2c, 0x98, 0xd8, 0xd6, 0x4d, 0x9d}
    data := []byte{0x53, 0x8b, 0x77, 0x59, 0x83, 0x4d, 0x34, 0x18}

    cipher, err := blowfish.NewCipher(key)
    if err != nil {
        panic(err)
    }

    fmt.Printf("key: %x\n", key)
    fmt.Printf("data: %x\n", data)

    encrypted := make([]byte, 8)
    cipher.Encrypt(encrypted, data)
    fmt.Printf("encrypted: %x\n", encrypted)
}

C代码:

#include <stdio.h>
#include <string.h>
#include <openssl/blowfish.h>
#include <openssl/sha.h>

/*
clang test1.c -o test1 \
-I/usr/local/Cellar/openssl/1.0.2k/include \
-L/usr/local/Cellar/openssl/1.0.2k/lib \
-lcrypto
./test1
*/

int main(int argc, char *argv[]) {
    unsigned char key[32] = {0xc9, 0x04, 0xa7, 0xa8, 0x5b, 0xbd, 0x97, 0x53, 0x24, 0xc5, 0x08, 0x3e, 0xd9, 0x6f, 0xf0, 0x22, 0xf2, 0x5e, 0x06, 0x2d, 0xa1, 0xd5, 0x75, 0xb2, 0x46, 0x2c, 0x2c, 0x98, 0xd8, 0xd6, 0x4d, 0x9d};
    unsigned char data[8] = {0x53, 0x8b, 0x77, 0x59, 0x83, 0x4d, 0x34, 0x18};

    BF_KEY bf_key;
    BF_set_key(&bf_key, 32, key);

    printf("key: ");
    for (int j = 0; j < 32; j++) printf("%02x", key[j]);
    printf("\n");
    printf("data: ");
    for (int j = 0; j < 8; j++) printf("%02x", data[j]);
    printf("\n");

    BF_encrypt((unsigned int*)data, &bf_key);

    printf("encrypted: ");
    for (int j = 0; j < 8; j++) printf("%02x", data[j]);
    printf("\n");

    return 0;
}

你能看出问题出在哪里吗?

问题出在变量 dataencrypted 的字节序上。在 C 代码中,data(8 字节)从字节数组转换为 unsigned int(32 位小端),然后就地加密。它影响输入和加密结果的字节顺序。要在 Golang 中获得相同的结果,您必须执行字节序转换,例如

package main

import (
    "bytes"
    "fmt"

    "encoding/binary"

    "golang.org/x/crypto/blowfish"
)

func convertEndian(in []byte) ([]byte, error) {
    //Read byte array as uint32 (little-endian)
    var v1, v2 uint32
    buf := bytes.NewReader(in)
    if err := binary.Read(buf, binary.LittleEndian, &v1); err != nil {
        return nil, err
    }
    if err := binary.Read(buf, binary.LittleEndian, &v2); err != nil {
        return nil, err
    }

    //convert uint32 to byte array
    out := make([]byte, 8)
    binary.BigEndian.PutUint32(out, v1)
    binary.BigEndian.PutUint32(out[4:], v2)

    return out, nil
}

func main() {
    key := []byte{0xc9, 0x04, 0xa7, 0xa8, 0x5b, 0xbd, 0x97, 0x53, 0x24, 0xc5, 0x08, 0x3e, 0xd9, 0x6f, 0xf0, 0x22, 0xf2, 0x5e, 0x06, 0x2d, 0xa1, 0xd5, 0x75, 0xb2, 0x46, 0x2c, 0x2c, 0x98, 0xd8, 0xd6, 0x4d, 0x9d}
    data := []byte{0x53, 0x8b, 0x77, 0x59, 0x83, 0x4d, 0x34, 0x18}

    //Add: This is equal to: (unsigned int *)data in C
    cdata, _ := convertEndian(data)

    cipher, err := blowfish.NewCipher(key)
    if err != nil {
        panic(err)
    }

    fmt.Printf("key: %x\n", key)
    fmt.Printf("data: %x\n", cdata)

    encrypted := make([]byte, 8)
    cipher.Encrypt(encrypted, cdata)
    fmt.Printf("encrypted-1: %x\n", encrypted)

    //Add: This is equal to {uint32, uint32} --> byte array
    ce, _ := convertEndian(encrypted)
    fmt.Printf("encrypted-2: %02x\n", ce)
}