首页 > 其他分享 >文件目录加密方法

文件目录加密方法

时间:2023-10-15 20:57:23浏览次数:37  
标签:加密 16 方法 iv Length cipher 文件目录 byte data

文件目录加密指的是通过加密方法加密目录名称,但保留目录结构,通过加密的目录保存加密文件,进而保持整个目录的保密性。

由于目录的特别,加密的方法需要满足以下要求:

1,加密后的密文尽可能短,从而能加密较深的目录结构

2,加密后的密文要能保持差异性,即目录名称间较小的差异,能产生较大的密文差异,从而无法通过密文还推断相近的明文特征

3,加密方法尽可能简单,最好只依赖原始目录结构

常用的加密模式如ECB,CBC等无法满足上述要求,这两种模式下,密文要求16字节对齐,使得密文通常比密文长很多,而且CBC模式需要初始化向量IV,需要专门的文件或目录来存储。

EME,CTR等加密模式能实现密文长度跟明文长度一样,但是EME模式需要初始化向量IV,需要专门的文件或目录存储该IV;而CTR模式由于异或操作的特性,使得相似的明文加密后生成相似的密文,只要破解部分文件名,便能容易的破解相似的文件名。

 

传统CBC模式虽然需要16字节对齐,但是可以通过密文偷窃算法(Cipher Text Steal)实现>16字节的明文生成一致长度的密文,同时,当密文>16字节时,通过使用16字节后的数据哈希值作为IV,可能避免专门的IV存储,哈希函数只用HMAC提高安全性。

而当明文<=16字节时,使用简单的ECB模式加密。

 

加密代码:

public byte[] encrypt(byte[] data)
        {
            if (data.Length < 16)
                return ecbPadEnc.TransformFinalBlock(data, 0, data.Length);
            else if (data.Length == 16)
                return ecbEnc.transform(data, new byte[17]);

            var cipher = new byte[data.Length + 1];
            var iv = hmac.ComputeHash(data, 16, data.Length - 16).head(16);

            // no need steal cipher
            if (data.Length % 16 == 0)
                return cbcEnc(iv, data, 0, data.Length, cipher, 0);

            // transform N-1 CBC block
            var lastPos = 16 * (data.Length / 16);
            cbcEnc(iv, data, 0, lastPos, cipher, 0);

            // steal cipher text for padding
            var lastSize = data.Length - lastPos;
            var stealPos = lastPos - 16 + lastSize;
            Buffer.BlockCopy(cipher, stealPos, data, data.Length - 16, 16 - lastSize);
            ecbEnc.TransformBlock(data, data.Length - 16, 16, cipher, cipher.Length - 17);

            return cipher;
        }

解密代码:

public byte[] decrypt(byte[] cipher)
        {
            if (cipher.Length == 16)
                return ecbPadDec.TransformFinalBlock(cipher, 0, cipher.Length);
            else if (cipher.Length == 17)
                return ecbDec.transform(cipher, 0, 16, new byte[16]);

            var data = new byte[cipher.Length - 1];
            // last steal block
            if (data.Length % 16 != 0)
            {
                ecbDec.TransformBlock(cipher, cipher.Length - 17, 16, data, data.Length - 16);
                // pay back the steal cipher
                Buffer.BlockCopy(data, data.Length - 16, cipher, cipher.Length - 17, 16);
            }
            // middle normal cbc chain
            var middleCount = data.Length / 16 - 1;
            if (middleCount > 0)
                cbcDec(cipher.head(16), cipher, 16, middleCount * 16, data, 16);
            // first block
            var iv = hmac.ComputeHash(data, 16, data.Length - 16).head(16);
            cbcDec(iv, cipher, 0, 16, data, 0);

            return data;
        }

需要注意,当明文为15和16字节时,ECB加密都生成16字节密文,产生混淆,所以实际加密时,当明文长度N>=16字节时,生成的密文长度M=N+1,密文末尾添加字节0x00,便于解密时识别明文长度。

完整代码 HmacIvCbc.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using util.ext;

namespace util.crypt
{
    public class HmacIvCbc : IDisposable
    {
        Aes aes;
        HMACSHA256 hmac;
        ICryptoTransform ecbEnc;
        ICryptoTransform ecbDec;
        ICryptoTransform ecbPadEnc;
        ICryptoTransform ecbPadDec;

        public HmacIvCbc(byte[] key)
        {
            init(key.head(key.Length / 2), key.tail(key.Length / 2));
        }

        public HmacIvCbc(byte[] encKey, byte[] macKey)
        {
            init(encKey, macKey);
        }

        void init(byte[] encKey, byte[] macKey)
        {
            aes = Aes.Create();
            aes.Key = encKey;

            hmac = new HMACSHA256(macKey);
            ecbEnc = getEncoder(CipherMode.ECB);
            ecbPadEnc = getEncoder(CipherMode.ECB, null, PaddingMode.PKCS7);
            ecbDec = getDecoder(CipherMode.ECB);
            ecbPadDec = getDecoder(CipherMode.ECB, null, PaddingMode.PKCS7);
        }

        ICryptoTransform getEncoder(CipherMode mode, byte[] iv = null, PaddingMode pad = PaddingMode.None)
        {
            aes.Mode = mode;
            aes.Padding = pad;
            if (null != iv)
                aes.IV = iv;
            return aes.CreateEncryptor();
        }

        byte[] cbcEnc(byte[] iv, byte[] src, int srcPos, int count, byte[] dst, int dstPos)
        {
            using (var enc = getEncoder(CipherMode.CBC, iv))
            {
                enc.TransformBlock(src, srcPos, count, dst, dstPos);
            }
            return dst;
        }

        ICryptoTransform getDecoder(CipherMode mode, byte[] iv = null, PaddingMode pad = PaddingMode.None)
        {
            aes.Mode = mode;
            aes.Padding = pad;
            if (null != iv)
                aes.IV = iv;
            return aes.CreateDecryptor();
        }

        byte[] cbcDec(byte[] iv, byte[] src, int srcPos, int count, byte[] dst, int dstPos)
        {
            using (var enc = getDecoder(CipherMode.CBC, iv))
            {
                enc.TransformBlock(src, srcPos, count, dst, dstPos);
            }
            return dst;
        }

        public byte[] encrypt(byte[] data)
        {
            if (data.Length < 16)
                return ecbPadEnc.TransformFinalBlock(data, 0, data.Length);
            else if (data.Length == 16)
                return ecbEnc.transform(data, new byte[17]);

            var cipher = new byte[data.Length + 1];
            var iv = hmac.ComputeHash(data, 16, data.Length - 16).head(16);

            // no need steal cipher
            if (data.Length % 16 == 0)
                return cbcEnc(iv, data, 0, data.Length, cipher, 0);

            // transform N-1 CBC block
            var lastPos = 16 * (data.Length / 16);
            cbcEnc(iv, data, 0, lastPos, cipher, 0);

            // steal cipher text for padding
            var lastSize = data.Length - lastPos;
            var stealPos = lastPos - 16 + lastSize;
            Buffer.BlockCopy(cipher, stealPos, data, data.Length - 16, 16 - lastSize);
            ecbEnc.TransformBlock(data, data.Length - 16, 16, cipher, cipher.Length - 17);

            return cipher;
        }

        public byte[] decrypt(byte[] cipher)
        {
            if (cipher.Length == 16)
                return ecbPadDec.TransformFinalBlock(cipher, 0, cipher.Length);
            else if (cipher.Length == 17)
                return ecbDec.transform(cipher, 0, 16, new byte[16]);

            var data = new byte[cipher.Length - 1];
            // last steal block
            if (data.Length % 16 != 0)
            {
                ecbDec.TransformBlock(cipher, cipher.Length - 17, 16, data, data.Length - 16);
                // pay back the steal cipher
                Buffer.BlockCopy(data, data.Length - 16, cipher, cipher.Length - 17, 16);
            }
            // middle normal cbc chain
            var middleCount = data.Length / 16 - 1;
            if (middleCount > 0)
                cbcDec(cipher.head(16), cipher, 16, middleCount * 16, data, 16);
            // first block
            var iv = hmac.ComputeHash(data, 16, data.Length - 16).head(16);
            cbcDec(iv, cipher, 0, 16, data, 0);

            return data;
        }

        public void Dispose()
        {
            ecbEnc?.Dispose();
            ecbDec?.Dispose();
            ecbPadEnc?.Dispose();
            ecbPadDec?.Dispose();
            aes?.Dispose();
            hmac?.Dispose();
        }
    }
}
View Code

Github链接:

https://github.com/bsmith-zhao/vfs/blob/main/util/crypt/HmacIvCbc.cs

标签:加密,16,方法,iv,Length,cipher,文件目录,byte,data
From: https://www.cnblogs.com/bsmith/p/17766157.html

相关文章

  • win11清理磁盘空间方法
    win11清理磁盘空间的方法:1、首先,按键盘上的Win键,或点击任务栏上的开始菜单,再选择已固定应用下的设置。2、当前路径为:系统》存储,可以看到各部分空间的占用情况,存储管理下,可以将存储感知(自动释放空间,删除临时文件,并管理本地可用的云内容)打开。3、......
  • 文件目录
       ......
  • access MD5加密
    PrivateConstBITS_TO_A_BYTE=8PrivateConstBYTES_TO_A_WORD=4PrivateConstBITS_TO_A_WORD=32Privatem_lOnBits(30)Privatem_l2Power(30)PrivateFunctionLShift(lValue,iShiftBits)IfiShiftBits=0ThenLShift=lValueExitFunction......
  • 判断二分图的方法
    题目描述:龙龙得知2020年中国将有2000万至4000万男人娶不到老婆后。他打算好好调查一下是不是人们的感情出现问题。他对n个人进行调查,得到m条信息,每条信息表示为某两人曾经是情侣。由于他不知道这些人的性别,请你帮他判断一下,有没有同性是情侣的情况?对于100%的数据,n的范围[2,100000......
  • Java拾贝第二天——方法
    Java拾贝不建议作为0基础学习,都是本人想到什么写什么方法方法就是一段可以重复调用的代码。方法也称函数无参方法无参方法其格式为:访问修饰符static返回值类型方法名(){//方法体[return返回值];}一个常规的Java代码结构应该如下:package包名;publicclass类名{......
  • 设置Debian系统的root登陆的方法
    设置Debian系统的root登陆的方法kyyxxk于2023-05-1510:05:48发布阅读量1.2k 收藏 2点赞数1文章标签: debian linux 运维版权Debian桌面环境默认不允许root登录,所以需要修改配置。一、让Debian可以使用root登录1)首先修改gdm3的设定文件(/etc/gdm3/dae......
  • 探秘Java语言中子类调用父类的构造方法的方式
    父类的构造方法不能被子类继承。假定Base父类有以下构造方法:publicBase(Srtingmsg){this.msg=msg;}以下Sub类继承了Base类:publicclassSubextendsBase{}以上Sub类有一个隐含的默认构造方法,形式如下:publicSub(){}尽管在Base父类中定义了如下形式的构造方法:publicBase(Str......
  • 记录Orcad中报错和解决方法
    本章目的:使用Orcad画原理图总会遇到奇怪的报错,故整理总结 1、根本原因:有元器件没有编号;更新一下位号解决。提示➤ERROR(ORNET-1048):Designisnotannotated.ERROR(ORNET-1006): Netlist failed or may be unusable. 2、根本原因:DesignCache右键CleanupCache,和......
  • 核方法(kernel method)的主要思想
    本文对核方法(kernelmethod)进行简要的介绍(https://www.jianshu.com/p/8e2649a435c4)。核方法的主要思想是基于这样一个假设:“在低维空间中不能线性分割的点集,通过转化为高维空间中的点集时,很有可能变为线性可分的”,例如下图   左图的两类数据要想在一维空间上线性分开......
  • sqlServer查询字段位数不够补0方法
    1.查询字段为字符串函数:RIGHT('0000'+字符串,n)即:从右侧截取字符串,n代表侧截取的位数实例:SELECTRIGHT('0000'+'66',3)//结果:066实例:SELECTRIGHT('0000'+'66',4)//结果:00662.查询字段非字符串......