您的位置:首页 > 其它

如何生成/读取带有密码的Office Excel 2003(Biff8格式)(非破解)

2011-02-22 11:36 627 查看
前言



对于这篇文章有兴趣的朋友可以先下载三份文档,和一个小工具。文档名称为

[MS-XLS](

介绍

Biff8格式

)

[MS-OFFCRYPTO](

介绍

Office加密

)

以及

[Applied Cryptography]

by Bruce Schneier(介绍一些加密算法,这里主要用到第

17章的

RC4流加密算法)。小工具名为

BiffView++,功能是可以查看

Excel2003文档的

Biff8格式。

正文



看过微软公开的

office文档格式的人应该知道,

Excel 2003是使用

Biff8的格式来生成的文件(

Excel
2007是

OpenXML),这篇文章是介绍对于如何通过

Biff8格式生成以及如何读取一个带有密码的

Excel文档。有兴趣的朋友可以先简单浏览一下

Biff8,了解其格式内容(参考文档

[MS-XLS])。

目前比较知名的对于

Excel Biff8格式操作的软件有:

·

NPOI—读、写

·

Spread(

FarPoint)—读、写

·

ActiveReports —支持其报表的

Excel导出

·

……

但以上软件似乎都并未实现加密的

Excel文件的读取与生成

。我在工作中正好需要用到这一块,所以研究学习了一下,现在将得到的成果与大家分享一下。

一、FilePass记录

研究过

Biff8格式的人都知道,它是以一条一条记录

(record)的形式保存,一条记录包括

Header(record
ID与

record
length)与内容。假如需要生成一份带有打开密码的

Excel文档,需要添加一条名为

FilePass

的记录,该条记录的内容由以下字段组成:

wEncryptionType (2 bytes)

:Boolean类型,指定加密类型,0x0000为XOR混淆,0x0001为RC4加密。现在多用RC4加密。

encryptionInfo (可变长度):

加密信息,具体的内容取决于

wEncryptionType

的值。此处只讨论RC4加密。

RC4加密的具体内容可以参考文档[MS-OFFCRYPTO]

,可以使用的加密算法有两种:RC4标准加密与CryptoAPI RC4加密。具体应该使用哪一种加密算法呢?这里就可以用到前言中介绍的工具BiffView++,先使用Office Excel生成一个带有密码的文档,在保存时的Tools->General Options...->Password to open设置一个密码然后保存。使用BiffView++查看保存的文档,可以发现FilePass

记录,如下:

BIFF FILEPASS

(2Fh)
54
01 00 01 00 01 00 75 E1 D8 96 5A CC D0 96 F7 5E

1E 14 FC 93 2E 61 6B F3 C2 42 72 48 99 37 29 A8

21 28 B5 6D 84 CF A2 10 95 55 E5 3C 67 1A C6 9F

DA F4 A4 19 35 6A

其中2Fh为FilePass的记录ID,54为长度,后面的一串16进制数据为内容,之前我们介绍FilePass的前两个byte表示加密类型,可以看到这里是01 00,代表RC4加密,接下来的两个byte同样是01 00,参考[MS-XLS]文档的FilePass记录可以发现,0x0001表示RC4标准加密,而CryptoAPI rc4加密则必须是0x0002或0x0003,所以我们可以知道,接下来要研究的是RC4标准加密。

二、RC4流加密算法

在介绍Office RC4加密信息之前,我们先要学习一下RC4加密算法,这是一个非常简单的流加密算法,参考

[Applied Cryptography]

,先简单介绍一下,然后给出算法的核心代码:
RC4算法包括初始化算法(KSA)和伪随机子密码生成算法(PRGA)两大部分。

初始化算法:

生成线性的S-BOX,生成256长度的由密钥重复填充的数组,计数器j重置为0然后
for i = 0 to 255:

j = (j + Si + Ki) mod 256

swap Si and Sj
伪随机子密码生成算法:

i = (i + 1) mod 256

j = (j + Si) mod 256

swap Si and Sj

t = (Si + Sj) mod 256

K = St

其中K是与明文异或后得到密文,或者与密文异或得到明文(对称算法,所以加密与解密可以为同一个函数)

以下为算法的核心代码(c#):
public class RC4
{
private int count_i, count_j;
private const int S_BOX_LENGTH = 256;
private byte[] s_box = new byte[S_BOX_LENGTH];
public void SetKey(byte[] key)
{
count_i = 0;
count_j = 0;
byte[] k = new byte[S_BOX_LENGTH];
int key_len = key.Length;
for (int i = 0; i < S_BOX_LENGTH; i++)
{
s_box[i] = (byte)i;
k[i] = key[i % key_len];
}
int j = 0;
for (int i = 0; i < S_BOX_LENGTH; i++)
{
unchecked
{
j = (byte)(j + s_box[i] + k[i]) & 255;
}
byte t = s_box[i];
s_box[i] = s_box[j];
s_box[j] = t;
}
}
public byte[] De_Encrypt(byte[] input)
{
if (input == null || input.Length <= 0) return null;
int x = count_i;
int y = count_j;
byte[] output = new byte[input.Length];
for (int index = 0; index < input.Length; index++)
{
x = (x + 1) & 255;
y = (y + s_box[x]) & 255;
byte t = s_box[x];
s_box[x] = s_box[y];
s_box[y] = t;
int tmp = (s_box[x] + s_box[y]) & 0xFF;
output[index] = (byte)(input[index] ^ s_box[tmp]);
}
count_i = x;
count_j = y;
return output;
}
}


三、Office二进制文档RC4加密

现在我们可以看一下RC4标准加密信息由什么组成:

EncryptionVersionInfo (4 bytes):

加密版本信息,分为主要和次要,各占两个byte,这里必须为0x0001与0x0001(我也不知道为什么)。

Salt (16 bytes):

一个随机生成,长度为16的bytes数组,用于生成RC4加密算法的密钥。不能与EncryptedVerifier

字段相同

EncryptedVerifier (16 bytes):

密码验证器,生成方式与工作原理容后再叙。

EncryptedVerifierHash (16 bytes):

验证器MD5 Hash

,生成方式与工作原理容后再叙。

要进行RC4加密,我们首先需要有密钥,那么密钥是如何生成的呢?

将密码以Unicode编码转化成Byte数组,然后进行MD5 hash

随机生成一个长度为16的byte数组Salt(与RC4加密信息的Salt字段对应)

取第一步结果的前5位与Salt连接,生成一个长度为21的byte数组

将第三步21位的数组重复连接16次,得到一个336位的byte数组(21*16=336)

将第四步的结果进行MD5 Hash,并取前5位与block

*(4 bytes)连接成一个长度为9的byte数组

将第五步的结果进行MD5 Hash得到一个16位的数组,即为密钥。

*block

:32-bit的无符整型,在密码验证时与Verifier生成时皆为0x00000000,在进行Biff8流加密时,每加密1024个字节的流就自增1,同时重新获取密钥,重置RC4的i,j计数器。

密码验证器EncryptedVerifier的生成与工作原理:

一份带有FilePass记录的Excel文档是如何验证用户输入的密码是否正确的呢?知道这个问题的答案后,我们也可以了解如何生成FilePass记录了。

首先,在得到用户输入的密码以后,使用上面介绍的方法生成密钥(block为0x00000000)

使用RC4算法,解密EncryptedVerifier

EncryptedVerifierHash

使用MD5 Hash计算解密后的EncryptedVerifier

第3步得到的结果,与解密后的EncryptedVerifierHash值进行比较,若完全一样,则密码正确,否则,密码验证失败。

知道了密码验证的工作原理以后,由于RC4加密的对称性(明文加密可以得到密文,密文再加密后就是明文),我们可以反向推导验证器的生成:

生成密钥(这一步是毫无疑问的)

随机生成一个16长度的byte数组,用RC4加密,得到的结果作为EncryptedVerifier

写入FilePass



第三步随机生成的16长度的数组(未加密时)进行MD5 Hash,再进行RC4加密,得到的结果作为EncryptedVerifierHash

写入FilePass



这样,一条FilePass记录就生成了,如果已经完成了Excel其他记录的生成,可以尝试导出一份带有密码的Excel文档,打开后如果FilePass正确生成,Excel应用程序会提示你输入密码。那么这个时候输入正确的密码以后,Excel会显示你导出内容吗,例如我导出了一张图片,这张图片会得到正确的显示吗?

自然Excel加密没有这么简单,那么接下来我们应该做的是什么:

在生成FilePass记录时的密钥我们需要保留下来。

将需要生成文件的流从Workbook的头开始,进行加密。

加密时有几点需要注意的地方

,1)
计数器count_i与count_j在每次加密时保留;2)block的值需要每1024个字节进行自增,自增的同时重置计数器count_i与
count_j为0。3)有些记录不需要加密
(BOF,FilePass,UsrExcl,FileLock,InterfaceHdr,RRDInfo,RRDHead,另外
BoundSheet8的lbPlyPos字段不需要加密),这里不需要加密是指不将加密后的密文,写入文件流,但是加密方法要执行,因为RC4加密算法
的结果与流的位置有关系。4)记录的ID与长度不需要加密,同3)。

将加密后的流写入文件,保存一下,如果代码正确的话,Excel文档就可以正确的显示了。

加密的Excel文档的读取:

首先要持有文档的密码(本文并不是破解加密)

根据密码与FilePass中的Salt生成密钥,block为0x00000000

逐条读取记录的文件流,并使用RC4解密

解密需要注意的地方与加密相同。

解密后得到的记录即为原始记录,可以自行根据标准文档进行解析。

结束语

文章到此就结束了,虽然标准文档中以上提到的内容都存在,但是有几个原因促使我写下这篇文章:

标准文档都是英文,理解会有误差

有些细节仅仅看文档还不能一次写成功,需要试验,所以将我的试验结果分享出来,方便有这方面兴趣的朋友少走弯路

希望帮助推广一下这类对Office文件操作的方法,优点:速度快、低依赖性、高可控制性;缺点:复杂的文档解析工作

出于各种原因,如果您对文章有疑问,或者发现我的bug,请告知,谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: