Because of legacy C#.NET code, I cannot change the key and the IV. They simply are what they are. But I cannot seem to find a way to do what I need to do. I tried this...
strToEncrypt = "Please encrypt me."
ivStr = "AStringOfIV="
keyStr = "aKeyOfSomeKindThat+IWillNotShare"
cipher = DES3.new(keyStr, DES3.MODE_CFB, IV=ivStr)
encryptedStr = cipher.iv + cipher.encrypt(strToEncrypt)
This told me "IV must be 8 bytes long."
Mine isn't and it can't be. So apparently this won't work. I also tried this:
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)
This told me "Invalid Initial Value (IV), must be a multiple of 8 bytes".
I tweaked the ivStr variable, checking it with getsizeof() as shown above, just to see what would happen:
ivStr = "AStringOfIV===="
I got the same message, "Invalid Initial Value (IV), must be a multiple of 8 bytes". But... it is. Now what?
I tried passing it in as bytes directly, both with the original ivStr and with the one that was 64 bytes, with extra equals signs.
k = pyDes.triple_des(
keyStr,
mode=pyDes.CBC,
IV=bytes(ivStr, 'UTF-8'),
pad=None,
padmode=pyDes.PAD_PKCS5
)
encryptedStr = k.encrypt(strToEncrypt)
I got the same message, "Invalid Initial Value (IV), must be a multiple of 8 bytes". It is I tell you!
I tried pyDes.CBC and pyDes.ECB, wondering if somehow that would make a difference. None I could see.
Per a suggestion from @ShadowRanger in the comments below, I switched my initial code to add b64decode
and b64encode
like this:
pyDes.triple_des(m.digest(),pyDes.CBC,IV=base64.b64decode(ivStr),padmode=pyDes.PAD_PKCS5)
encryptedStr = base64.b64encode(k.encrypt(strToEncrypt))
That did remove the 8-bytes error I was getting and produced a string result, however, the string result does not match the result the C# program produces, so I am still not at the finish line yet.
For reference, if it helps, the C#.NET decrypt code that will be used against my encrypted string (and the old C#.NET code to encrypt it in the first place) is here:
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();
}
}
}
The code above, when run as a console application, produces the following results, which I need to duplicate in python3:
4B7389BB6DFE3AC7
39C739D51AC4FD13
BEB55BBC9430B83583E3E5E4E6C3799E
FD66F55347E715560C963B0EA181FB50
So, how do I do TripleDES encryption in python3 using a pre-defined key and IV?
If you can offer me any useful assistance, it would be very much appreciated!
Based on the equals padding, I strongly suspect your IV is base64 encoded. Perhaps the original API expected to receive it base64 encoded? If you do base64.b64decode("AStringOfIV=")
it produces a length 8 IV, b'\x01+k\x8ax\x0e|\x85'
, which may get the behavior you want.