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