从 wincrypt API 到 Go 的 RC2 解密

问题描述 投票:0回答:1

我想将 1990 年的旧 C 代码重写为 Go。但这里的痛点是密码算法的迁移。我有以下 Cpp 代码,可以成功地将密码解密为纯文本。

#include <windows.h>
#include <wincrypt.h>
#include <string>
#include <iostream>

using namespace std;

int main() {
    auto name = L"aaaa";

    HCRYPTPROV hProv;

    if (!CryptAcquireContext(&hProv, name, MS_DEF_PROV, PROV_RSA_FULL, 0) &&
        !CryptAcquireContextW(&hProv, name, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET) &&
        !CryptAcquireContextW(&hProv, name, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET) &&
        !CryptAcquireContextW(&hProv, name, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET | CRYPT_NEWKEYSET)) {
        cout << "fail" << endl;
        exit(1);
    }

    HCRYPTHASH hHash;

    if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) {
        cout << "fail" << endl;
        exit(1);
    }

    const BYTE* pwd = reinterpret_cast<const BYTE*>("-+ REDACTED +-");

    if (!CryptHashData(hHash, pwd, 14, 0)) {
        cout << "md5 failure" << endl;
        exit(1);
    }

    HCRYPTKEY hKey;

    if (!CryptDeriveKey(hProv, CALG_RC2, hHash, 0, &hKey)) {
        cout << "failure" << endl;
        exit(1);
    }

    unsigned char cipher[] = {52, 54, 253, 199, 131, 110, 202, 15, 185, 107, 71, 244, 150, 171, 220, 6, 183, 86, 234, 252, 242, 84, 156, 200};

    DWORD len = 24;

    if (!CryptDecrypt(hKey, 0, TRUE, 0, cipher, &len)) {
        printf("%x\n", GetLastError());
        exit(1);
    }

    for (int i = 0; i < len; i++) {
        printf("%d, ", cipher[i]);
    }
}

我有以下 Go 代码:

package main

import (
    "crypto/md5"
    "fmt"

    "github.com/dgryski/go-rc2"
)

func main() {
    pwd := "-+ REDACTED +-"
    hash := md5.Sum([]byte(pwd))

    alg, err := rc2.New(hash[:], 128)
    if err != nil {
        panic(err)
    }

    cipher := []byte{52, 54, 253, 199, 131, 110, 202, 15, 185, 107, 71, 244, 150, 171, 220, 6, 183, 86, 234, 252, 242, 84, 156, 200}

    result := []byte{}
    dst := make([]byte, 8)

    for i := 8; i <= len(cipher); i += 8 {
        alg.Decrypt(dst, cipher[i-8:i])
        result = append(result, dst...)
    }

    fmt.Println(result)
}

在线运行:https://go.dev/play/p/veRMRShmtnw

它们的输出是不同的。而CPP版本可以正确解密。

我的假设是,“CryptDeriveKey”使用附加值强化初始哈希密码,结果加密密钥被更改。

go winapi cryptography wincrypt rc2-cipher
1个回答
0
投票

以下代码不正确,因为最后一个块未解密,并且

result
的长度为
16
字节。

    for i := 8; i < len(cipher); i += 8 {
        alg.Decrypt(dst, cipher[i-8:i])
        result = append(result, dst...)
    }

将其替换为以下代码并重试:

    for i := 0; i < len(cipher); i += 8 {
        alg.Decrypt(dst, cipher[i:i+8])
        result = append(result, dst...)
    }
© www.soinside.com 2019 - 2024. All rights reserved.