如何用C 实现DES加密解密(DES在线解密)

2023-03-20 22:10:41 密语知识 思思

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

using System.Security.Cryptography;

namespace Sens.Security

{

    #region class - hDES

    public class HDES

    {

        #region private field

        /// summary

        /// 密钥加密算法,默认为SHA1

        /// /summary

        private HashAlgorithm KeyHash;

        private Listint supportedKeySize;

        private Encoding _encoding = Encoding.Default;

        private DES des;

        #endregion

        #region constructor

        public HDES(string key, DES des)

        {

            if (des == null)

                throw new Exception("des不能为null");

            else

                this.des = des;

            if (string.IsNullOrEmpty(key))

                throw new Exception("密钥不能为空");

            //获取支持的密钥长度

            this.supportedKeySize = new Listint(SupportedKeySize);

            // 初始化默认的key的加密方式

            this.KeyHash = SHA1.Create();

            this.StringKey = key;

        }

        #endregion

        #region public properties

        /// summary

        /// 获取或设置文本编码的方式

        /// /summary

        public Encoding encoding

        {

            set { _encoding = value == null ? Encoding.Default : value; }

            get { return _encoding; }

        }

        /// summary

        /// 通过字符串设置密钥

        /// /summary

        public string StringKey

        {

            set

            {

                if (string.IsNullOrEmpty(value))

                    throw new Exception("密钥不能为空");

                byte[] keyHash = KeyHash.ComputeHash(encoding.GetBytes(value));

                byte[] tmp = new byte[8];

                for (int i = 0; i  8; i++)

                {

                    tmp[i] = keyHash[i];

                }

                this.Key = tmp;

                for (int i = 8; i  16; i++)

                {

                    tmp[i - 8] = keyHash[i];

                }

                this.IV = tmp;

            }

        }

        /// summary

        /// 

        /// /summary

        public byte[] Key

        {

            set

            {

                if (!supportedKeySize.Contains(value.Length * 8))

                    throw new Exception("密钥长度不对");

                this.des.Key = value;

            }

            get { return this.Key; }

        }

        /// summary

        /// 设置对称加密算法的初始化向量

        /// /summary

        public byte[] IV

        {

            set

            {

                if (!supportedKeySize.Contains(value.Length * 8))

                    throw new Exception("向量长度不对");

                this.des.IV = value;

            }

            get { return this.IV; }

        }

        /// summary

        ///  获取密钥大小

        /// /summary

        public int KeySize

        {

            get { return des.KeySize; }

        }

        /// summary

        /// 获取支持的密钥大小

        /// /summary

        public KeySizes[] LegalKeySizes

        {

            get { return des.LegalKeySizes; }

        }

        /// summary

        /// 获取支持的块大小

        /// /summary

        public KeySizes[] LegalBlockSizes

        {

            get { return des.LegalBlockSizes; }

        }

        /// summary

        /// 获取支持的密钥大小

        /// /summary

        public int[] SupportedKeySize

        {

            get

            {

                Listint tmp = new Listint();

                int step = 0;

                foreach (KeySizes item in des.LegalKeySizes)

                {

                    if (item.SkipSize == 0)

                        if (item.MaxSize == item.MinSize)

                            step = item.MaxSize;

                        else

                            step = item.MaxSize - item.MinSize;

                    else

                        step = item.SkipSize;

                    for (int i = item.MinSize; i = item.MaxSize; i += step)

                    {

                        if (!tmp.Contains(i))

                            tmp.Add(i);

                    }

                }

                return tmp.ToArray();

            }

        }

        #endregion

        #region public methods

        #region 加解密字符串

        /// summary

        ///  加密字符串

        /// /summary

        /// param name="scr"/param

        /// returns/returns

        public string EncryptString(string scr)

        {

            MemoryStream ms = new MemoryStream();

            CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);

            byte[] inputByteArray = encoding.GetBytes(scr);

            cs.Write(inputByteArray, 0, inputByteArray.Length);

            cs.FlushFinalBlock();

            StringBuilder ret = new StringBuilder();

            foreach (byte b in ms.ToArray())

            {

                ret.AppendFormat("{0:X2}", b);

            }

            return ret.ToString();

        }

        /// summary

        ///  解密字符串

        /// /summary

        /// param name="scr"/param

        /// returns/returns

        public string DecryptString(string scr)

        {

            byte[] inputByteArray = new byte[scr.Length / 2];

            for (int x = 0; x  scr.Length / 2; x++)

            {

                int i = (System.Convert.ToInt32(scr.Substring(x * 2, 2), 16));

                inputByteArray[x] = (byte)i;

            }

            MemoryStream ms = new MemoryStream();

            CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);

            cs.Write(inputByteArray, 0, inputByteArray.Length);

            cs.FlushFinalBlock();

            StringBuilder ret = new StringBuilder();

            return encoding.GetString(ms.ToArray());

        }

        #endregion

        #region 加解密文件

        /// summary

        ///  加密文件

        /// /summary

        /// param name="filePath"要加密的文件位置/param

        /// param name="savePath"加密后文件保存到的位置/param

        /// returns/returns

        public bool EncryptFile(string filePath, string savePath)

        {

            FileStream fs = File.OpenRead(filePath);

            byte[] inputByteArray = new byte[fs.Length];

            fs.Read(inputByteArray, 0, (int)fs.Length);

            fs.Close();

            MemoryStream ms = new MemoryStream();

            CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);

            cs.Write(inputByteArray, 0, inputByteArray.Length);

            cs.FlushFinalBlock();

            fs = File.OpenWrite(savePath);

            foreach (byte b in ms.ToArray())

            {

                fs.WriteByte(b);

            }

            fs.Close();

            cs.Close();

            ms.Close();

            return true;

        }

        /// summary

        /// 解密文件

        /// /summary

        /// param name="filePath"要解密的文件/param

        /// param name="savePath"解密后保存到的位置/param

        /// param name="keyStr"/param

        /// returns/returns

        public bool DecryptFile(string filePath, string savePath)

        {

            FileStream fs = File.OpenRead(filePath);

            byte[] inputByteArray = new byte[fs.Length];

            fs.Read(inputByteArray, 0, (int)fs.Length);

            fs.Close();

            MemoryStream ms = new MemoryStream();

            CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);

            cs.Write(inputByteArray, 0, inputByteArray.Length);

            cs.FlushFinalBlock();

            fs = File.OpenWrite(savePath);

            foreach (byte b in ms.ToArray())

            {

                fs.WriteByte(b);

            }

            fs.Close();

            cs.Close();

            ms.Close();

            return true;

        }

        #endregion

        #endregion

    }

    #endregion

}

iOS DES加密 解密

头文件

#import CommonCrypto/CommonCryptor.h

NSString *const kInitVector = @"ffGGtsdfzxCv5568";

NSString *const DESKey = @"gg356tt8g5h6j9jh";

+ (NSString *)encodeDesWithString:(NSString *)str{

    NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding];

    size_t plainTextBufferSize = [data length];

    const void *vplainText = (const void *)[data bytes];

    CCCryptorStatus ccStatus;

    uint8_t *bufferPtr = NULL;

    size_t bufferPtrSize = 0;

    size_t movedBytes = 0;

    bufferPtrSize = (plainTextBufferSize + kCCBlockSizeDES) ~(kCCBlockSizeDES - 1);

    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));

    memset((void *)bufferPtr, 0x0, bufferPtrSize);

    const void *vkey = (const void *) [DESKey UTF8String];

    const void *vinitVec = (const void *) [kInitVector UTF8String];

    ccStatus = CCCrypt(kCCEncrypt,

                      kCCAlgorithmDES,

                      kCCOptionPKCS7Padding,

                      vkey,

                      kCCKeySizeDES,

                      vinitVec,

                      vplainText,

                      plainTextBufferSize,

                      (void *)bufferPtr,

                      bufferPtrSize,

                      movedBytes);

    NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];

    NSString *result = [myData base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];

    return result;

}

+ (NSString *)decodeDesWithString:(NSString *)str{

        NSData *encryptData = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters];

        size_t plainTextBufferSize = [encryptData length];

        const void *vplainText = [encryptData bytes];

        CCCryptorStatus ccStatus;

        uint8_t *bufferPtr = NULL;

        size_t bufferPtrSize = 0;

        size_t movedBytes = 0;

        bufferPtrSize = (plainTextBufferSize + kCCBlockSizeDES) ~(kCCBlockSizeDES - 1);

        bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));

        memset((void *)bufferPtr, 0x0, bufferPtrSize);

        const void *vkey = (const void *) [DESKey UTF8String];

        const void *vinitVec = (const void *) [kInitVector UTF8String];

        ccStatus = CCCrypt(kCCDecrypt,

                          kCCAlgorithmDES,

                          kCCOptionPKCS7Padding,

                          vkey,

                          kCCKeySizeDES,

                          vinitVec,

                          vplainText,

                          plainTextBufferSize,

                          (void *)bufferPtr,

                          bufferPtrSize,

                          movedBytes);

        NSString *result = [[NSString alloc] initWithData:[NSData dataWithBytes:(const void *)bufferPtr

                                                                        length:(NSUInteger)movedBytes] encoding:NSUTF8StringEncoding];

        return result;

}

DES 加密算法解析

第一步是用密钥初始化des

初始化的过程主要是用传入的密钥生成16对长度为48的Kn 子密钥

生成48位子密钥Kn的函数主要是 __create_sub_keys , 主要设计两个换位表pc1和pc2

key = self.__permutate(des.__pc1, self.__String_to_BitList(self.getKey())) 开始先用换位表生成56位的初始key值(同pc1表的位数)

之后划分成两部分self.L和self.R各28位,然后是一个循环16此的左移操作,最后用pc2换位表生成第一个子密钥Kn[0]

我们传入数据调用encrypt函数即可, DES.encrypt('flag{isisisikey}') 我们先来看encrypt函数

encrypt函数主要调用了crypt函数,继续跟进crypt函数,开始一部分是cbc模式获取iv的过程,这里先暂时不考虑cbc,直接看关键部分

这里就设计到分组加密的核心了,为什么DES又叫分组加密,有一操作是 block = self.__String_to_BitList(data[i:i+8]) 把加密数据每八个字节分成一个block,然后调用 __String_to_BitList 会将八字节字符转换为64bit的二进制,每个block再调用 __des_crypt 函数加密

开始几步和子密钥生成函数类似,用一个ip换位表初始化block,然后划分成self,L和self.R 各32位。

之后又是一个16轮的计算,我们分析一下每轮操作

self.R = self.__permutate(des.__expansion_table, self.R) 利用一个扩展表将32bit扩展成48位,扩展表:

B = [self.R[:6], self.R[6:12], self.R[12:18], self.R[18:24], self.R[24:30], self.R[30:36], self.R[36:42], self.R[42:]] 将48位的self.R 分成6*8为,之后一个循环就是经典的是s-box的置换操作

s-box盒一个八个,m是前后2bit,n是中间6bit, v是s-box的(n,m)处的值

self.R = self.__permutate(des.__p, Bn) 是P-box置换盒。 最后返回64bit的processed_block, 经过BitList_to_String函数处理就变成8字节的字符流了,最后把每个block分组join一块就是最后的密文。

我们再来总结一下这个过程

子密钥生成算法

des 加密算法

附上完整版des加解密算法脚本

使用des对文件加密后怎么解密

您好,一般来说在线加密工具都是网页版的,des加密需要加密前明文和加密密钥,在网页的控件上填写好对应信息之后,点击加密按钮一般就可以看到加密后的加密结果。

DES加密解密结果为何不一致?

这个问题主要涉及编码、输入格式、输出格式、加密模式这几个方面的问题,还有一些细节问题比如空格与回车。 首先是编码问题,在线的编码格式一般默认是UTF-8,因此如果网页编码不是UTF-8,则会导致加密的结果不一样。因为DES算法本质上是对二进制内容进行加密,同样的文字经过不同的编码映射成的二进制内容并不相同。 其次,是输入格式问题。一般在网页的输入是文本格式(Plain Text),但是许多教程为了方便理解,写的输入格式是16进制,比如 DES算法实例讲解 这篇文章里面主要用的是16进制格式作为讲解,对于许多在线工具,明文和密钥输入用的是文本格式。因此,在输入的时候一定要注意区分。 然后,是输出格式的问题。有些在线加密工具输出会自动进行Base64编码,这样结果和直接加密的结果完全不同。DES加密的密文是16进制格式的,无法一一对应成ASCII码。密文要么以16进制输出,要么输出一堆乱码,而Base64能将一个较长的16进制数组编码为一个字符串,方便处理。 最后,是加密模式的问题。DES本身采用的是ECB(电子密码本)模式,即将加密的数据分成若干组,每组的大小跟加密密钥长度相同,这样密文输出完全由明文和密钥决定。为了进一步加强安全性,有许多安全性扩展,就诞生了别的加密模式,比如加密块链模式CBC、加密反馈模式CFB等等。不同的模式加密结果也会完全不同。 在附带一点细节问题,即空格与回车的问题。尤其是在字符串处理的时候,有些字符串会带回车换行(0x0D 0x0A),这会造成最后一个64位字符块加密有些许差别。还有一些文本框自动(trigger)去除空格,就导致文本中的空格没有被计算在内,导致加密不同。

java的 DES 加密解密方法 求对应C#的加密解密方法,急切

/*

* @param arrB 需要转换的byte数组

* @return 转换后的字符串

* @throws Exception 本方法不处理任何异常,所有异常全部抛出

*/

public static String byteArr2HexStr(byte[] arrB) throws Exception {

int iLen = arrB.length;

// 每个byte用两个字符才能表示,所以字符串的长度是数组长度的两倍

StringBuffer sb = new StringBuffer(iLen * 2);

for (int i = 0; i iLen; i++) {

int intTmp = arrB[i];

// 把负数转换为正数

while (intTmp 0) {

intTmp = intTmp + 256;

}

// 小于0F的数需要在前面补0

if (intTmp 16) {

sb.append("0");

}

sb.append(Integer.toString(intTmp, 16));

}

return sb.toString();

}

/*

* @param strIn 需要转换的字符串

* @return 转换后的byte数组

* @throws Exception 本方法不处理任何异常,所有异常全部抛出

*/

public static byte[] hexStr2ByteArr(String strIn) throws Exception {

byte[] arrB = strIn.getBytes();

int iLen = arrB.length;

// 两个字符表示一个字节,所以字节数组长度是字符串长度除以2

byte[] arrOut = new byte[iLen / 2];

for (int i = 0; i iLen; i = i + 2) {

String strTmp = new String(arrB, i, 2);

arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);

}

return arrOut;

}

/**

* 加密字节数组

*

* @param arrB

* 需加密的字节数组

* @return 加密后的字节数组

* @throws Exception

*/

@SuppressWarnings("restriction")

private static byte[] encrypt(byte[] arrB,String keyParameter) throws Exception {

Security.addProvider(new com.sun.crypto.provider.SunJCE());

Key key = getKey(keyParameter.getBytes());

Cipher encryptCipher = Cipher.getInstance("DES");

encryptCipher.init(Cipher.ENCRYPT_MODE, key);

return encryptCipher.doFinal(arrB);

}

/**

* 加密字符串

*

* @param strIn

* 需加密的字符串

* @return 加密后的字符串

* @throws Exception

*/

public static String encrypt(String strIn,String keyParameter) throws Exception {

return HexStrByteArrUtils.byteArr2HexStr(encrypt(strIn.getBytes(PiccConfig.PICC_INPUT_CHARSET),keyParameter));

}

/**

* 解密字节数组

*

* @param arrB

* 需解密的字节数组

* @return 解密后的字节数组

* @throws Exception

*/

@SuppressWarnings("restriction")

private static byte[] decrypt(byte[] arrB,String keyParameter) throws Exception {

Security.addProvider(new com.sun.crypto.provider.SunJCE());

Key key = getKey(keyParameter.getBytes());

Cipher decryptCipher = Cipher.getInstance("DES");

decryptCipher.init(Cipher.DECRYPT_MODE, key);

return decryptCipher.doFinal(arrB);

}

/**

* 解密字符串

*

* @param strIn

* 需解密的字符串

* @return 解密后的字符串

* @throws Exception

*/

public static String decrypt(String strIn,String keyParameter) throws Exception {

return new String(decrypt(HexStrByteArrUtils.hexStr2ByteArr(strIn),keyParameter),PiccConfig.PICC_INPUT_CHARSET);

}