如何使用 BouncyCastle Blowfish 实现解密数据?
How to decrypt data using the BouncyCastle Blowfish implementation?
我正在使用一个外部 API,其中 returns 我是一个 Blowfish 加密的 JSON 数组。首先,我尝试使用基于此 post c# Bouncy Castle Blowfish Decryption - Pad block corrupted.
的 BountyCastle 包来实现 Blowfish encrypt/decrypt 方法
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}][=10=][=10=][=10=][=10=][=10=]
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);
}
}
现在我想解密 API 响应。 Apireturns我下面的Blowfish加密JSON正文内容
$-1$cb8ba9e30b19ff2a$d1157421764fe503d1fa9810fb9e6c3b424a1e8d014a321f5a2fb47ec6ebc8287d4d6236448d3623be42cf927fb883ca48810037c1a62bd229f937727c272c76420eb1f630bb2856c27d10c955220a1539f64e07c5708db90787ac470cad8372ea086501981c7a53ca69740c7ccfced856e234a6801efcf1f71178e75646441ba2716ea75a75ff3e6e002ba08ad18efeef95a909c9a5c68087cc63ed138a63c6788b9bbc43f3c04d2a496660f84ac98f011d3930c61ce9d5565131d2cba65db7c9bef824dd9a6594
我收到了一个解密密钥和这个 PHP 代码示例作为“文档”。响应本身包含三组
- switch 语句的字符串(例如 -1)
- 表示盐的十六进制字符串
- 表示内容的十六进制字符串
.
<?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);
抛出一个
Org.BouncyCastle.Crypto.InvalidCipherTextException: 'pad block corrupted'
异常。有人知道如何解密这个 Api 回复吗?
PHP代码首先将三部分分开。第二部分是 IV,它是十六进制解码的,因此大小为 8 字节。第三部分是数据,由于第一部分中的 -1,它首先被十六进制解码,然后通过在 CBC 模式下应用带有 PKCS7 填充的 Blowfish,使用密钥和 IV 解密。
检查C#实现,测试数据有用:
- 应用以下 Base64 解码密钥作为 20 字节密钥:
MDEyMzQ1Njc4OTAxMjM0NTY3ODk=
- 作为密文使用:
$-1$cb8ba9e30b19ff2acb8430f6b9c109e4334874408dbd26be36b0c9600383d63afd70669efcec38bea1290dfbe6b71519b1f48b514957845
如果您在 PHP 代码中使用此数据,decryptData()
returns:
The quick brown fox jumps over the lazy dog
必须在 C# 代码中进行以下更改:
- 考虑 IV
- 使用 CBC 模式和 PKCS7 填充
- 密钥的Base64解码
这个结果例如在下面的实现中:
private static void Main(string[] args)
{
//string key = "KgKnVRujrgAv4XjD4bKCqdQVN5De0DCw8zpu1URnPw8"; // this decryption key is not the correct one to use
//string apiResponse = "$-1$cb8ba9e30b19ff2a$d1157421764fe503d1fa9810fb9e6c3b424a1e8d014a321f5a2fb47ec6ebc8287d4d6236448d3623be42cf927fb883ca48810037c1a62bd229f937727c272c76420eb1f630bb2856c27d10c955220a1539f64e07c5708db90787ac470cad8372ea086501981c7a53ca69740c7ccfced856e234a6801efcf1f71178e75646441ba2716ea75a75ff3e6e002ba08ad18efeef95a909c9a5c68087cc63ed138a63c6788b9bbc43f3c04d2a496660f84ac98f011d3930c61ce9d5565131d2cba65db7c9bef824dd9a6594";
string key = "MDEyMzQ1Njc4OTAxMjM0NTY3ODk=";
string apiResponse = "$-1$cb8ba9e30b19ff2acb8430f6b9c109e4334874408dbd26be36b0c9600383d63afd70669efcec38bea1290dfbe6b71519b1f48b514957845";
Match matches = Regex.Match(apiResponse, @"^$([^$]{2,4})$([a-f0-9]{16,64})$([a-f0-9]*)");
Group algorithm = matches.Groups[1];
Group iv = matches.Groups[2]; // 2nd part is the IV
Group content = matches.Groups[3];
string decryptedContent = Decrypt(content.ToString(), key, iv.ToString()); // Pass additionally the IV
Console.WriteLine(decryptedContent);
}
private static string Decrypt(string encryptedContent, string decryptionKey, string iv)
{
byte[] contentBytes = Hex.Decode(encryptedContent);
byte[] keyBytes = Convert.FromBase64String(decryptionKey); // Base64 decode the key
KeyParameter keyParameter = new KeyParameter(keyBytes);
ParametersWithIV keyParamWithIv = new ParametersWithIV(keyParameter, Hex.Decode(iv)); // Consider the IV
BlowfishEngine blowfishEngine = new BlowfishEngine();
PaddedBufferedBlockCipher paddedBufferedBlockCipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(blowfishEngine), new Pkcs7Padding()); // Consider CBC mode and PKCS7 padding
paddedBufferedBlockCipher.Init(false, keyParamWithIv);
int outputLength = paddedBufferedBlockCipher.GetOutputSize(contentBytes.Length);
byte[] outputBytes = new byte[outputLength];
int processedBytes = paddedBufferedBlockCipher.ProcessBytes(contentBytes, 0, contentBytes.Length, outputBytes, 0);
processedBytes += paddedBufferedBlockCipher.DoFinal(outputBytes, processedBytes);
return Encoding.UTF8.GetString(outputBytes, 0, processedBytes); // The quick brown fox jumps over the lazy dog
}
如果执行此代码,测试明文结果。因此,使用此代码,您的密文应该可以使用您的密钥解密。
我正在使用一个外部 API,其中 returns 我是一个 Blowfish 加密的 JSON 数组。首先,我尝试使用基于此 post c# Bouncy Castle Blowfish Decryption - Pad block corrupted.
的 BountyCastle 包来实现 Blowfish encrypt/decrypt 方法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}][=10=][=10=][=10=][=10=][=10=]
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);
}
}
现在我想解密 API 响应。 Apireturns我下面的Blowfish加密JSON正文内容
$-1$cb8ba9e30b19ff2a$d1157421764fe503d1fa9810fb9e6c3b424a1e8d014a321f5a2fb47ec6ebc8287d4d6236448d3623be42cf927fb883ca48810037c1a62bd229f937727c272c76420eb1f630bb2856c27d10c955220a1539f64e07c5708db90787ac470cad8372ea086501981c7a53ca69740c7ccfced856e234a6801efcf1f71178e75646441ba2716ea75a75ff3e6e002ba08ad18efeef95a909c9a5c68087cc63ed138a63c6788b9bbc43f3c04d2a496660f84ac98f011d3930c61ce9d5565131d2cba65db7c9bef824dd9a6594
我收到了一个解密密钥和这个 PHP 代码示例作为“文档”。响应本身包含三组
- switch 语句的字符串(例如 -1)
- 表示盐的十六进制字符串
- 表示内容的十六进制字符串
.
<?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);
抛出一个
Org.BouncyCastle.Crypto.InvalidCipherTextException: 'pad block corrupted'
异常。有人知道如何解密这个 Api 回复吗?
PHP代码首先将三部分分开。第二部分是 IV,它是十六进制解码的,因此大小为 8 字节。第三部分是数据,由于第一部分中的 -1,它首先被十六进制解码,然后通过在 CBC 模式下应用带有 PKCS7 填充的 Blowfish,使用密钥和 IV 解密。
检查C#实现,测试数据有用:
- 应用以下 Base64 解码密钥作为 20 字节密钥:
MDEyMzQ1Njc4OTAxMjM0NTY3ODk=
- 作为密文使用:
$-1$cb8ba9e30b19ff2acb8430f6b9c109e4334874408dbd26be36b0c9600383d63afd70669efcec38bea1290dfbe6b71519b1f48b514957845
如果您在 PHP 代码中使用此数据,decryptData()
returns:
The quick brown fox jumps over the lazy dog
必须在 C# 代码中进行以下更改:
- 考虑 IV
- 使用 CBC 模式和 PKCS7 填充
- 密钥的Base64解码
这个结果例如在下面的实现中:
private static void Main(string[] args)
{
//string key = "KgKnVRujrgAv4XjD4bKCqdQVN5De0DCw8zpu1URnPw8"; // this decryption key is not the correct one to use
//string apiResponse = "$-1$cb8ba9e30b19ff2a$d1157421764fe503d1fa9810fb9e6c3b424a1e8d014a321f5a2fb47ec6ebc8287d4d6236448d3623be42cf927fb883ca48810037c1a62bd229f937727c272c76420eb1f630bb2856c27d10c955220a1539f64e07c5708db90787ac470cad8372ea086501981c7a53ca69740c7ccfced856e234a6801efcf1f71178e75646441ba2716ea75a75ff3e6e002ba08ad18efeef95a909c9a5c68087cc63ed138a63c6788b9bbc43f3c04d2a496660f84ac98f011d3930c61ce9d5565131d2cba65db7c9bef824dd9a6594";
string key = "MDEyMzQ1Njc4OTAxMjM0NTY3ODk=";
string apiResponse = "$-1$cb8ba9e30b19ff2acb8430f6b9c109e4334874408dbd26be36b0c9600383d63afd70669efcec38bea1290dfbe6b71519b1f48b514957845";
Match matches = Regex.Match(apiResponse, @"^$([^$]{2,4})$([a-f0-9]{16,64})$([a-f0-9]*)");
Group algorithm = matches.Groups[1];
Group iv = matches.Groups[2]; // 2nd part is the IV
Group content = matches.Groups[3];
string decryptedContent = Decrypt(content.ToString(), key, iv.ToString()); // Pass additionally the IV
Console.WriteLine(decryptedContent);
}
private static string Decrypt(string encryptedContent, string decryptionKey, string iv)
{
byte[] contentBytes = Hex.Decode(encryptedContent);
byte[] keyBytes = Convert.FromBase64String(decryptionKey); // Base64 decode the key
KeyParameter keyParameter = new KeyParameter(keyBytes);
ParametersWithIV keyParamWithIv = new ParametersWithIV(keyParameter, Hex.Decode(iv)); // Consider the IV
BlowfishEngine blowfishEngine = new BlowfishEngine();
PaddedBufferedBlockCipher paddedBufferedBlockCipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(blowfishEngine), new Pkcs7Padding()); // Consider CBC mode and PKCS7 padding
paddedBufferedBlockCipher.Init(false, keyParamWithIv);
int outputLength = paddedBufferedBlockCipher.GetOutputSize(contentBytes.Length);
byte[] outputBytes = new byte[outputLength];
int processedBytes = paddedBufferedBlockCipher.ProcessBytes(contentBytes, 0, contentBytes.Length, outputBytes, 0);
processedBytes += paddedBufferedBlockCipher.DoFinal(outputBytes, processedBytes);
return Encoding.UTF8.GetString(outputBytes, 0, processedBytes); // The quick brown fox jumps over the lazy dog
}
如果执行此代码,测试明文结果。因此,使用此代码,您的密文应该可以使用您的密钥解密。