如何使用预定义的密钥和 IV 在 python3 中进行 TripleDES 加密?
How do I do TripleDES encryption in python3 using a pre-defined key and IV?
由于遗留 C#.NET 代码,我无法更改密钥和 IV。他们就是他们本来的样子。但我似乎无法找到一种方法来做我需要做的事情。我试过这个...
strToEncrypt = "Please encrypt me."
ivStr = "AStringOfIV="
keyStr = "aKeyOfSomeKindThat+IWillNotShare"
cipher = DES3.new(keyStr, DES3.MODE_CFB, IV=ivStr)
encryptedStr = cipher.iv + cipher.encrypt(strToEncrypt)
这告诉我“IV 必须是 8 个字节长。”
我的不是,也不可能。所以显然这行不通。我也试过这个:
m=hashlib.md5()
print(sys.getsizeof(iv))
m.update(bytes(keyStr, 'UTF-8'))
k = pyDes.triple_des(m.digest(),pyDes.CBC,IV=iv,padmode=pyDes.PAD_PKCS5)
encryptedStr = k.encrypt(strToEncrypt)
这告诉我“初始值 (IV) 无效,必须是 8 字节的倍数”。
我调整了 ivStr 变量,如上所示使用 getsizeof() 检查它,看看会发生什么:
ivStr = "AStringOfIV===="
我收到相同的消息,“初始值 (IV) 无效,必须是 8 字节的倍数”。但它是。现在怎么办?
我尝试直接将它作为字节传递,原始的 ivStr 和 64 字节的都带有额外的等号。
k = pyDes.triple_des(
keyStr,
mode=pyDes.CBC,
IV=bytes(ivStr, 'UTF-8'),
pad=None,
padmode=pyDes.PAD_PKCS5
)
encryptedStr = k.encrypt(strToEncrypt)
我收到相同的消息,“初始值 (IV) 无效,必须是 8 字节的倍数”。就是我告诉你!
我尝试了 pyDes.CBC 和 pyDes.ECB,想知道这是否会有所不同。 None我看到了。
根据@ShadowRanger 在下面评论中的建议,我将初始代码更改为添加 b64decode
和 b64encode
,如下所示:
pyDes.triple_des(m.digest(),pyDes.CBC,IV=base64.b64decode(ivStr),padmode=pyDes.PAD_PKCS5)
encryptedStr = base64.b64encode(k.encrypt(strToEncrypt))
这确实消除了我得到的 8 字节错误并生成了一个字符串结果,但是,该字符串结果与 C# 程序生成的结果不匹配,所以我还没有到达终点。
作为参考,如果有帮助,将用于我的加密字符串的 C#.NET 解密代码(以及首先用于加密它的旧 C#.NET 代码)位于此处:
using System;
using System.Security.Cryptography;
using System.Text;
namespace encryption
{
class Program
{
const string IV = "AStringOfIV=";
const string Key = "aKeyOfSomeKindThat+IWillNotShare";
public static string Encrypt(string data)
{
byte[] buffer = Encoding.UTF8.GetBytes(data);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
ICryptoTransform transform = tdes.CreateEncryptor(Convert.FromBase64String(Key), Convert.FromBase64String(IV));
byte[] result = transform.TransformFinalBlock(buffer, 0, buffer.Length);
string encrypted = BitConverter.ToString(result).Replace("-", "");
return encrypted;
}
public static string Decrypt(string data)
{
byte[] result = StringToByteArray(data);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
ICryptoTransform transform = tdes.CreateDecryptor(Convert.FromBase64String(Key), Convert.FromBase64String(IV));
byte[] originalBytes = transform.TransformFinalBlock(result, 0, result.Length);
string original = Encoding.UTF8.GetString(originalBytes);
return original;
}
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length / 2;
byte[] bytes = new byte[NumberChars];
using (var sr = new System.IO.StringReader(hex))
{
for (int i = 0; i < NumberChars; i++)
{
string thisByte = new string(new char[2] { (char)sr.Read(), (char)sr.Read() });
bytes[i] = Convert.ToByte(thisByte, 16);
}
}
return bytes;
}
static void Main(string[] args)
{
Console.WriteLine(Encrypt("397854"));
Console.WriteLine(Encrypt("397786"));
Console.WriteLine(Encrypt("70001948"));
Console.WriteLine(Encrypt("70001890"));
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
}
}
上面的代码,当 运行 作为控制台应用程序时,会产生以下结果,我需要将其复制到 python3:
4B7389BB6DFE3AC7
39C739D51AC4FD13
BEB55BBC9430B83583E3E5E4E6C3799E
FD66F55347E715560C963B0EA181FB50
那么,如何使用预定义密钥和 IV 在 python3 中进行 TripleDES 加密?
如果您能为我提供任何有用的帮助,将不胜感激!
根据等号填充,我强烈怀疑您的 IV 是 base64 编码的。也许原始 API 期望收到它的 base64 编码?如果你这样做 base64.b64decode("AStringOfIV=")
它会产生一个长度为 8 的 IV,b'\x01+k\x8ax\x0e|\x85'
,这可能会得到你想要的行为。
确保您对每个值使用正确的编码 (Base64) 并使用正确的操作模式 (CBC)。
这是对我有用的 python 代码:
import pyDes
import base64
strToEncrypt = "Please encrypt me."
ivStr = "AStringOfIV="
keyStr = "aKeyOfSomeKindThat+IWillNotShare"
k = pyDes.triple_des(
base64.b64decode(keyStr),
mode=pyDes.CBC,
IV=base64.b64decode(ivStr),
padmode=pyDes.PAD_PKCS5
)
encryptedStr = k.encrypt(strToEncrypt)
k = pyDes.triple_des(
base64.b64decode(keyStr),
mode=pyDes.CBC,
IV=base64.b64decode(ivStr),
padmode=pyDes.PAD_PKCS5
)
decryptedStr = k.decrypt(encryptedStr)
请注意,由于存在许多问题,此代码并不安全:
- IV 是静态的,但对于 CBC 模式必须是不可预测的。 IV 不应该是秘密的。我们通常在加密时将其添加到密文中,然后在解密前将其切掉。
- Triple DES 的块大小较小,您使用的协议可能容易受到 Sweet32 或类似攻击。
- 您没有使用任何类型的身份验证。这样你就无法检测到密文是否有任何(恶意的)更改。 CBC 模式具有部分可延展性,因此如果您将其用于任何严肃的事情,接收方必须验证解密的消息,以便它完全符合非常严格的结构。相反,我建议使用 AES-GCM 或至少通过 encrypt-then-MAC 方案添加消息验证码,如 HMAC-SHA256。
- 您的 C# 代码使用默认的操作模式和填充。这很棘手,因为默认值可能会在未来的 .Net 版本中发生变化,这可能会破坏您的代码。始终限定您使用的选项。
由于遗留 C#.NET 代码,我无法更改密钥和 IV。他们就是他们本来的样子。但我似乎无法找到一种方法来做我需要做的事情。我试过这个...
strToEncrypt = "Please encrypt me."
ivStr = "AStringOfIV="
keyStr = "aKeyOfSomeKindThat+IWillNotShare"
cipher = DES3.new(keyStr, DES3.MODE_CFB, IV=ivStr)
encryptedStr = cipher.iv + cipher.encrypt(strToEncrypt)
这告诉我“IV 必须是 8 个字节长。”
我的不是,也不可能。所以显然这行不通。我也试过这个:
m=hashlib.md5()
print(sys.getsizeof(iv))
m.update(bytes(keyStr, 'UTF-8'))
k = pyDes.triple_des(m.digest(),pyDes.CBC,IV=iv,padmode=pyDes.PAD_PKCS5)
encryptedStr = k.encrypt(strToEncrypt)
这告诉我“初始值 (IV) 无效,必须是 8 字节的倍数”。
我调整了 ivStr 变量,如上所示使用 getsizeof() 检查它,看看会发生什么:
ivStr = "AStringOfIV===="
我收到相同的消息,“初始值 (IV) 无效,必须是 8 字节的倍数”。但它是。现在怎么办?
我尝试直接将它作为字节传递,原始的 ivStr 和 64 字节的都带有额外的等号。
k = pyDes.triple_des(
keyStr,
mode=pyDes.CBC,
IV=bytes(ivStr, 'UTF-8'),
pad=None,
padmode=pyDes.PAD_PKCS5
)
encryptedStr = k.encrypt(strToEncrypt)
我收到相同的消息,“初始值 (IV) 无效,必须是 8 字节的倍数”。就是我告诉你!
我尝试了 pyDes.CBC 和 pyDes.ECB,想知道这是否会有所不同。 None我看到了。
根据@ShadowRanger 在下面评论中的建议,我将初始代码更改为添加 b64decode
和 b64encode
,如下所示:
pyDes.triple_des(m.digest(),pyDes.CBC,IV=base64.b64decode(ivStr),padmode=pyDes.PAD_PKCS5)
encryptedStr = base64.b64encode(k.encrypt(strToEncrypt))
这确实消除了我得到的 8 字节错误并生成了一个字符串结果,但是,该字符串结果与 C# 程序生成的结果不匹配,所以我还没有到达终点。
作为参考,如果有帮助,将用于我的加密字符串的 C#.NET 解密代码(以及首先用于加密它的旧 C#.NET 代码)位于此处:
using System;
using System.Security.Cryptography;
using System.Text;
namespace encryption
{
class Program
{
const string IV = "AStringOfIV=";
const string Key = "aKeyOfSomeKindThat+IWillNotShare";
public static string Encrypt(string data)
{
byte[] buffer = Encoding.UTF8.GetBytes(data);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
ICryptoTransform transform = tdes.CreateEncryptor(Convert.FromBase64String(Key), Convert.FromBase64String(IV));
byte[] result = transform.TransformFinalBlock(buffer, 0, buffer.Length);
string encrypted = BitConverter.ToString(result).Replace("-", "");
return encrypted;
}
public static string Decrypt(string data)
{
byte[] result = StringToByteArray(data);
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
ICryptoTransform transform = tdes.CreateDecryptor(Convert.FromBase64String(Key), Convert.FromBase64String(IV));
byte[] originalBytes = transform.TransformFinalBlock(result, 0, result.Length);
string original = Encoding.UTF8.GetString(originalBytes);
return original;
}
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length / 2;
byte[] bytes = new byte[NumberChars];
using (var sr = new System.IO.StringReader(hex))
{
for (int i = 0; i < NumberChars; i++)
{
string thisByte = new string(new char[2] { (char)sr.Read(), (char)sr.Read() });
bytes[i] = Convert.ToByte(thisByte, 16);
}
}
return bytes;
}
static void Main(string[] args)
{
Console.WriteLine(Encrypt("397854"));
Console.WriteLine(Encrypt("397786"));
Console.WriteLine(Encrypt("70001948"));
Console.WriteLine(Encrypt("70001890"));
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
}
}
上面的代码,当 运行 作为控制台应用程序时,会产生以下结果,我需要将其复制到 python3:
4B7389BB6DFE3AC7
39C739D51AC4FD13
BEB55BBC9430B83583E3E5E4E6C3799E
FD66F55347E715560C963B0EA181FB50
那么,如何使用预定义密钥和 IV 在 python3 中进行 TripleDES 加密?
如果您能为我提供任何有用的帮助,将不胜感激!
根据等号填充,我强烈怀疑您的 IV 是 base64 编码的。也许原始 API 期望收到它的 base64 编码?如果你这样做 base64.b64decode("AStringOfIV=")
它会产生一个长度为 8 的 IV,b'\x01+k\x8ax\x0e|\x85'
,这可能会得到你想要的行为。
确保您对每个值使用正确的编码 (Base64) 并使用正确的操作模式 (CBC)。
这是对我有用的 python 代码:
import pyDes
import base64
strToEncrypt = "Please encrypt me."
ivStr = "AStringOfIV="
keyStr = "aKeyOfSomeKindThat+IWillNotShare"
k = pyDes.triple_des(
base64.b64decode(keyStr),
mode=pyDes.CBC,
IV=base64.b64decode(ivStr),
padmode=pyDes.PAD_PKCS5
)
encryptedStr = k.encrypt(strToEncrypt)
k = pyDes.triple_des(
base64.b64decode(keyStr),
mode=pyDes.CBC,
IV=base64.b64decode(ivStr),
padmode=pyDes.PAD_PKCS5
)
decryptedStr = k.decrypt(encryptedStr)
请注意,由于存在许多问题,此代码并不安全:
- IV 是静态的,但对于 CBC 模式必须是不可预测的。 IV 不应该是秘密的。我们通常在加密时将其添加到密文中,然后在解密前将其切掉。
- Triple DES 的块大小较小,您使用的协议可能容易受到 Sweet32 或类似攻击。
- 您没有使用任何类型的身份验证。这样你就无法检测到密文是否有任何(恶意的)更改。 CBC 模式具有部分可延展性,因此如果您将其用于任何严肃的事情,接收方必须验证解密的消息,以便它完全符合非常严格的结构。相反,我建议使用 AES-GCM 或至少通过 encrypt-then-MAC 方案添加消息验证码,如 HMAC-SHA256。
- 您的 C# 代码使用默认的操作模式和填充。这很棘手,因为默认值可能会在未来的 .Net 版本中发生变化,这可能会破坏您的代码。始终限定您使用的选项。