From 44240798be68433127e4699598ae0b98098743b8 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald <jonas.jenwald@gmail.com> Date: Wed, 13 May 2015 17:25:42 +0200 Subject: [PATCH] Convert UTF8 encoded passwords to ISO-8859-1 for |R = 6| encryption (issue 6010) For passwords where the encoding already is correct, the conversion is a no-op. Also, since `encodeURIComponent` might throw, we need to make sure that we handle that case too. Fixes 6010. --- src/core/crypto.js | 13 +++++++++++-- src/shared/util.js | 4 ++++ test/pdfs/.gitignore | 2 ++ test/pdfs/issue6010_1.pdf | 37 +++++++++++++++++++++++++++++++++++++ test/pdfs/issue6010_2.pdf | 38 ++++++++++++++++++++++++++++++++++++++ test/test_manifest.json | 17 +++++++++++++++++ 6 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 test/pdfs/issue6010_1.pdf create mode 100644 test/pdfs/issue6010_2.pdf diff --git a/src/core/crypto.js b/src/core/crypto.js index abb1d18fd..95d63b175 100644 --- a/src/core/crypto.js +++ b/src/core/crypto.js @@ -15,7 +15,8 @@ * limitations under the License. */ /* globals bytesToString, DecryptStream, error, isInt, isName, Name, - PasswordException, PasswordResponses, stringToBytes */ + PasswordException, PasswordResponses, stringToBytes, warn, + utf8StringToString */ 'use strict'; @@ -1918,6 +1919,14 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { var fileIdBytes = stringToBytes(fileId); var passwordBytes; if (password) { + if (revision === 6) { + try { + password = utf8StringToString(password); + } catch (ex) { + warn('CipherTransformFactory: ' + + 'Unable to convert UTF8 encoded password.'); + } + } passwordBytes = stringToBytes(password); } @@ -2022,7 +2031,7 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { CipherTransformFactory.prototype = { createCipherTransform: - function CipherTransformFactory_createCipherTransform(num, gen) { + function CipherTransformFactory_createCipherTransform(num, gen) { if (this.algorithm === 4 || this.algorithm === 5) { return new CipherTransform( buildCipherConstructor(this.cf, this.stmf, diff --git a/src/shared/util.js b/src/shared/util.js index 47736b02b..382f6437f 100644 --- a/src/shared/util.js +++ b/src/shared/util.js @@ -946,6 +946,10 @@ function stringToUTF8String(str) { return decodeURIComponent(escape(str)); } +function utf8StringToString(str) { + return unescape(encodeURIComponent(str)); +} + function isEmptyObj(obj) { for (var key in obj) { return false; diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index 7946c42e3..ca03261e1 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -130,3 +130,5 @@ !issue5701.pdf !issue5896.pdf !issue5909.pdf +!issue6010_1.pdf +!issue6010_2.pdf diff --git a/test/pdfs/issue6010_1.pdf b/test/pdfs/issue6010_1.pdf new file mode 100644 index 000000000..504711092 --- /dev/null +++ b/test/pdfs/issue6010_1.pdf @@ -0,0 +1,37 @@ +%PDF-1.7 +%���� +1 0 obj +<</Pages 6 0 R/Type/Catalog>> +endobj +2 0 obj +<</Type/Encoding/BaseEncoding/WinAnsiEncoding>> +endobj +3 0 obj +<</Parent 6 0 R/Resources<</Font<</F1 5 0 R>>>>/MediaBox[0 0 200 50]/Type/Page/Contents 4 0 R>> +endobj +4 0 obj +<</Filter/FlateDecode/Length 64>> +stream +��6�2���|Q$j����^�BHJC<w߲�M%X33u찺;�*���iͻ���K��9���IR� +endstream +endobj +5 0 obj +<</BaseFont/Times-Roman/Subtype/Type1/Type/Font/Encoding 2 0 R>> +endobj +6 0 obj +<</MediaBox[0 0 200 50]/Kids[3 0 R]/Type/Pages/Count 1>> +endobj +xref +0 7 +0000000000 65535 f +0000000015 00000 n +0000000060 00000 n +0000000123 00000 n +0000000234 00000 n +0000000365 00000 n +0000000445 00000 n +trailer +<</Size 7/ID[(gUe>/j�_�8:�;�)(gUe>/j�_�8:�;�)]/Encrypt<</Filter/Standard/V 5/CF<</StdCF<</Length 32/AuthEvent/DocOpen/CFM/AESV3>>>>/EncryptMetadata true/Length 256/R 6/O(��6��\(�T#�k6PQ鎒\n���`@��$�K��e�� F��)/U(��� 4�4��~>W�nT-�:���}|XSvf2,8ߛ^�,�}w��3\f����)/P -4/StrF/StdCF/StmF/StdCF/Perms(�����\r1��o�u)/OE(�?�O����\(Q�5F��RV��J��,VY�)/UE(Eb�lp�K�5�PL����FqI�D<��>�<�)>>/Root 1 0 R>> +startxref +517 +%%EOF diff --git a/test/pdfs/issue6010_2.pdf b/test/pdfs/issue6010_2.pdf new file mode 100644 index 000000000..ccb117e59 --- /dev/null +++ b/test/pdfs/issue6010_2.pdf @@ -0,0 +1,38 @@ +%PDF-1.7 +%���� +1 0 obj +<</Pages 6 0 R/Type/Catalog>> +endobj +2 0 obj +<</Type/Encoding/BaseEncoding/WinAnsiEncoding>> +endobj +3 0 obj +<</Parent 6 0 R/Resources<</Font<</F1 5 0 R>>>>/MediaBox[0 0 200 50]/Type/Page/Contents 4 0 R>> +endobj +4 0 obj +<</Filter/FlateDecode/Length 64>> +stream +��h�R�$���֯�k��o��oElg,���Qhw$YvÃ=�;^�u��s�_� +##%�'�� +endstream +endobj +5 0 obj +<</BaseFont/Times-Roman/Subtype/Type1/Type/Font/Encoding 2 0 R>> +endobj +6 0 obj +<</MediaBox[0 0 200 50]/Kids[3 0 R]/Type/Pages/Count 1>> +endobj +xref +0 7 +0000000000 65535 f +0000000015 00000 n +0000000060 00000 n +0000000123 00000 n +0000000234 00000 n +0000000365 00000 n +0000000445 00000 n +trailer +<</Size 7/ID[(I�$"E6?T��nߏ\b)(I�$"E6?T��nߏ\b)]/Encrypt<</Filter/Standard/V 5/CF<</StdCF<</Length 32/AuthEvent/DocOpen/CFM/AESV3>>>>/EncryptMetadata true/Length 256/R 6/O(듷XXB\f����p �G&�§q0�<���Px�a�U�������Y)/U(WPk�D��_Ñ�L^���D\f.C�s�r���F\\NU��L���4�F���9�)/P -4/StrF/StdCF/StmF/StdCF/Perms(G^�o����F�GQO)/OE(h7饷�ⴁCn���x�������'7+��n53�E)/UE(�W�[�ZѪ=Q����0y�#�#�ԭ�&ڹ��Pv)>>/Root 1 0 R>> +startxref +517 +%%EOF diff --git a/test/test_manifest.json b/test/test_manifest.json index f20b9863a..be0ec3067 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -1493,6 +1493,23 @@ "type": "eq", "about": "Rotated transparency group with blend mode." }, + { "id": "issue6010_1", + "file": "pdfs/issue6010_1.pdf", + "md5": "b58adce5dbb08936ddb0d904f0da8716", + "rounds": 1, + "link": false, + "type": "load", + "password": "abc" + }, + { "id": "issue6010_2", + "file": "pdfs/issue6010_2.pdf", + "md5": "73a8091d0ab2a47af5ca45047f04da99", + "rounds": 1, + "link": false, + "type": "load", + "password": "\u00E6\u00F8\u00E5", + "about": "The password (���) is UTF8 encoded." + }, { "id": "issue3458.pdf", "file": "pdfs/issue3458.pdf", "md5": "dab8bd3ad1acfc8dc82a8381a3c8ff94",