22#include <osl/diagnose.h>
30#include <com/sun/star/beans/NamedValue.hpp>
33#define DEBUG_MSO_ENCRYPTION_STD97 0
35#if DEBUG_MSO_ENCRYPTION_STD97
47template<
typename Type >
48void lclRotateLeft(
Type& rnValue,
int nBits )
52 sal::static_int_cast< unsigned int >(nBits) <
sizeof(
Type ) * 8 );
53 rnValue =
static_cast< Type >( (rnValue << nBits) | (rnValue >> (
sizeof(
Type ) * 8 - nBits)) );
57template<
typename Type >
60 OSL_ASSERT( (nBits < nWidth) && (nWidth <
sizeof(
Type ) * 8) );
61 Type nMask =
static_cast< Type >( (1UL << nWidth) - 1 );
62 rnValue =
static_cast< Type >(
63 ((rnValue << nBits) | ((rnValue & nMask) >> (nWidth - nBits))) & nMask );
66std::size_t lclGetLen(
const sal_uInt8* pnPassData, std::size_t nBufferSize )
69 while( (nLen < nBufferSize) && pnPassData[ nLen ] ) ++nLen;
73sal_uInt16 lclGetKey(
const sal_uInt8* pnPassData, std::size_t nBufferSize )
75 std::size_t nLen = lclGetLen( pnPassData, nBufferSize );
79 sal_uInt16 nKeyBase = 0x8000;
80 sal_uInt16 nKeyEnd = 0xFFFF;
81 const sal_uInt8* pnChar = pnPassData + nLen - 1;
87 lclRotateLeft( nKeyBase, 1 );
88 if( nKeyBase & 1 ) nKeyBase ^= 0x1020;
89 if( cChar & 1 ) nKey ^= nKeyBase;
91 lclRotateLeft( nKeyEnd, 1 );
92 if( nKeyEnd & 1 ) nKeyEnd ^= 0x1020;
95 return nKey ^ nKeyEnd;
98sal_uInt16 lclGetHash(
const sal_uInt8* pnPassData, std::size_t nBufferSize )
100 std::size_t nLen = lclGetLen( pnPassData, nBufferSize );
102 sal_uInt16 nHash =
static_cast< sal_uInt16
>( nLen );
109 sal_uInt16 cChar = *pnChar;
111 lclRotateLeft( cChar, nRot, 15 );
125 mnRotateDistance( nRotateDistance )
137 mnKey = lclGetKey( pnPassData, 16 );
138 mnHash = lclGetHash( pnPassData, 16 );
140 memcpy(
mpnKey, pnPassData, 16 );
144 0xBB, 0xFF, 0xFF, 0xBA,
145 0xFF, 0xFF, 0xB9, 0x80,
146 0x00, 0xBE, 0x0F, 0x00,
147 0xBF, 0x0F, 0x00, 0x00
150 std::size_t nLen = lclGetLen( pnPassData, 16 );
151 const sal_uInt8* pnFillChar = spnFillChars;
156 ShortToSVBT16(
mnKey, pnOrigKey );
160 *pnKeyChar ^= pnOrigKey[
nIndex & 0x01 ];
167 bool bResult =
false;
170 uno::Sequence< sal_Int8 > aKey = aHashData.
getUnpackedValueOrDefault(
"XOR95EncryptionKey", uno::Sequence< sal_Int8 >() );
172 if ( aKey.getLength() == 16 )
174 memcpy(
mpnKey, aKey.getConstArray(), 16 );
181 OSL_FAIL(
"Unexpected key size!" );
190 aHashData[ OUString(
"XOR95EncryptionKey" ) ] <<= uno::Sequence<sal_Int8>(
reinterpret_cast<sal_Int8*
>(
mpnKey), 16 );
191 aHashData[ OUString(
"XOR95BaseKey" ) ] <<=
static_cast<sal_Int16
>(
mnKey);
192 aHashData[ OUString(
"XOR95PasswordHash" ) ] <<=
static_cast<sal_Int16
>(
mnHash);
212 for(
const sal_uInt8* pnDataEnd = pnData + nBytes; pnData < pnDataEnd; ++pnData )
214 lclRotateLeft( *pnData, 3 );
215 *pnData ^= *pnCurrKey;
216 if( pnCurrKey < pnKeyLast ) ++pnCurrKey;
else pnCurrKey =
mpnKey;
228 for(
const sal_uInt8* pnDataEnd = pnData + nBytes; pnData < pnDataEnd; ++pnData )
230 const sal_uInt8 cChar = *pnData ^ *pnCurrKey;
231 if (*pnData && cChar)
234 if( pnCurrKey < pnKeyLast )
251 : m_sEncKeyName(
std::move(aEncKeyName))
252 , m_nHashLen(nHashLen)
253 , m_hCipher(rtl_cipher_create(rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream))
255 , m_aDigestValue(nHashLen, 0)
261 :
MSCodec97(RTL_DIGEST_LENGTH_MD5,
"STD97EncryptionKey")
263 m_hDigest = rtl_digest_create(rtl_Digest_AlgorithmMD5);
268 :
MSCodec97(RTL_DIGEST_LENGTH_SHA1,
"CryptoAPIEncryptionKey")
284#if DEBUG_MSO_ENCRYPTION_STD97
287 printf(
"digest: (%s)\n", msg);
288 for (
int i = 0;
i < 16; ++
i)
289 printf(
"%2.2x ", pDigest[
i]);
300#if DEBUG_MSO_ENCRYPTION_STD97
301 fprintf(stdout,
"MSCodec_Std97::InitCodec: --begin\n");fflush(stdout);
303 bool bResult =
false;
307 const size_t nKeyLen = aKey.getLength();
312 uno::Sequence< sal_Int8 > aUniqueID = aHashData.
getUnpackedValueOrDefault(
"STD97UniqueID", uno::Sequence< sal_Int8 >() );
313 if ( aUniqueID.getLength() == 16 )
315 assert(
m_aDocId.size() ==
static_cast<size_t>(aUniqueID.getLength()));
322 OSL_FAIL(
"Unexpected document ID!" );
325 OSL_FAIL(
"Unexpected key size!" );
335 aHashData[ OUString(
"STD97UniqueID" ) ] <<= uno::Sequence< sal_Int8 >(
reinterpret_cast<sal_Int8*
>(
m_aDocId.data()),
m_aDocId.size() );
341 const sal_uInt16 pPassData[16],
344#if DEBUG_MSO_ENCRYPTION_STD97
345 fprintf(stdout,
"MSCodec_Std97::InitKey: --begin\n");fflush(stdout);
350 const size_t nKeyLen = aKey.getLength();
358 memcpy (
m_aDocId.data(), pDocId, 16);
364 const sal_uInt16 pPassData[16],
367 sal_uInt32
const saltSize = 16;
370 std::vector<sal_uInt8> initialData(pDocId, pDocId + saltSize);
373 for (sal_Int32 nInd = 0; nInd < 16 && pPassData[nInd]; ++nInd)
375 initialData.push_back(sal::static_int_cast<sal_uInt8>((pPassData[nInd] >> 0) & 0xff));
376 initialData.push_back(sal::static_int_cast<sal_uInt8>((pPassData[nInd] >> 8) & 0xff));
381 initialData.data(), initialData.size(),
382 ::comphelper::HashType::SHA1));
387 memcpy(
m_aDocId.data(), pDocId, 16);
399#if DEBUG_MSO_ENCRYPTION_STD97
400 fprintf(stdout,
"MSCodec97::VerifyKey: \n");
420 rtl_secureZeroMemory(aDigest.data(),
m_nHashLen);
428 std::vector<sal_uInt8> verifier(16);
430 pSaltData, 16, verifier.data(), verifier.size());
433 verifier.data(), verifier.size(), ::comphelper::HashType::SHA1));
434 ::std::copy(sha1.begin(), sha1.end(), pDigest);
445 pKeyData[ 5] =
sal_uInt8((nCounter >> 0) & 0xff);
446 pKeyData[ 6] =
sal_uInt8((nCounter >> 8) & 0xff);
447 pKeyData[ 7] =
sal_uInt8((nCounter >> 16) & 0xff);
448 pKeyData[ 8] =
sal_uInt8((nCounter >> 24) & 0xff);
454 (void)rtl_digest_updateMD5 (
456 (void)rtl_digest_rawMD5 (
457 m_hDigest, pKeyData, RTL_DIGEST_LENGTH_MD5);
460 rtlCipherError
result = rtl_cipher_init (
462 pKeyData, RTL_DIGEST_LENGTH_MD5,
nullptr, 0);
465 rtl_secureZeroMemory (pKeyData,
sizeof(pKeyData));
467 return (
result == rtl_Cipher_E_None);
474 aKeyData.push_back(
sal_uInt8((nCounter >> 0) & 0xff));
475 aKeyData.push_back(
sal_uInt8((nCounter >> 8) & 0xff));
476 aKeyData.push_back(
sal_uInt8((nCounter >> 16) & 0xff));
477 aKeyData.push_back(
sal_uInt8((nCounter >> 24) & 0xff));
480 aKeyData.data(), aKeyData.size(), ::comphelper::HashType::SHA1));
483 rtl_cipher_init(
m_hCipher, rtl_Cipher_DirectionDecode,
486 return (
result == rtl_Cipher_E_None);
494 aHashData[OUString(
"STD97EncryptionKey")] <<=
m_aStd97Key;
500#if DEBUG_MSO_ENCRYPTION_STD97
505 sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
509 m_hCipher, pDigest, 16, pDigest,
sizeof(pDigest));
511 memcpy(nSaltDigest, pDigest, 16);
516 const void *pData, std::size_t nDatLen,
519 rtlCipherError
result = rtl_cipher_encode(
522 return (
result == rtl_Cipher_E_None);
526 const void *pData, std::size_t nDatLen,
529 rtlCipherError
result = rtl_cipher_decode(
532 return (
result == rtl_Cipher_E_None);
538 std::size_t nDatLeft = nDatLen;
541 while (bResult && nDatLeft)
543 std::size_t nBlockLen = ::std::min< std::size_t >( nDatLeft,
sizeof(pnDummy) );
544 bResult =
Decode( pnDummy, nBlockLen, pnDummy, nBlockLen );
545 nDatLeft -= nBlockLen;
558 m_hCipher, pSaltData, 16, pBuffer,
sizeof(pBuffer));
564 memset (pBuffer + 17, 0,
sizeof(pBuffer) - 17);
570 rtl_digest_updateMD5 (
573 m_hDigest, pDigestLocal,
sizeof(pDigestLocal));
575 memcpy(pDigest, pDigestLocal, 16);
586 sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
590 m_hCipher, pSalt, 16, pSaltData,
sizeof(pBuffer));
592 memcpy( pBuffer, pSalt, 16 );
595 memset (pBuffer + 17, 0,
sizeof(pBuffer) - 17);
598 rtl_digest_updateMD5 (
604 m_hCipher, pDigest, 16, pSaltDigest, 16);
606 rtl_secureZeroMemory (pBuffer,
sizeof(pBuffer));
607 rtl_secureZeroMemory (pDigest,
sizeof(pDigest));
613 memcpy(pDocId,
m_aDocId.data(), 16);
static css::uno::Sequence< sal_Int8 > GenerateStd97Key(std::u16string_view aPassword, const css::uno::Sequence< sal_Int8 > &aDocId)
static std::vector< unsigned char > calculateHash(const unsigned char *pInput, size_t length, HashType eType)
TValueType getUnpackedValueOrDefault(const OUString &sKey, const TValueType &aDefault) const
css::uno::Sequence< css::beans::NamedValue > getAsConstNamedValueList() const
bool Skip(std::size_t nDatLen)
Lets the cipher skip a specific amount of bytes.
bool Encode(const void *pData, std::size_t nDatLen, sal_uInt8 *pBuffer, std::size_t nBufLen)
Encodes a block of memory.
std::vector< sal_uInt8 > m_aDigestValue
bool VerifyKey(const sal_uInt8 *pSaltData, const sal_uInt8 *pSaltDigest)
Verifies the validity of the password using the passed salt data.
virtual bool InitCipher(sal_uInt32 nCounter)=0
Rekeys the codec using the specified counter.
MSCodec97(size_t nHashLen, OUString aEncKeyName)
void GetDocId(sal_uInt8 pDocId[16])
virtual void GetDigestFromSalt(const sal_uInt8 *pSaltData, sal_uInt8 *pDigest)=0
virtual css::uno::Sequence< css::beans::NamedValue > GetEncryptionData()
Retrieves the encryption data.
bool Decode(const void *pData, std::size_t nDatLen, sal_uInt8 *pBuffer, std::size_t nBufLen)
Decodes a block of memory.
std::vector< sal_uInt8 > m_aDocId
bool InitCodec(const css::uno::Sequence< css::beans::NamedValue > &aData)
Initializes the algorithm with the encryption data.
css::uno::Sequence< sal_Int8 > m_aStd97Key
virtual void InitKey(const sal_uInt16 pPassData[16], const sal_uInt8 pDocId[16]) override
Initializes the algorithm with the specified password and document ID.
virtual bool InitCipher(sal_uInt32 nCounter) override
Rekeys the codec using the specified counter.
virtual void GetDigestFromSalt(const sal_uInt8 *pSaltData, sal_uInt8 *pDigest) override
virtual css::uno::Sequence< css::beans::NamedValue > GetEncryptionData() override
Retrieves the encryption data.
virtual ~MSCodec_Std97() override
void CreateSaltDigest(const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16])
Creates an MD5 digest of salt digest.
virtual bool InitCipher(sal_uInt32 nCounter) override
Rekeys the codec using the specified counter.
void GetEncryptKey(const sal_uInt8 pSalt[16], sal_uInt8 pSaltData[16], sal_uInt8 pSaltDigest[16])
Gets salt data and salt digest.
virtual void GetDigestFromSalt(const sal_uInt8 *pSaltData, sal_uInt8 *pDigest) override
virtual void InitKey(const sal_uInt16 pPassData[16], const sal_uInt8 pDocId[16]) override
Initializes the algorithm with the specified password and document ID.
std::size_t mnOffset
Encryption key.
css::uno::Sequence< css::beans::NamedValue > GetEncryptionData()
Retrieves the encryption data.
bool InitCodec(const css::uno::Sequence< css::beans::NamedValue > &aData)
Initializes the algorithm with the encryption data.
MSCodec_Xor95(int nRotateDistance)
void InitCipher()
Reinitializes the codec to start a new memory block.
void Skip(std::size_t nBytes)
Lets the cipher skip a specific amount of bytes.
int mnRotateDistance
Hash value from password.
sal_uInt16 mnHash
Base key from password.
bool VerifyKey(sal_uInt16 nKey, sal_uInt16 nHash) const
Verifies the validity of the password using the passed key and hash.
void InitKey(const sal_uInt8 pnPassData[16])
Initializes the algorithm with the specified password.
virtual void Decode(sal_uInt8 *pnData, std::size_t nBytes) override
Decodes a block of memory inplace.
virtual void Decode(sal_uInt8 *pnData, std::size_t nBytes) override
Decodes a block of memory inplace.
std::unique_ptr< sal_Int32[]> pData
constexpr OUStringLiteral aData
Shape IDs per cluster in DGG atom.
const sal_uInt32 SHA1_HASH_LENGTH
const sal_uInt32 ENCRYPT_KEY_SIZE_AES_128
static void lcl_PrintDigest(const sal_uInt8 *, const char *)
const sal_uInt32 SALT_LENGTH
EncryptionStandardHeader()
std::unique_ptr< char[]> aBuffer