各位大師好,
小弟目前想開發使用3DES,並以CBC模式和ISO9797-1的算法來加密,
加密規則如上方圖片所示,輸入data不限定是幾字元,
想得出與其一樣的輸出,但嘗試了很久,都沒辦法得到預期的加密結果(確定這軟體加密是無誤的)
預期輸出:4BFDF58BCD4494003B73B6DD1338F5E74D9656983984217E1E0ADDA7AB6C225F22A038536B54F95B
我的輸出:1FB0FACB9E5F9D9A
以下是我的程式碼,懇請各位高手指正一下,非常感謝。
string Key_MAC = "447FC2AA6EFFFEE5405A559E88DC958C";
string input = "201801221009512692302018013521567";
byte[] kMAC = Encoding.UTF8.GetBytes(Key_MAC);
byte[] eIfd = Encoding.ASCII.GetBytes(input);
// Split the 16 byte MAC key into two keys
byte[] key1 = new byte[8];
Array.Copy(kMAC, 0, key1, 0, 8);
byte[] key2 = new byte[8];
Array.Copy(kMAC, 8, key2, 0, 8);
// Padd the data with Padding Method 2 (Bit Padding)
System.IO.MemoryStream out_Renamed = new System.IO.MemoryStream();
out_Renamed.Write(eIfd, 0, eIfd.Length);
out_Renamed.WriteByte((byte)(0x80));
while (out_Renamed.Length % 8 != 0)
{
out_Renamed.WriteByte((byte)0x00);
}
byte[] eIfd_padded = out_Renamed.ToArray();
// Split the blocks
byte[] d1 = new byte[8];
byte[] d2 = new byte[8];
byte[] d3 = new byte[8];
byte[] d4 = new byte[8];
byte[] d5 = new byte[8];
Array.Copy(eIfd_padded, 0, d1, 0, 8);
Array.Copy(eIfd_padded, 8, d2, 0, 8);
Array.Copy(eIfd_padded, 16, d3, 0, 8);
Array.Copy(eIfd_padded, 24, d4, 0, 8);
Array.Copy(eIfd_padded, 32, d5, 0, 8);
DES des1 = DES.Create();
des1.BlockSize = 64;
des1.Key = key1;
des1.Mode = CipherMode.CBC;
des1.Padding = PaddingMode.None;
des1.IV = new byte[8];
DES des2 = DES.Create();
des2.BlockSize = 64;
des2.Key = key2;
des2.Mode = CipherMode.CBC;
des2.Padding = PaddingMode.None;
des2.IV = new byte[8];
// MAC Algorithm 3
// Initial Transformation 1
byte[] h1 = des1.CreateEncryptor().TransformFinalBlock(d1, 0, 8);
// Iteration on the rest of blocks
// XOR
byte[] int2 = new byte[8];
for (int i = 0; i < 8; i++)
int2[i] = (byte)(h1[i] ^ d2[i]);
// Encrypt
byte[] h2 = des1.CreateEncryptor().TransformFinalBlock(int2, 0, 8);
// XOR
byte[] int3 = new byte[8];
for (int i = 0; i < 8; i++)
int3[i] = (byte)(h2[i] ^ d3[i]);
// Encrypt
byte[] h3 = des1.CreateEncryptor().TransformFinalBlock(int3, 0, 8);
// XOR
byte[] int4 = new byte[8];
for (int i = 0; i < 8; i++)
int4[i] = (byte)(h3[i] ^ d4[i]);
// Encrypt
byte[] h4 = des1.CreateEncryptor().TransformFinalBlock(int4, 0, 8);
// XOR
byte[] int5 = new byte[8];
for (int i = 0; i < 8; i++)
int5[i] = (byte)(h4[i] ^ d5[i]);
// Encrypt
byte[] h5 = des1.CreateEncryptor().TransformFinalBlock(int5, 0, 8);
// Output Transformation 3
byte[] h5decrypt = des2.CreateDecryptor().TransformFinalBlock(h5, 0, 8);
byte[] mIfd = des1.CreateEncryptor().TransformFinalBlock(h5decrypt, 0, 8);
string result = "";
for (int i = 0; i < mIfd.Length; i++)
{
result += mIfd[i].ToString("X2"); // hex format
}
label1.Text = result;
//輸出為: 1FB0FACB9E5F9D9A
沒寫過 C# ,不過目前我看到的問題:
Encoding.UTF8.GetBytes
是錯誤的,會產生 32 bytes)PaddingMode.Zeros
試試看剪剪貼貼改一下,有跑出來。
參考資料:
using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
public class Test
{
public static void Main()
{
string input = "201801221009512692302018013521567";
string Key_MAC = "447FC2AA6EFFFEE5405A559E88DC958C";
string IVHex = "0000000000000000";
byte[] data = Encoding.ASCII.GetBytes(input);
byte[] key = StringToByteArray(Key_MAC);
byte[] iv = StringToByteArray(IVHex);
byte[] result = EncryptTextToMemory(data, key, iv);
Console.WriteLine(ByteArrayToString(result));
}
public static byte[] EncryptTextToMemory(byte[] toEncrypt, byte[] Key, byte[] IV)
{
try
{
// Create a MemoryStream.
MemoryStream mStream = new MemoryStream();
//這邊有修改過,因為預設的 padding 不是 zero
TripleDESCryptoServiceProvider dec = new TripleDESCryptoServiceProvider();
dec.Padding = PaddingMode.Zeros;
// Create a CryptoStream using the MemoryStream
// and the passed key and initialization vector (IV).
CryptoStream cStream = new CryptoStream(
mStream,
dec.CreateEncryptor(Key, IV),
CryptoStreamMode.Write
);
// Convert the passed string to a byte array.
// Write the byte array to the crypto stream and flush it.
cStream.Write(toEncrypt, 0, toEncrypt.Length);
cStream.FlushFinalBlock();
// Get an array of bytes from the
// MemoryStream that holds the
// encrypted data.
byte[] ret = mStream.ToArray();
// Close the streams.
cStream.Close();
mStream.Close();
// Return the encrypted buffer.
return ret;
}
catch(CryptographicException e)
{
Console.WriteLine("A Cryptographic error occurred: {0}", e.Message);
return null;
}
}
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
}
這一類的加密算法真有點複雜,
感謝您的指正~
閒著自己用 javascript 全程刻一個當練習
可以純前端網頁計算而不用透過伺服器
DEMO:DES、3DES 計算機
原始碼:https://github.com/ren1244/des-calculator/