PBOC圈存时用到3DES加密解密以及MAC计算方法

时间:2021-11-12 04:08:59

最近在做PBOC圈存时用到了3DES的加密解密以及MAC计算问题,在网上了解一些知识,复制了一些demo学习,我这里没有深入研究,只是把我用到的和了解的做个总结,便于以后使用和学习。

3DES分双倍长和三倍长,我使用到的是双倍长,加密模式为ECB,代码如下

public static class EncryptUtils
{ //构造一个对称算法
private static SymmetricAlgorithm mCSP = new TripleDESCryptoServiceProvider();
//加密模式为ECB时,初始化向量是没用的
private static byte[] IV = { 0xB0, 0xA2, 0xB8, 0xA3, 0xDA, 0xCC, 0xDA, 0xCC }; /// <summary>
/// 3DES加密
/// </summary>
/// <param name="data"></param>
/// <param name="key"></param>
/// <returns></returns>
public static string Encrypt3DES(string strKey, string strValue)
{
byte[] key = TransTools.strToToHexByte(strKey);
byte[] value = TransTools.strToToHexByte(strValue);
TripleDESCryptoServiceProvider tdsc = new TripleDESCryptoServiceProvider();
//指定密匙长度,默认为192位
tdsc.KeySize = ;
//使用指定的key和IV(加密向量)
tdsc.Key = key;
//tdsc.IV = IV;
//加密模式,偏移
tdsc.Mode = CipherMode.ECB;
tdsc.Padding = PaddingMode.None;
//进行加密转换运算
ICryptoTransform ct = tdsc.CreateEncryptor();
//8很关键,加密结果是8字节数组
byte[] data = ct.TransformFinalBlock(value, , );
string results = "";
//基于十六进制
for (int i = ; i < data.Count(); i++)
{
results += string.Format("{0:X2}", data[i]); }
return results;
}
/// <summary>
///
/// </summary>
/// <param name="keys"></param>
/// <param name="values"></param>
/// <returns></returns>
public static string Decrypt3DES(string strKey, string strValue)
{ byte[] key = TransTools.strToToHexByte(strKey);
byte[] value = TransTools.strToToHexByte(strValue);
TripleDESCryptoServiceProvider tdsc = new TripleDESCryptoServiceProvider();
//指定密匙长度,默认为192位
tdsc.KeySize = ;
//使用指定的key和IV(加密向量)
tdsc.Key = key;
//tdsc.IV = IV;
//加密模式,偏移
tdsc.Mode = CipherMode.ECB;
tdsc.Padding = PaddingMode.None;
//进行加密转换运算
ICryptoTransform ct = tdsc.CreateDecryptor();
byte[] data = ct.TransformFinalBlock(value, , );
//8很关键,加密结果是8字节数组 string results = "";
//基于十六进制
for (int i = ; i < data.Count(); i++)
{
results += string.Format("{0:X2}", data[i]); }
return results;
} }

下面一段代码是用来计算MAC的,这是我完全copy网上大神的,不得不佩服啊

public  class Mac3Encrypt
{ private static int[] iSelePM1 = { // 置换选择1的矩阵
, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , }; private static int[] iSelePM2 = { // 置换选择2的矩阵
, , , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , }; private static int[] iROLtime = { // 循环左移位数表
, , , , , , , , , , , , , , , }; private static int[] iInitPM = { // 初始置换IP
, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , }; private static int[] iInvInitPM = { // 初始逆置换
, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , }; private static int[] iEPM = { // 选择运算E
, , , , , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , }; private static int[] iPPM = { // 置换运算P
, , , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , };
// 8个S盒 private static int[][] iSPM = new int[][]; public Mac3Encrypt()
{
iSPM[] = new int[]{, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , }; iSPM[] = new int[]{, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , };
iSPM[] = new int[] { , , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , };
iSPM[] = new int[] {, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , };
iSPM[] = new int[] { , , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , };
iSPM[] = new int[] {, , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , ,
, , , , , , , , };
iSPM[] = new int[] { , , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , ,
, , , , , , , , , };
iSPM[] = new int[] { , , , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , , ,
, , , , , , , , , , , , , , , , ,
, , , , , , , , , }; } private int[] iCipherKey = new int[];
private int[] iCKTemp = new int[];
private int[] iPlaintext = new int[];
private int[] iCiphertext = new int[];
private int[] iPKTemp = new int[];
private int[] iL = new int[];
private int[] iR = new int[]; // 数组置换
// iSource与iDest的大小不一定相等 private void permu(int[] iSource, int[] iDest, int[] iPM)
{
if (iDest == null) iDest = new int[iPM.Length]; for (int i = ; i < iPM.Length; i++)
iDest[i] = iSource[iPM[i] - ];
} // 将字节数组进行 位-〉整数 压缩
// 例如:{0x35,0xf3}->{0,0,1,1,0,1,0,1,1,1,1,1,0,0,1,1}, bArray->iArray
private void arrayBitToI(byte[] bArray, int[] iArray)
{
for (int i = ; i < iArray.Length; i++)
{
iArray[i] = (int)(bArray[i / ] >> ( - i % ) & 0x01);
}
} // 将整形数组进行 整数-〉位 压缩
// arrayBitToI的逆变换,iArray->bArray
private void arrayIToBit(byte[] bArray, int[] iArray)
{
for (int i = ; i < bArray.Length; i++)
{
bArray[i] = (byte)iArray[ * i];
for (int j = ; j < ; j++)
{
bArray[i] = (byte)(bArray[i] << );
bArray[i] += (byte)iArray[ * i + j];
}
}
} // 数组的逐项模2加
// array1[i]=array1[i]^array2[i]
private void arrayM2Add(int[] array1, int[] array2)
{
for (int i = ; i < array2.Length; i++)
{
array1[i] ^= array2[i];
}
} // 一个数组等分成两个数组-数组切割
private void arrayCut(int[] iSource, int[] iDest1, int[] iDest2)
{
int k = iSource.Length;
for (int i = ; i < k / ; i++)
{
iDest1[i] = iSource[i];
iDest2[i] = iSource[i + k / ];
}
} // 两个等大的数组拼接成一个
// arrayCut的逆变换
private void arrayComb(int[] iDest, int[] iSource1, int[] iSource2)
{
int k = iSource1.Length;
for (int i = ; i < k; i++)
{
iDest[i] = iSource1[i];
iDest[i + k] = iSource2[i];
}
} // 子密钥产生算法中的循环左移
private void ROL(int[] array)
{
int temp = array[];
for (int i = ; i < ; i++)
{
array[i] = array[i + ];
}
array[] = temp; temp = array[];
for (int i = ; i < ; i++)
{
array[ + i] = array[ + i + ];
}
array[] = temp; } // 16个子密钥完全倒置
private int[][] invSubKeys(int[][] iSubKeys)
{
int[][] iInvSubKeys = new int[][];
for (int i = ; i < ; i++)
{
iInvSubKeys[i] = new int[];
for (int j = ; j < ; j++)
iInvSubKeys[i][j] = iSubKeys[ - i][j];
}
return iInvSubKeys;
} // S盒代替
// 输入输出皆为部分数组,因此带偏移量
private void Sbox(int[] iInput, int iOffI, int[] iOutput, int iOffO,
int[] iSPM)
{
int iRow = iInput[iOffI] * + iInput[iOffI + ]; // S盒中的行号
int iCol = iInput[iOffI + ] * + iInput[iOffI + ] *
+ iInput[iOffI + ] * + iInput[iOffI + ];
// S盒中的列号
int x = iSPM[ * iRow + iCol];
iOutput[iOffO] = x >> & 0x01;
iOutput[iOffO + ] = x >> & 0x01;
iOutput[iOffO + ] = x >> & 0x01;
iOutput[iOffO + ] = x & 0x01;
} // 加密函数f
private int[] encFunc(int[] iInput, int[] iSubKey)
{
int[] iTemp1 = new int[];
int[] iTemp2 = new int[];
int[] iOutput = new int[];
permu(iInput, iTemp1, iEPM);
arrayM2Add(iTemp1, iSubKey);
for (int i = ; i < ; i++)
Sbox(iTemp1, i * , iTemp2, i * , iSPM[i]);
permu(iTemp2, iOutput, iPPM);
return iOutput;
} // 子密钥生成
private int[][] makeSubKeys(byte[] bCipherKey)
{
int[][] iSubKeys = new int[][];
arrayBitToI(bCipherKey, iCipherKey);
// int[] tmp = iCipherKey;
permu(iCipherKey, iCKTemp, iSelePM1);
for (int i = ; i < ; i++)
{
for (int j = ; j < iROLtime[i]; j++)
ROL(iCKTemp);
iSubKeys[i] = new int[];
permu(iCKTemp, iSubKeys[i], iSelePM2);
}
return iSubKeys;
} // 加密
private byte[] encrypt(byte[] bPlaintext, int[][] iSubKeys)
{
byte[] bCiphertext = new byte[];
arrayBitToI(bPlaintext, iPlaintext);
permu(iPlaintext, iPKTemp, iInitPM);
arrayCut(iPKTemp, iL, iR);
for (int i = ; i < ; i++)
{
if (i % == )
{
arrayM2Add(iL, encFunc(iR, iSubKeys[i]));
}
else
{
arrayM2Add(iR, encFunc(iL, iSubKeys[i]));
}
}
arrayComb(iPKTemp, iR, iL);
permu(iPKTemp, iCiphertext, iInvInitPM);
arrayIToBit(bCiphertext, iCiphertext);
return bCiphertext;
} // 解密
private byte[] decrypt(byte[] bCiphertext, int[][] iSubKeys)
{
int[][] iInvSubKeys = invSubKeys(iSubKeys);
return encrypt(bCiphertext, iInvSubKeys);
} // Bit XOR
private byte[] BitXor(byte[] Data1, byte[] Data2, int Len)
{
int i;
byte[] Dest = new byte[Len]; for (i = ; i < Len; i++)
Dest[i] = (byte)(Data1[i] ^ Data2[i]); return Dest;
} // 3DesMac
private byte[] MAC16(int[][] iSubKeys1, int[][] iSubKeys2, byte[] bInit,
byte[] bCiphertext)
{
byte[] pbySrcTemp = new byte[];
byte[] pbyInitData = new byte[];
byte[] pbyDeaSrc = new byte[];
byte[] pbyMac = new byte[];
int i, j, n, iAppend;
int nCur = ;
int iSrcLen = bCiphertext.Length;
n = iSrcLen / + ;
iAppend = - (n * - iSrcLen); for (nCur = ; nCur < ; nCur++)
pbyInitData[nCur] = bInit[nCur]; for (i = ; i < n; i++)
{
for (nCur = ; nCur < ; nCur++)
pbySrcTemp[] = 0x00;
if (i == (n - ))
{
for (nCur = ; nCur < iAppend; nCur++)
pbySrcTemp[nCur] = bCiphertext[i * + nCur];
pbySrcTemp[iAppend] = (byte)0x80;
for (j = iAppend + ; j < ; j++)
pbySrcTemp[j] = 0x00;
}
else
{
for (nCur = ; nCur < ; nCur++)
pbySrcTemp[nCur] = bCiphertext[i * + nCur];
} pbyDeaSrc = BitXor(pbySrcTemp, pbyInitData, ); pbyInitData = encrypt(pbyDeaSrc, iSubKeys1);
}
pbyDeaSrc = decrypt(pbyInitData, iSubKeys2);
pbyInitData = encrypt(pbyDeaSrc, iSubKeys1); for (nCur = ; nCur < ; nCur++)
pbyMac[nCur] = pbyInitData[nCur];
return pbyMac;
} //private String byte2hex(byte[] b)
//{ // 一个字节的数,
// // 转成16进制字符串
// String hs = "";
// String stmp = "";
// for (int n = 0; n < b.Length; n++)
// {
// // 整数转成十六进制表示
// stmp = String.Format("{0:X2}", b[n] & 0XFF);// (java.lang.Integer.toHexString(b[n] & 0XFF));
// if (stmp.Length == 1)
// hs = hs + "0" + stmp;
// else
// hs = hs + stmp;
// }
// return hs.ToUpper(); // 转成大写
//} private byte[] hex2byte(byte[] b)
{
if ((b.Length % ) != )
throw new Exception("长度不是偶数");
byte[] b2 = new byte[b.Length / ];
for (int n = ; n < b.Length; n += )
{
byte[] bs = new byte[];
Array.Copy(b, n, bs, , );
String item = System.Text.Encoding.Default.GetString(bs);
b2[n / ] = (byte)Convert.ToInt16(item, );
}
return b2;
} /*
* strKey:密钥,Hex字符串,如:78B49F4BF5B16A17DF4AF5A36E49F4A0.长度必须为32
* strInitData:初始因子.长度必须为16,一般为:0000000000000000 strMacData:MAC数据,长度必须为偶数
*/
public String Str3MAC(String strKey, String strInitData, String strMacData)
{
String strKey1;
String strKey2;
if ((strKey.Length) != )
{
throw new Exception("密钥长度不正确,必须为32");
}
if ((strInitData.Length) != )
{
throw new Exception("初始因子长度不正确,必须为16");
}
if ((strMacData.Length % ) != )
{
throw new Exception("MAC Data长度不是偶数");
} strKey1 = strKey.Substring(, );
strKey2 = strKey.Substring(, ); byte[] cipherKey1 = hex2byte(Encoding.Default.GetBytes(strKey1)); // 3DES的密钥K1
byte[] cipherKey2 = hex2byte(Encoding.Default.GetBytes(strKey2)); // 3DES的密钥K2
byte[] bInit = hex2byte(Encoding.Default.GetBytes(strInitData)); // 初始因子
byte[] bCiphertext = hex2byte(Encoding.Default.GetBytes(strMacData)); // MAC数据 int[][] subKeys1 = new int[][]; // 用于存放K1产生的子密钥
int[][] subKeys2 = new int[][]; // 用于存放K2产生的子密钥
subKeys1 = makeSubKeys(cipherKey1);
subKeys2 = makeSubKeys(cipherKey2); byte[] byMac = MAC16(subKeys1, subKeys2, bInit, bCiphertext); String sRet = byte2hex(byMac);
//System.out.println("strKey:" + strKey + " strInitData:" + strInitData
// + " strMacData:" + strMacData);
//System.out.println("sRet:" + sRet);
return sRet;
} public String calculatorMac(String communicationKey, String strData)
{
//System.out.println(strData);
return this.Str3MAC(communicationKey, "", strData);
} public String StrDe3DES(String strKey, String strEncData)
{
String strKey1;
String strKey2;
String strTemp1;
String strTemp2; if ((strKey.Length) != )
{
throw new Exception("密钥长度不正确,必须为32");
}
if ((strEncData.Length) != )
{
throw new Exception("数据密文长度不正确,必须为32");
} strKey1 = strKey.Substring(, );
strKey2 = strKey.Substring(, );
strTemp1 = strEncData.Substring(, );
strTemp2 = strEncData.Substring(, ); byte[] cipherKey1 = hex2byte(Encoding.Default.GetBytes(strKey1)); // 3DES的密钥K1
byte[] cipherKey2 = hex2byte(Encoding.Default.GetBytes(strKey2)); // 3DES的密钥K2 byte[] bCiphertext1 = hex2byte(Encoding.Default.GetBytes(strTemp1)); // 数据1
byte[] bCiphertext2 = hex2byte(Encoding.Default.GetBytes(strTemp2)); // 数据1 int[][] subKeys1 = new int[][]; // 用于存放K1产生的子密钥
int[][] subKeys2 = new int[][]; // 用于存放K2产生的子密钥
subKeys1 = makeSubKeys(cipherKey1);
subKeys2 = makeSubKeys(cipherKey2); byte[] bTemp11 = decrypt(bCiphertext1, subKeys1);
byte[] bTemp21 = encrypt(bTemp11, subKeys2);
byte[] bPlaintext11 = decrypt(bTemp21, subKeys1); byte[] bTemp12 = decrypt(bCiphertext2, subKeys1);
byte[] bTemp22 = encrypt(bTemp12, subKeys2);
byte[] bPlaintext12 = decrypt(bTemp22, subKeys1); return byte2hex(bPlaintext11) + byte2hex(bPlaintext12);
} private static byte[] hex2byte(string hexStr)
{ if ((hexStr.Length % ) != )
throw new Exception("长度不是偶数"); int ilen = hexStr.Length / ;
byte[] b2 = new byte[ilen];
for (int n = ; n < hexStr.Length; n += )
{
String item = hexStr.Substring(n, );
b2[n / ] = (byte)Convert.ToInt16(item, );
}
return b2;
} private static String byte2hex(byte[] b)
{ // 一个字节的数,
// 转成16进制字符串
String hs = "";
String stmp = "";
for (int n = ; n < b.Length; n++)
{
// 整数转成十六进制表示
stmp = String.Format("{0:X2}", b[n] & 0XFF);// (java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.Length == )
hs = hs + "" + stmp;
else
hs = hs + stmp;
}
return hs.ToUpper(); // 转成大写
} public static string DES3Encrypt(string strString, string strKey)
{
TripleDESCryptoServiceProvider DES = new TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider hashMD5 = new MD5CryptoServiceProvider();
DES.Key = hashMD5.ComputeHash(hex2byte(strKey));
DES.Mode = CipherMode.ECB;
ICryptoTransform DESEncrypt = DES.CreateEncryptor();
byte[] Buffer = hex2byte(strKey);
return byte2hex(DESEncrypt.TransformFinalBlock(Buffer, , Buffer.Length)); } }