Vs2010 word(2013 2016) docx 加密原理 附源码

Vs2010 word(2013 2016) docx 加密原理 附源码
算法是微软官方开源的。本人只不过是代码c++实现

样例内容

用记事本、UE或notepad++ 打开docx 文档,搜索dataIntegrity即可找到。截图如下
在这里插入图片描述
文本如下:
<p:encryptedKey spinCount=“100000” saltSize=“16” blockSize=“16” keyBits=“256” hashSize=“64” cipherAlgorithm=“AES” cipherChaining=“ChainingModeCBC” hashAlgorithm=“SHA512” saltValue=“kBwW6kHn3awgc9RYRjVM1g==” encryptedVerifierHashInput=“uqgGl3gMsLmvdp4nWWugXA==” encryptedVerifierHashValue=“76HNruOUbatVN/FBy7+Ao0JsEVr2A5bkoNd3DWNeaVhu6ZPp23BNGKNms1wN40V13VL0sYIOex0nenSJVbZw2g==” encryptedKeyValue=“mBryq38L0HAyHPOE9bv6N8Ulo+lA0AygY/jHCU5FKR8=”/>

解密流程

	OpenSSL_add_all_algorithms();

	unsigned char block1[8] = {0xFE, 0xA7, 0xD2, 0x76, 0x3B, 0x4B, 0x9E, 0x79};
	unsigned char block2[8] = {0xD7, 0xAA, 0x0F, 0x6D, 0x30, 0x61, 0x34, 0x4E};

	//hash(密码 + saltValue) 
	string aaa= "";
	string saltValue = base64decode("kBwW6kHn3awgc9RYRjVM1g==");
	string h = derive_iterated_hash_from_password(aaa,saltValue,"SHA512",100000);
	
	//hash(h+block)
	string key1 = derive_encryption_key(h,block1,"SHA512",256);
	string key2 = derive_encryption_key(h,block2,"SHA512",256);
	
	//通过key1 和 aes_cbc 解密encryptedVerifierHashInput
	string encryptedVerifierHashInput = base64decode("uqgGl3gMsLmvdp4nWWugXA==");
	PrintHex((unsigned char*)encryptedVerifierHashInput.c_str(),encryptedVerifierHashInput.length());
	
	string out_text = _decrypt_aes_cbc(encryptedVerifierHashInput, key1, saltValue);
	
	//hash(VerifierHashInput)
	unsigned char hashStr[65] = {0};
	SHA512((unsigned char*)out_text.data(), out_text.size(), hashStr);
	PrintHex((unsigned char*)hashStr,64);

	//通过key2 和 aes_cbc 解密encryptedVerifierHashValue
	string encryptedVerifierHashValue = base64decode("76HNruOUbatVN/FBy7+Ao0JsEVr2A5bkoNd3DWNeaVhu6ZPp23BNGKNms1wN40V13VL0sYIOex0nenSJVbZw2g==");

	PrintHex((unsigned char*)encryptedVerifierHashValue.c_str(),encryptedVerifierHashValue.length());
	PrintHex((unsigned char*)key2.c_str(),key2.length());
	PrintHex((unsigned char*)saltValue.c_str(),saltValue.length());
	string expected_hash = _decrypt_aes_cbc(encryptedVerifierHashValue, key2, saltValue);
	PrintHex((unsigned char*)expected_hash.c_str(),expected_hash.length());
	
	//比较
	if( 0 == memcmp(hashStr,expected_hash.data(),64) )

hash(密码 + saltValue)

string derive_iterated_hash_from_password(string password, string saltValue, string hashAlgorithm, int spinValue)
{
	//NOTE: Initial round sha512(salt + password)
	//saltValue + password.encode("UTF-16LE");

	int len = 0;
	unsigned char buf[512] = {0};
	memcpy(buf,saltValue.c_str(),saltValue.length());
	len += saltValue.length();

	//memcpy(buf+len,password.c_str(),password.length());
	//len += password.length();
	wchar_t uPasswd[256] = {0};
	int uPwdLen = StringA2W(password.c_str(),password.length(),uPasswd,255);
	memcpy(buf+len,uPasswd,(uPwdLen*sizeof(wchar_t)));
	len += (uPwdLen*sizeof(wchar_t));

	unsigned char hashStr[65] = {0};
	SHA512(buf, len, hashStr);
        
    //Iteration of 0 -> spincount-1; hash = sha512(iterator + hash)
    for(int i=0; i<spinValue; i++)
	{
		memcpy(buf,&i,4);
		memcpy(buf+4,hashStr,64);
        SHA512(buf, 68, hashStr);
	}
    return string((char*)hashStr,64);
}

hash(h+block)

string derive_encryption_key(string h, unsigned char* blockKey, string hashAlgorithm, int keyBits)
{
	//h_final = hashCalc(h + blockKey)

	int len = 0;
	unsigned char buf[512] = {0};
	memcpy(buf,h.c_str(),h.length());
	len += h.length();
	
	memcpy(buf+len,blockKey,8);
	len += 8;

	unsigned char hashStr[65] = {0};
	SHA512(buf, len, hashStr);
	
	//NOTE: Needed to truncate encryption key to bitsize
    //encryption_key = h_final.digest()[: keyBits//8]

    return string((char*)hashStr,keyBits/8);
}

ase解密

string _decrypt_aes_cbc(string data, string key, string iv)
{
unsigned char _iv[100] = {0};
unsigned char _key[100] = {0};
memcpy(_key,key.c_str(),key.length());
memcpy(_iv,iv.c_str(),iv.length());

EVP_CIPHER_CTX* ectx = EVP_CIPHER_CTX_new();
const EVP_CIPHER * cipher = EVP_get_cipherbyname("aes-256-cbc");
EVP_CipherInit_ex(ectx, cipher, NULL, _key, _iv, 0);
EVP_CIPHER_CTX_set_padding(ectx, 0);

int in_len = data.length();
unsigned char* in = (unsigned char*)data.c_str();
unsigned char* out = new unsigned char[data.length()+32];

int nTotal = 0;
int nDecryptLen = 0;
EVP_CipherUpdate(ectx, out, &nDecryptLen, in, in_len);
nTotal = nDecryptLen;
EVP_CipherFinal_ex(ectx, out + nDecryptLen, &nDecryptLen);
nTotal += nDecryptLen;
EVP_CIPHER_CTX_free(ectx);

string retstr;
retstr.assign(nTotal,0);
memcpy((void*)retstr.c_str(),out,nTotal);
return retstr;

}

参考内容

https://learn.microsoft.com/en-us/openspecs/office_file_formats/ms-offcrypto/a57cb947-554f-4e5e-b150-3f2978225e92

msoffcrypto-tool

源码

https://download.csdn.net/download/wzwwql/87732077

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_森罗万象_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值