C# 如何使用BouncyCastle Blowfish实现解密数据?

C# 如何使用BouncyCastle Blowfish实现解密数据?,c#,encryption,bouncycastle,blowfish,C#,Encryption,Bouncycastle,Blowfish,我正在使用一个外部API,它返回一个Blowfish加密的JSON数组。首先,我尝试使用基于本文的BountyCastle包实现河豚加密/解密方法 抛出 Org.BouncyCastle.Crypto.InvalidCipherTextException:“填充块已损坏” 例外。有人知道如何解密这个Api响应吗?PHP代码首先将这三部分分开。第二部分是IV,它是十六进制解码的,因此大小为8字节。第三部分是数据,由于第一部分中的-1,首先对数据进行十六进制解码,然后通过在CBC模式下使用Blowf

我正在使用一个外部API,它返回一个Blowfish加密的JSON数组。首先,我尝试使用基于本文的BountyCastle包实现河豚加密/解密方法

抛出

Org.BouncyCastle.Crypto.InvalidCipherTextException:“填充块已损坏”


例外。有人知道如何解密这个Api响应吗?

PHP代码首先将这三部分分开。第二部分是IV,它是十六进制解码的,因此大小为8字节。第三部分是数据,由于第一部分中的-1,首先对数据进行十六进制解码,然后通过在CBC模式下使用Blowfish和PKCS7填充,使用密钥和IV进行解密

为了检查C#实现,测试数据非常有用:

  • 作为20字节密钥,将应用以下Base64解码密钥:
MDEyMzQ1Njc4OTAxMjM0NTY3ODk=
  • 使用密文时:
$-1$cb8ba9e30b19ff2a$1CB8430F6B9C109E434874408DBD26BE36B0C9600383D63AFD70669EFCEC38BEA1290DFBE6B71519B1F48B514957845
如果在PHP代码中使用此数据,
decryptData()
返回:

敏捷的棕色狐狸跳过了懒狗 必须对C代码进行以下更改:

  • 审议第四次会议
  • CBC模式和PKCS7填充的使用
  • 密钥的Base64解码
这将导致以下实施:

private static void Main(字符串[]args)
{
//string key=“kgknvrujrgav4xjd4bkcqvn5de0dcw8zpu1urnpw8”//此解密密钥使用不正确
//字符串响应="1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,1美元,10 10年10 10 10 10月10号10号10号10号10号10号10号10号10号10号10号10号10层10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10层10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号10号1043f3c04d2a496660f84ac98f011d3930c61ce9d5565131d2cba65db7c9bef824dd9a6594”;
string key=“MDEyMzQ1Njc4OTAxMjM0NTY3ODk=”;
字符串apiResponse=“$-1$cb8ba9e30b19ff2a$1CB8430F6B9C109E434874408DBD26BE36B0C9600383D63AFD70669EFCEC38BEA1290DFBE6B71519B1F48B514957845”;
Match matches=Regex.Match(apiResponse,@“^\$([^$]{2,4})\$([a-f0-9]{16,64})\$([a-f0-9]*)”;
组算法=匹配项。组[1];
组iv=匹配。组[2];//第二部分是iv
组内容=匹配项。组[3];
string decryptedContent=Decrypt(content.ToString(),key,iv.ToString());//另外传递iv
Console.WriteLine(解密内容);
}
私有静态字符串解密(string encryptedContent、string decryptionKey、string iv)
{
字节[]内容字节=十六进制解码(encryptedContent);
byte[]keyBytes=Convert.FromBase64String(decryptionKey);//Base64解码密钥
KeyParameter KeyParameter=新的KeyParameter(keyBytes);
参数IV键PARAMIVIVI=新参数IV(键参数,十六进制译码(IV));
BlowfishEngine BlowfishEngine=新的BlowfishEngine();
PADD BuffeReDePixPad BuffeleDeBiCHIPHER =新的PADD BuffeleDebug(新CBCBulcPiver(BooFigEngEngress),新PKCS7PADIDEN());
paddedBufferedBlockCipher.Init(false,keyParamWithIv);
int outputLength=paddedBufferedBlockCipher.GetOutputSize(contentBytes.Length);
字节[]输出字节=新字节[outputLength];
int processedBytes=paddedBufferedBlockCipher.ProcessBytes(contentBytes,0,contentBytes.Length,outputBytes,0);
processedBytes+=paddedBufferedBlockCipher.DoFinal(outputBytes,processedBytes);
return Encoding.UTF8.GetString(outputBytes,0,processedBytes);//敏捷的棕色狐狸跳过了懒狗
}

如果执行此代码,则测试明文结果。因此,使用此代码,您的密文应该可以使用密钥进行解密。

可能仍然与编码有关。可能内容不在UTF8中。我还尝试了
encoding.ASCII.GetBytes(content)
但是得到同样的错误…数据是十六进制编码的,所以十六进制解码它。$表示一种特殊的格式,让我想起Unix密码的加密格式。在这种情况下,它不是加密,而是hashing@PresidentJamesK.Polk对不起,我不明白。我已经在尝试用
Hex.decode(内容)解码它了
好的,对。
Hex.Decode()
要求使用有效的十六进制字符,“$”和“-”无效。但要点是,您需要查阅“外部API”的文档以了解此特定数据格式。“-1”算法的确切含义是什么?
internal class Program
{
    private static void Main(string[] args)
    {
        string key = "KgKnVRujrgAv4XjD4bKCqdQVN5De0DCw8zpu1URnPw8="; // random
        string content = "[{'id':1},{'id':2}]";

        string encryptedContent = Encrypt(content, key);
        string decryptedContent = Decrypt(encryptedContent, key);

        /*
         
            decryptedContent returns 
        
                [{'id':1},{'id':2}]\0\0\0\0\0

            so I think this should be fine
         
         */
    }

    private static string Encrypt(string content, string encryptionKey)
    {
        byte[] contentBytes = Encoding.UTF8.GetBytes(content);

        return SharedCode(
            contentBytes,
            encryptionKey,
            true,
            encryptedContentBytes => BitConverter
                .ToString(encryptedContentBytes)
                .Replace("-", ""));
    }

    private static string Decrypt(string encryptedContent, string decryptionKey)
    {
        byte[] contentBytes = Hex.Decode(encryptedContent);

        return SharedCode(contentBytes, decryptionKey, false, decryptedContentBytes =>
        {
            string decryptedContentString = BitConverter
                .ToString(decryptedContentBytes)
                .Replace("-", "");

            byte[] hexBytes = new byte[decryptedContentString.Length / 2];
            
            for (int i = 0; i < hexBytes.Length; i++)
            {
                string currentHexString = decryptedContentString.Substring(i * 2, 2);
                hexBytes[i] = Convert.ToByte(currentHexString, 16);
            }

            return Encoding.UTF8.GetString(hexBytes);
        });
    }

    private static string SharedCode(byte[] contentBytes, string key, bool forceEncryption, Func<byte[], string> processor)
    {
        BlowfishEngine blowfishEngine = new BlowfishEngine();
        PaddedBufferedBlockCipher paddedBufferedBlockCipher = new PaddedBufferedBlockCipher(blowfishEngine);
        byte[] keyBytes = Encoding.UTF8.GetBytes(key);
        KeyParameter keyParameter = new KeyParameter(keyBytes);
        paddedBufferedBlockCipher.Init(forceEncryption, keyParameter);
        int outputLength = paddedBufferedBlockCipher.GetOutputSize(contentBytes.Length);
        byte[] outputBytes = new byte[outputLength];
        int processedBytes = paddedBufferedBlockCipher.ProcessBytes(contentBytes, 0, contentBytes.Length, outputBytes, 0);
        paddedBufferedBlockCipher.DoFinal(outputBytes, processedBytes);

        return processor(outputBytes);
    }
}
<?php
function decryptData(string $data, string $key): string{
    $matches = [];
    if(!preg_match('|^\$([^$]{2,4})\$([a-f0-9]{16,64})\$|i', $data, $matches)){
        return '';
    }
    $data = (string) substr($data, strlen($matches[0]));
    switch($matches[1]){
        default:
            return '';
        case '-1':
            $data = (string) hex2bin($data);
        case '-1a':
            $algo = 'blowfish';
            return (string) openssl_decrypt($data, $algo, (string) base64_decode($key), OPENSSL_RAW_DATA, (string) hex2bin($matches[2]));
    }
}
internal class Program
{
    private static void Main(string[] args)
    {
        string key = "KgKnVRujrgAv4XjD4bKCqdQVN5De0DCw8zpu1URnPw8"; // this decryption key is not the correct one to use
        string apiResponse = "$-1$cb8ba9e30b19ff2a$d1157421764fe503d1fa9810fb9e6c3b424a1e8d014a321f5a2fb47ec6ebc8287d4d6236448d3623be42cf927fb883ca48810037c1a62bd229f937727c272c76420eb1f630bb2856c27d10c955220a1539f64e07c5708db90787ac470cad8372ea086501981c7a53ca69740c7ccfced856e234a6801efcf1f71178e75646441ba2716ea75a75ff3e6e002ba08ad18efeef95a909c9a5c68087cc63ed138a63c6788b9bbc43f3c04d2a496660f84ac98f011d3930c61ce9d5565131d2cba65db7c9bef824dd9a6594";

        Match matches = Regex.Match(apiResponse, @"^\$([^$]{2,4})\$([a-f0-9]{16,64})\$([a-f0-9]*)");
        Group algorithm = matches.Groups[1];
        Group salt = matches.Groups[2];
        Group content = matches.Groups[3];
        string encryptedContent = content.ToString();
        string decryptedContent = Decrypt(encryptedContent, key);
    }

    private static string Decrypt(string encryptedContent, string decryptionKey)
    {
        byte[] contentBytes = Hex.Decode(encryptedContent);
        BlowfishEngine blowfishEngine = new BlowfishEngine();
        PaddedBufferedBlockCipher paddedBufferedBlockCipher = new PaddedBufferedBlockCipher(blowfishEngine);
        byte[] keyBytes = Encoding.UTF8.GetBytes(decryptionKey);
        KeyParameter keyParameter = new KeyParameter(keyBytes);
        paddedBufferedBlockCipher.Init(false, keyParameter);
        int outputLength = paddedBufferedBlockCipher.GetOutputSize(contentBytes.Length);
        byte[] outputBytes = new byte[outputLength];
        int processedBytes = paddedBufferedBlockCipher.ProcessBytes(contentBytes, 0, contentBytes.Length, outputBytes, 0);
        paddedBufferedBlockCipher.DoFinal(outputBytes, processedBytes); // throws Org.BouncyCastle.Crypto.InvalidCipherTextException: 'pad block corrupted'

        string decryptedContentString = BitConverter
            .ToString(outputBytes)
            .Replace("-", "");

        byte[] hexBytes = new byte[decryptedContentString.Length / 2];

        for (int i = 0; i < hexBytes.Length; i++)
        {
            string currentHexString = decryptedContentString.Substring(i * 2, 2);
            hexBytes[i] = Convert.ToByte(currentHexString, 16);
        }

        return Encoding.UTF8.GetString(hexBytes);
    }
}
paddedBufferedBlockCipher.DoFinal(outputBytes, processedBytes);