1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "xfa/fxfa/xfa_checksum.h"
8
9 #include "core/fdrm/crypto/fx_crypt.h"
10 #include "third_party/base/ptr_util.h"
11
12 namespace {
13
14 struct FX_BASE64DATA {
15 uint32_t data1 : 2;
16 uint32_t data2 : 6;
17 uint32_t data3 : 4;
18 uint32_t data4 : 4;
19 uint32_t data5 : 6;
20 uint32_t data6 : 2;
21 uint32_t data7 : 8;
22 };
23
24 const FX_CHAR g_FXBase64EncoderMap[64] = {
25 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
26 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
27 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
28 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
29 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
30 };
31
Base64EncodePiece(const FX_BASE64DATA & src,int32_t iBytes,FX_CHAR dst[4])32 void Base64EncodePiece(const FX_BASE64DATA& src,
33 int32_t iBytes,
34 FX_CHAR dst[4]) {
35 dst[0] = g_FXBase64EncoderMap[src.data2];
36 uint32_t b = src.data1 << 4;
37 if (iBytes > 1) {
38 b |= src.data4;
39 }
40 dst[1] = g_FXBase64EncoderMap[b];
41 if (iBytes > 1) {
42 b = src.data3 << 2;
43 if (iBytes > 2) {
44 b |= src.data6;
45 }
46 dst[2] = g_FXBase64EncoderMap[b];
47 if (iBytes > 2) {
48 dst[3] = g_FXBase64EncoderMap[src.data5];
49 } else {
50 dst[3] = '=';
51 }
52 } else {
53 dst[2] = dst[3] = '=';
54 }
55 }
56
Base64EncodeA(const uint8_t * pSrc,int32_t iSrcLen,FX_CHAR * pDst)57 int32_t Base64EncodeA(const uint8_t* pSrc, int32_t iSrcLen, FX_CHAR* pDst) {
58 ASSERT(pSrc);
59 if (iSrcLen < 1) {
60 return 0;
61 }
62 if (!pDst) {
63 int32_t iDstLen = iSrcLen / 3 * 4;
64 if ((iSrcLen % 3) != 0) {
65 iDstLen += 4;
66 }
67 return iDstLen;
68 }
69 FX_BASE64DATA srcData;
70 int32_t iBytes = 3;
71 FX_CHAR* pDstEnd = pDst;
72 while (iSrcLen > 0) {
73 if (iSrcLen > 2) {
74 ((uint8_t*)&srcData)[0] = *pSrc++;
75 ((uint8_t*)&srcData)[1] = *pSrc++;
76 ((uint8_t*)&srcData)[2] = *pSrc++;
77 iSrcLen -= 3;
78 } else {
79 *((uint32_t*)&srcData) = 0;
80 ((uint8_t*)&srcData)[0] = *pSrc++;
81 if (iSrcLen > 1) {
82 ((uint8_t*)&srcData)[1] = *pSrc++;
83 }
84 iBytes = iSrcLen;
85 iSrcLen = 0;
86 }
87 Base64EncodePiece(srcData, iBytes, pDstEnd);
88 pDstEnd += 4;
89 }
90 return pDstEnd - pDst;
91 }
92
93 } // namespace
94
CXFA_SAXReaderHandler(CXFA_ChecksumContext * pContext)95 CXFA_SAXReaderHandler::CXFA_SAXReaderHandler(CXFA_ChecksumContext* pContext)
96 : m_pContext(pContext) {
97 ASSERT(m_pContext);
98 }
~CXFA_SAXReaderHandler()99 CXFA_SAXReaderHandler::~CXFA_SAXReaderHandler() {}
OnTagEnter(const CFX_ByteStringC & bsTagName,CFX_SAXItem::Type eType,uint32_t dwStartPos)100 CXFA_SAXContext* CXFA_SAXReaderHandler::OnTagEnter(
101 const CFX_ByteStringC& bsTagName,
102 CFX_SAXItem::Type eType,
103 uint32_t dwStartPos) {
104 UpdateChecksum(true);
105 if (eType != CFX_SAXItem::Type::Tag &&
106 eType != CFX_SAXItem::Type::Instruction) {
107 return nullptr;
108 }
109 m_SAXContext.m_eNode = eType;
110 CFX_ByteTextBuf& textBuf = m_SAXContext.m_TextBuf;
111 textBuf << "<";
112 if (eType == CFX_SAXItem::Type::Instruction) {
113 textBuf << "?";
114 }
115 textBuf << bsTagName;
116 m_SAXContext.m_bsTagName = bsTagName;
117 return &m_SAXContext;
118 }
119
OnTagAttribute(CXFA_SAXContext * pTag,const CFX_ByteStringC & bsAttri,const CFX_ByteStringC & bsValue)120 void CXFA_SAXReaderHandler::OnTagAttribute(CXFA_SAXContext* pTag,
121 const CFX_ByteStringC& bsAttri,
122 const CFX_ByteStringC& bsValue) {
123 if (!pTag)
124 return;
125
126 pTag->m_TextBuf << " " << bsAttri << "=\"" << bsValue << "\"";
127 }
128
OnTagBreak(CXFA_SAXContext * pTag)129 void CXFA_SAXReaderHandler::OnTagBreak(CXFA_SAXContext* pTag) {
130 if (!pTag)
131 return;
132
133 pTag->m_TextBuf << ">";
134 UpdateChecksum(false);
135 }
136
OnTagData(CXFA_SAXContext * pTag,CFX_SAXItem::Type eType,const CFX_ByteStringC & bsData,uint32_t dwStartPos)137 void CXFA_SAXReaderHandler::OnTagData(CXFA_SAXContext* pTag,
138 CFX_SAXItem::Type eType,
139 const CFX_ByteStringC& bsData,
140 uint32_t dwStartPos) {
141 if (!pTag)
142 return;
143
144 CFX_ByteTextBuf& textBuf = pTag->m_TextBuf;
145 if (eType == CFX_SAXItem::Type::CharData)
146 textBuf << "<![CDATA[";
147
148 textBuf << bsData;
149 if (eType == CFX_SAXItem::Type::CharData)
150 textBuf << "]]>";
151 }
152
OnTagClose(CXFA_SAXContext * pTag,uint32_t dwEndPos)153 void CXFA_SAXReaderHandler::OnTagClose(CXFA_SAXContext* pTag,
154 uint32_t dwEndPos) {
155 if (!pTag)
156 return;
157
158 CFX_ByteTextBuf& textBuf = pTag->m_TextBuf;
159 if (pTag->m_eNode == CFX_SAXItem::Type::Instruction)
160 textBuf << "?>";
161 else if (pTag->m_eNode == CFX_SAXItem::Type::Tag)
162 textBuf << "></" << pTag->m_bsTagName.AsStringC() << ">";
163
164 UpdateChecksum(false);
165 }
166
OnTagEnd(CXFA_SAXContext * pTag,const CFX_ByteStringC & bsTagName,uint32_t dwEndPos)167 void CXFA_SAXReaderHandler::OnTagEnd(CXFA_SAXContext* pTag,
168 const CFX_ByteStringC& bsTagName,
169 uint32_t dwEndPos) {
170 if (!pTag)
171 return;
172
173 pTag->m_TextBuf << "</" << bsTagName << ">";
174 UpdateChecksum(false);
175 }
176
OnTargetData(CXFA_SAXContext * pTag,CFX_SAXItem::Type eType,const CFX_ByteStringC & bsData,uint32_t dwStartPos)177 void CXFA_SAXReaderHandler::OnTargetData(CXFA_SAXContext* pTag,
178 CFX_SAXItem::Type eType,
179 const CFX_ByteStringC& bsData,
180 uint32_t dwStartPos) {
181 if (!pTag && eType != CFX_SAXItem::Type::Comment)
182 return;
183
184 if (eType == CFX_SAXItem::Type::Comment) {
185 m_SAXContext.m_TextBuf << "<!--" << bsData << "-->";
186 UpdateChecksum(false);
187 } else {
188 pTag->m_TextBuf << " " << bsData;
189 }
190 }
191
UpdateChecksum(bool bCheckSpace)192 void CXFA_SAXReaderHandler::UpdateChecksum(bool bCheckSpace) {
193 int32_t iLength = m_SAXContext.m_TextBuf.GetLength();
194 if (iLength < 1) {
195 return;
196 }
197 uint8_t* pBuffer = m_SAXContext.m_TextBuf.GetBuffer();
198 bool bUpdata = true;
199 if (bCheckSpace) {
200 bUpdata = false;
201 for (int32_t i = 0; i < iLength; i++) {
202 bUpdata = (pBuffer[i] > 0x20);
203 if (bUpdata) {
204 break;
205 }
206 }
207 }
208 if (bUpdata) {
209 m_pContext->Update(CFX_ByteStringC(pBuffer, iLength));
210 }
211 m_SAXContext.m_TextBuf.Clear();
212 }
213
CXFA_ChecksumContext()214 CXFA_ChecksumContext::CXFA_ChecksumContext() {}
215
~CXFA_ChecksumContext()216 CXFA_ChecksumContext::~CXFA_ChecksumContext() {}
217
StartChecksum()218 void CXFA_ChecksumContext::StartChecksum() {
219 FinishChecksum();
220 m_pByteContext = pdfium::MakeUnique<CRYPT_sha1_context>();
221 CRYPT_SHA1Start(m_pByteContext.get());
222 m_bsChecksum.clear();
223 m_pSAXReader = pdfium::MakeUnique<CFX_SAXReader>();
224 }
225
UpdateChecksum(const CFX_RetainPtr<IFX_SeekableReadStream> & pSrcFile,FX_FILESIZE offset,size_t size)226 bool CXFA_ChecksumContext::UpdateChecksum(
227 const CFX_RetainPtr<IFX_SeekableReadStream>& pSrcFile,
228 FX_FILESIZE offset,
229 size_t size) {
230 if (!m_pSAXReader || !pSrcFile)
231 return false;
232
233 if (size < 1)
234 size = pSrcFile->GetSize();
235
236 CXFA_SAXReaderHandler handler(this);
237 m_pSAXReader->SetHandler(&handler);
238 if (m_pSAXReader->StartParse(
239 pSrcFile, (uint32_t)offset, (uint32_t)size,
240 CFX_SaxParseMode_NotSkipSpace | CFX_SaxParseMode_NotConvert_amp |
241 CFX_SaxParseMode_NotConvert_lt | CFX_SaxParseMode_NotConvert_gt |
242 CFX_SaxParseMode_NotConvert_sharp) < 0) {
243 return false;
244 }
245 return m_pSAXReader->ContinueParse(nullptr) > 99;
246 }
247
FinishChecksum()248 void CXFA_ChecksumContext::FinishChecksum() {
249 m_pSAXReader.reset();
250 if (m_pByteContext) {
251 uint8_t digest[20];
252 FXSYS_memset(digest, 0, 20);
253 CRYPT_SHA1Finish(m_pByteContext.get(), digest);
254 int32_t nLen = Base64EncodeA(digest, 20, nullptr);
255 FX_CHAR* pBuffer = m_bsChecksum.GetBuffer(nLen);
256 Base64EncodeA(digest, 20, pBuffer);
257 m_bsChecksum.ReleaseBuffer(nLen);
258 m_pByteContext.reset();
259 }
260 }
261
GetChecksum() const262 CFX_ByteString CXFA_ChecksumContext::GetChecksum() const {
263 return m_bsChecksum;
264 }
265
Update(const CFX_ByteStringC & bsText)266 void CXFA_ChecksumContext::Update(const CFX_ByteStringC& bsText) {
267 if (!m_pByteContext)
268 return;
269
270 CRYPT_SHA1Update(m_pByteContext.get(), bsText.raw_str(), bsText.GetLength());
271 }
272