summaryrefslogtreecommitdiff
path: root/vcl/source
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2024-11-11 15:19:45 +0100
committerMiklos Vajna <vmiklos@collabora.com>2024-12-02 09:11:02 +0100
commit27804802fc45bc969d95261899f45bdedcb7eb7e (patch)
tree64f39ca894053f214ab64d92e2357eac0bd90a73 /vcl/source
parentce9be1415eb079323b5ad0cadd47e4b90c3a4aff (diff)
pdf: R6 hash algorithm and test, introduce PDFEncryptorR6
This adds PDFEncryptorR6 and adds R6 hash implementation and makes sure it is correct with a test. Change-Id: I11ca746a6b676bb294723b4ef76069f1d4f3a182 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176451 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Diffstat (limited to 'vcl/source')
-rw-r--r--vcl/source/pdf/PDFEncryptorR6.cxx103
1 files changed, 103 insertions, 0 deletions
diff --git a/vcl/source/pdf/PDFEncryptorR6.cxx b/vcl/source/pdf/PDFEncryptorR6.cxx
new file mode 100644
index 000000000000..64e668dca598
--- /dev/null
+++ b/vcl/source/pdf/PDFEncryptorR6.cxx
@@ -0,0 +1,103 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <pdf/PDFEncryptorR6.hxx>
+#include <pdf/EncryptionHashTransporter.hxx>
+#include <pdf/pdfwriter_impl.hxx>
+#include <comphelper/crypto/Crypto.hxx>
+#include <comphelper/hash.hxx>
+#include <comphelper/random.hxx>
+
+namespace vcl::pdf
+{
+namespace
+{
+/** Calculates modulo 3 of the 128-bit integer, using the first 16 bytes of the vector */
+sal_Int32 calculateModulo3(std::vector<sal_uInt8> const& rInput)
+{
+ sal_Int32 nSum = 0;
+ for (size_t i = 0; i < 16; ++i)
+ nSum += rInput[i];
+ return nSum % 3;
+}
+}
+
+/** Algorithm 2.B: Computing a hash (revision 6 and later)
+ *
+ * Described in ISO 32000-2:2020(E) - 7.6.4.3.4
+ */
+std::vector<sal_uInt8> computeHashR6(const sal_uInt8* pPassword, size_t nPasswordLength,
+ std::vector<sal_uInt8> const& rValidationSalt,
+ std::vector<sal_uInt8> const& rUserKey)
+{
+ // Round 0
+ comphelper::Hash aHash(comphelper::HashType::SHA256);
+ aHash.update(pPassword, nPasswordLength);
+ aHash.update(rValidationSalt);
+ if (!rUserKey.empty()) // if calculating owner key
+ aHash.update(rUserKey);
+
+ std::vector<sal_uInt8> K = aHash.finalize();
+
+ std::vector<sal_uInt8> E;
+
+ sal_Int32 nRound = 1;
+ do
+ {
+ // Step a)
+ std::vector<sal_uInt8> K1;
+ for (sal_Int32 nRepetition = 0; nRepetition < 64; ++nRepetition)
+ {
+ K1.insert(K1.end(), pPassword, pPassword + nPasswordLength);
+ K1.insert(K1.end(), K.begin(), K.end());
+ if (!rUserKey.empty()) // if calculating owner key
+ K1.insert(K1.end(), rUserKey.begin(), rUserKey.end());
+ }
+
+ // Step b)
+ std::vector<sal_uInt8> aKey(K.begin(), K.begin() + 16);
+ std::vector<sal_uInt8> aInitVector(K.begin() + 16, K.end());
+
+ E = std::vector<sal_uInt8>(K1.size(), 0);
+
+ comphelper::Encrypt aEncrypt(aKey, aInitVector, comphelper::CryptoType::AES_128_CBC);
+ aEncrypt.update(E, K1);
+
+ // Step c)
+ sal_Int32 nModulo3Result = calculateModulo3(E);
+
+ // Step d)
+ comphelper::HashType eType;
+ switch (nModulo3Result)
+ {
+ case 0:
+ eType = comphelper::HashType::SHA256;
+ break;
+ case 1:
+ eType = comphelper::HashType::SHA384;
+ break;
+ default:
+ eType = comphelper::HashType::SHA512;
+ break;
+ }
+ K = comphelper::Hash::calculateHash(E.data(), E.size(), eType);
+
+ nRound++;
+ }
+ // Step e) and f)
+ // We stop iteration if we do at least 64 rounds and (the last element of E <= round number - 32)
+ while (nRound < 64 || E.back() > (nRound - 32));
+
+ // Output - first 32 bytes
+ return std::vector<sal_uInt8>(K.begin(), K.begin() + 32);
+}
+
+} // end vcl::pdf
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */