https://www.cnblogs.com/Again/p/7698187.html
昨天做项目的时候,遇到了c++通讯发送加密数据c#解密出错问题。 因为有很多选项,特地做了个对比,研究了其中的一些参数 DES 要注意的项目: 1.密钥 Key、IV 两个密钥都是8字节 2.模式 ECB、CBC 在ECB模式下,只用key;在CBC模式下,同时使用key和IV 3.字节填充模式 非8倍数字节数、8倍数字节数 [url=] [/url]
C# DES{ //输入 byte[] INPUT_buffer____ = { 0x31, }; //ECB byte[] ECB_PKCS7_____ = { 0xD6, 0x98, 0x32, 0xA0, 0x62, 0x9A, 0xB7, 0x0F, }; byte[] ECB_Zeros_____ = { 0xB6, 0x61, 0x3E, 0xE6, 0x93, 0x8B, 0x45, 0x71, };// 填充Zero√ byte[] ECB_ANSIX923__ = { 0x7C, 0xB0, 0xEE, 0xE6, 0xD1, 0x3C, 0xC7, 0x88, }; byte[] ECB_ISO10126__ = { 0x0A, 0x22, 0x65, 0xE4, 0x2E, 0xB3, 0xBC, 0x34, }; //CBC byte[] CBC_PKCS7_____ = { 0x3C, 0x77, 0x8E, 0xD4, 0x82, 0xA6, 0x66, 0x36, }; byte[] CBC_Zeros_____ = { 0x40, 0x9D, 0xA7, 0xE5, 0x0D, 0xDF, 0x61, 0x7E, };// 填充Zero√ byte[] CBC_ANSIX923__ = { 0x41, 0x91, 0x0C, 0xCE, 0xC4, 0x41, 0x77, 0xFF, }; byte[] CBC_ISO10126__ = { 0x5C, 0x9C, 0xA9, 0xD6, 0x65, 0x23, 0x5E, 0x39, };}C# DES{ //输入 byte[] INPUT_buffer____ = { 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, }; //ECB byte[] ECB_PKCS7_____ = { 0x74, 0xA5, 0x81, 0x53, 0x4A, 0x4B, 0xF8, 0xB1, 0x89, 0xF4, 0xD1, 0xBA, 0x96, 0x97, 0x9A, 0xD0, }; byte[] ECB_Zeros_____ = { 0x74, 0xA5, 0x81, 0x53, 0x4A, 0x4B, 0xF8, 0xB1, };// 填充Zero√ byte[] ECB_ANSIX923__ = { 0x74, 0xA5, 0x81, 0x53, 0x4A, 0x4B, 0xF8, 0xB1, 0x24, 0xC8, 0x74, 0xB9, 0x6D, 0x5C, 0x9E, 0x13, }; byte[] ECB_ISO10126__ = { 0x74, 0xA5, 0x81, 0x53, 0x4A, 0x4B, 0xF8, 0xB1, 0xAC, 0xB2, 0x70, 0x9C, 0xDC, 0xB5, 0x2C, 0x03, }; //CBC byte[] CBC_PKCS7_____ = { 0x6B, 0x0E, 0xC8, 0x18, 0x33, 0xE5, 0xE6, 0xA7, 0x70, 0xF9, 0x31, 0x8D, 0xDF, 0x6C, 0x6A, 0x86, }; byte[] CBC_Zeros_____ = { 0x6B, 0x0E, 0xC8, 0x18, 0x33, 0xE5, 0xE6, 0xA7, };// 填充Zero√ byte[] CBC_ANSIX923__ = { 0x6B, 0x0E, 0xC8, 0x18, 0x33, 0xE5, 0xE6, 0xA7, 0x28, 0xA0, 0xBC, 0x4A, 0x5A, 0x28, 0x41, 0xB8, }; byte[] CBC_ISO10126__ = { 0x6B, 0x0E, 0xC8, 0x18, 0x33, 0xE5, 0xE6, 0xA7, 0xD5, 0xF9, 0x47, 0xDD, 0xF3, 0xCE, 0x7D, 0xC2, };}2017-10-19 22:59:33,455 - 461560 [DEBUG] : ECB : PAD_ISO_12017-10-19 22:59:33,456 - 461560 [DEBUG] : B6613EE6938B457100000000000000002017-10-19 22:59:33,457 - 461560 [DEBUG] : ECB : PAD_ISO_22017-10-19 22:59:33,457 - 461560 [DEBUG] : B6613EE6938B457100000000000000002017-10-19 22:59:33,458 - 461560 [DEBUG] : ECB : PAD_PKCS_72017-10-19 22:59:33,458 - 461560 [DEBUG] : B6613EE6938B45710000000000000000 // 填充Zero√2017-10-19 22:59:33,459 - 461560 [DEBUG] : CBC : PAD_ISO_12017-10-19 22:59:33,460 - 461560 [DEBUG] : 409DA7E50DDF617E00000000000000002017-10-19 22:59:33,460 - 461560 [DEBUG] : CBC : PAD_ISO_22017-10-19 22:59:33,461 - 461560 [DEBUG] : 409DA7E50DDF617E00000000000000002017-10-19 22:59:33,462 - 461560 [DEBUG] : CBC : PAD_PKCS_72017-10-19 22:59:33,462 - 461560 [DEBUG] : 409DA7E50DDF617E0000000000000000 // 填充Zero√2017-10-19 23:01:30,977 - 464436 [DEBUG] : ECB : PAD_ISO_12017-10-19 23:01:30,979 - 464436 [DEBUG] : 74A581534A4BF8B100000000000000002017-10-19 23:01:30,980 - 464436 [DEBUG] : ECB : PAD_ISO_22017-10-19 23:01:30,981 - 464436 [DEBUG] : 74A581534A4BF8B100000000000000002017-10-19 23:01:30,982 - 464436 [DEBUG] : ECB : PAD_PKCS_72017-10-19 23:01:30,983 - 464436 [DEBUG] : 74A581534A4BF8B10000000000000000 // 填充Zero√2017-10-19 23:01:30,988 - 464436 [DEBUG] : CBC : PAD_ISO_12017-10-19 23:01:30,989 - 464436 [DEBUG] : 6B0EC81833E5E6A700000000000000002017-10-19 23:01:30,990 - 464436 [DEBUG] : CBC : PAD_ISO_22017-10-19 23:01:30,990 - 464436 [DEBUG] : 6B0EC81833E5E6A700000000000000002017-10-19 23:01:30,991 - 464436 [DEBUG] : CBC : PAD_PKCS_72017-10-19 23:01:30,992 - 464436 [DEBUG] : 6B0EC81833E5E6A70000000000000000 // 填充Zero√长度不足应该补充 00 ,并且只有不满足8倍数字节的时候才补充字节[url=] [/url]
不同的填充模式,对于输出的结果最后一组数据会有很大不同。 譬如: 金融DES:在末尾填充“8000...” PKCS #7: 填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。
Zeros :填充字符串由设置为零的字节组成。
ANSIX923: 填充字符串由一个字节序列组成,此字节序列的最后一个字节填充字节序列的长度,其余字节均填充数字零。
ISO10126: 填充字符串由一个字节序列组成,此字节序列的最后一个字节填充字节序列的长度,其余字节填充随机数据。
代码中C++库,对于其他填充模式支持不好,默认设置为 PAD_PKCS_7,并表现出跟C# Zero填充一样的效果 下面贴出代码示例 c#代码 [url=] [/url]
private byte[] Encrypt(byte[] inputByteArray, string sKey) { DESCryptoServiceProvider des = new DESCryptoServiceProvider(); //建立加密对象的密钥和偏移量 //原文使用ASCIIEncoding.ASCII方法的GetBytes方法 //使得输入密码必须输入英文文本 des.Mode = CipherMode.CBC; des.Padding = PaddingMode.Zeros; des.Key = ASCIIEncoding.ASCII.GetBytes(sKey); des.IV = ASCIIEncoding.ASCII.GetBytes(sKey); MemoryStream ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write); //Write the byte array into the crypto stream //(It will end up in the memory stream) cs.Write(inputByteArray, 0, inputByteArray.Length); cs.FlushFinalBlock(); //Get the data back from the memory stream byte[] result = ms.ToArray(); return result; } //解密方法 private byte[] Decrypt(byte[] inputByteArray, string sKey) { DESCryptoServiceProvider des = new DESCryptoServiceProvider(); //建立加密对象的密钥和偏移量,此值重要,不能修改 des.Mode = CipherMode.CBC; des.Padding = PaddingMode.Zeros; des.Key = ASCIIEncoding.ASCII.GetBytes(sKey); des.IV = ASCIIEncoding.ASCII.GetBytes(sKey); MemoryStream ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write); //Flush the data through the crypto stream into the memory stream cs.Write(inputByteArray, 0, inputByteArray.Length); cs.FlushFinalBlock(); //Get the data back from the memory stream byte[] result = ms.ToArray(); return result; }[url=] [/url]
c#demo byte[] buffer = { 0x02, 0xDF, 0xD1, 0x9F, 0x23, 0xC9, 0x29, 0xA7, 0x3B, 0xB9, 0x92, 0xED, 0x2A, 0xB2, 0x47, 0x03, 0x7E, 0x6F, 0x27, 0x92, 0x0E, 0xDB, 0x17, 0xB2, 0x53, 0x2C, 0x48, 0x38, 0x61, 0x8E, 0x2E, 0xB2, 0xD2, 0xB7, 0xCA, 0x4F, 0x7D, 0xCE, 0x0F, 0xA4, 0xD7, 0x06, 0xA7, 0x29 };byte[] minwen = Decrypt(buffer, "password");
c++ 代码 来源于[邹德强代码] DES.h
DES.cpp
代码中C++库,对于其他填充模式支持不好,默认设置为 PAD_PKCS_7,并表现出跟C# Zero填充一样的效果 c++封装,相当于使用案例 [url=] [/url]
#ifndef CDES_H_CAESAR_1_DEF #define CDES_H_CAESAR_1_DEF #include <string>#include <iostream>class HGDes { private: HGDes(); virtual ~HGDes(); public: //加密 - 从流中加密数据 static void DES_Decrypt(std::istream& input,std: stream& output); //解密 - 从流中解密数据 static void DES_Encrypt(std::istream& input,std: stream& output); //加密 - 加密文本到base64格式 static std::string Encrypt_to_Base64(std::string input); //解密 - 从base64格式解密文本 static std::string Decrypt_from_Base64(std::string input);}; #endif//CDES_H_CAESAR__DEF [url=] [/url]
[url=] [/url]
// DES.cpp: implementation of the CDES class. // ////////////////////////////////////////////////////////////////////// #include "HGDES.h" #include "memory.h" #include <iostream> #include <sstream>#include "DES.h"#include "..\Base64\Base64.h"using namespace std; HGDes::HGDes() { } HGDes::~HGDes() { } void HGDes: ES_Encrypt(std::istream& input,std: stream& output){ //计算缓冲区长度 input.seekg(0, input.end); int datalen = input.tellg(); input.seekg(0, input.beg); int outlen = ((datalen/8)*8) + ((datalen%8==0) ? 0:8); //创建缓冲区 char* In = new char[datalen]; char* Out = new char[outlen]; memset(In,0,datalen); memset(Out,0,outlen); for (int i=0 ; i<datalen ; i++) { In = input.get(); } int keylen = 8; char Key[8] = {0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,}; char IV[8] = {0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,}; Des::RunDes(Des::ENCRYPT,Des::CBC, In,Out,datalen,Key,keylen); for (int i = 0; i < outlen ; i++) { output<<Out; }}void HGDes: ES_Decrypt(std::istream& input,std: stream& output){ //计算缓冲区长度 input.seekg(0, input.end); int datalen = input.tellg(); input.seekg(0, input.beg); int outlen = ((datalen/8)*8) + ((datalen%8==0) ? 0:8); //创建缓冲区 char* In = new char[datalen]; char* Out = new char[datalen]; memset(In,0,datalen); memset(Out,0,datalen); for (int i=0 ; i<datalen ; i++) { In = input.get(); } int keylen = 8; char Key[8] = {0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,}; char IV[8] = {0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,}; Des::RunDes(Des: ECRYPT,Des::CBC, In,Out,datalen,Key,keylen); //计算末尾0的数量 int count = 0; for (int i = outlen - 1; i >= 0 ; i--) { if (Out != 0) { break; } count++; } for (int i = 0; i < outlen - count ; i++) { output<<Out; }}std::string HGDes::Encrypt_to_Base64(std::string input){ if (input.empty()) { return ""; } else { std::stringstream inputstream; inputstream << input; std::stringstream outputstream; DES_Encrypt(inputstream,outputstream); std::string result = Base64::base64_encode(outputstream); return result; }}std::string HGDes: ecrypt_from_Base64(std::string input){ if (input.empty()) { return ""; } else { std::stringstream inputstream; Base64::base64_decode(input,inputstream); std::stringstream outputstream; DES_Decrypt(inputstream,outputstream); return outputstream.str(); }}[url=] [/url]
|