mirror of
https://github.com/jmcnamara/libxlsxwriter
synced 2025-03-28 21:13:14 +00:00
Fix worksheet password hashing algorithm for long passwords.
Replace/fix the worksheet protection password algorithm so that is works correctly for strings over 24 chars.
This commit is contained in:
parent
1b7e99a7eb
commit
d3efbdbbfe
@ -633,32 +633,27 @@ lxw_version_id(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash a worksheet password. Based on the algorithm provided by Daniel Rentz
|
||||
* of OpenOffice.
|
||||
* Hash a worksheet password. Based on the algorithm in ECMA-376-4:2016,
|
||||
* Office Open XML File Formats - Transitional Migration Features,
|
||||
* Additional attributes for workbookProtection element (Part 1, §18.2.29).
|
||||
*/
|
||||
uint16_t
|
||||
lxw_hash_password(const char *password)
|
||||
{
|
||||
size_t count;
|
||||
size_t i;
|
||||
uint16_t hash = 0x0000;
|
||||
uint16_t byte_count = strlen(password);
|
||||
uint16_t hash = 0;
|
||||
const char *p = &password[byte_count];
|
||||
|
||||
count = strlen(password);
|
||||
if (!byte_count)
|
||||
return hash;
|
||||
|
||||
for (i = 0; i < (uint8_t) count; i++) {
|
||||
uint32_t low_15;
|
||||
uint32_t high_15;
|
||||
uint32_t letter = password[i] << (i + 1);
|
||||
|
||||
low_15 = letter & 0x7fff;
|
||||
high_15 = letter & (0x7fff << 15);
|
||||
high_15 = high_15 >> 15;
|
||||
letter = low_15 | high_15;
|
||||
|
||||
hash ^= letter;
|
||||
while (p-- != password) {
|
||||
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
|
||||
hash ^= *p & 0xFF;
|
||||
}
|
||||
|
||||
hash ^= count;
|
||||
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff);
|
||||
hash ^= byte_count;
|
||||
hash ^= 0xCE4B;
|
||||
|
||||
return hash;
|
||||
|
46
test/unit/utility/test_hash_password.c
Normal file
46
test/unit/utility/test_hash_password.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Tests for the libxlsxwriter library.
|
||||
*
|
||||
* Copyright 2014-2022, John McNamara, jmcnamara@cpan.org
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../ctest.h"
|
||||
#include "../helper.h"
|
||||
|
||||
#include "../../../include/xlsxwriter/utility.h"
|
||||
|
||||
|
||||
// Test lxw_hash_password().
|
||||
CTEST(utility, lxw_hash_password) {
|
||||
|
||||
ASSERT_EQUAL(0x83AF, lxw_hash_password("password"));
|
||||
ASSERT_EQUAL(0xD14E, lxw_hash_password("This is a longer phrase"));
|
||||
ASSERT_EQUAL(0xCE2A, lxw_hash_password("0"));
|
||||
ASSERT_EQUAL(0xCEED, lxw_hash_password("01"));
|
||||
ASSERT_EQUAL(0xCF7C, lxw_hash_password("012"));
|
||||
ASSERT_EQUAL(0xCC4B, lxw_hash_password("0123"));
|
||||
ASSERT_EQUAL(0xCACA, lxw_hash_password("01234"));
|
||||
ASSERT_EQUAL(0xC789, lxw_hash_password("012345"));
|
||||
ASSERT_EQUAL(0xDC88, lxw_hash_password("0123456"));
|
||||
ASSERT_EQUAL(0xEB87, lxw_hash_password("01234567"));
|
||||
ASSERT_EQUAL(0x9B86, lxw_hash_password("012345678"));
|
||||
ASSERT_EQUAL(0xFF84, lxw_hash_password("0123456789"));
|
||||
ASSERT_EQUAL(0xFF86, lxw_hash_password("01234567890"));
|
||||
ASSERT_EQUAL(0xEF87, lxw_hash_password("012345678901"));
|
||||
ASSERT_EQUAL(0xAF8A, lxw_hash_password("0123456789012"));
|
||||
ASSERT_EQUAL(0xEF90, lxw_hash_password("01234567890123"));
|
||||
ASSERT_EQUAL(0xEFA5, lxw_hash_password("012345678901234"));
|
||||
ASSERT_EQUAL(0xEFD0, lxw_hash_password("0123456789012345"));
|
||||
ASSERT_EQUAL(0xEF09, lxw_hash_password("01234567890123456"));
|
||||
ASSERT_EQUAL(0xEEB2, lxw_hash_password("012345678901234567"));
|
||||
ASSERT_EQUAL(0xED33, lxw_hash_password("0123456789012345678"));
|
||||
ASSERT_EQUAL(0xEA14, lxw_hash_password("01234567890123456789"));
|
||||
ASSERT_EQUAL(0xE615, lxw_hash_password("012345678901234567890"));
|
||||
ASSERT_EQUAL(0xFE96, lxw_hash_password("0123456789012345678901"));
|
||||
ASSERT_EQUAL(0xCC97, lxw_hash_password("01234567890123456789012"));
|
||||
ASSERT_EQUAL(0xAA98, lxw_hash_password("012345678901234567890123"));
|
||||
ASSERT_EQUAL(0xFA98, lxw_hash_password("0123456789012345678901234"));
|
||||
ASSERT_EQUAL(0xD298, lxw_hash_password("01234567890123456789012345"));
|
||||
ASSERT_EQUAL(0xD2D3, lxw_hash_password("0123456789012345678901234567890"));
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user