• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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