Besides the file header, DocInfo and the sections, an HWP 5.0 compound
file can hold a summary, previews, options, scripts, an XML template, a version history
and a bibliography. A distribution document, made to be read but not edited, keeps its
text encrypted. This page follows Hancom’s HWP 5.0 specification, revision 1.3
(sections 3.2.4 to 3.2.12 and 4.4), and its separate specification of distribution
documents, revision 1.2 (9 October 2014).
\005HwpSummaryInformation
The document summary entered under File › Document information › Summary, as a standard OLE summary information property set (the stream name begins with the byte 5). The properties Hangul writes (table 7):
| Property | ID name | ID | Type |
|---|---|---|---|
| Title | PIDSI_TITLE | 0x02 | VT_LPSTR |
| Subject | PIDSI_SUBJECT | 0x03 | VT_LPSTR |
| Author | PIDSI_AUTHOR | 0x04 | VT_LPSTR |
| Keywords | PIDSI_KEYWORDS | 0x05 | VT_LPSTR |
| Comments | PIDSI_COMMENTS | 0x06 | VT_LPSTR |
| Last saved by | PIDSI_LASTAUTHOR | 0x08 | VT_LPSTR |
| Revision number | PIDSI_REVNUMBER | 0x09 | VT_LPSTR |
| Last printed | PIDSI_LASTPRINTED | 0x0B | VT_FILETIME (UTC) |
| Created | PIDSI_CREATE_DTM | 0x0C | VT_FILETIME (UTC) |
| Last saved | PIDSI_LASTSAVE_DTM | 0x0D | VT_FILETIME (UTC) |
| Number of pages | PIDSI_PAGECOUNT | 0x0E | VT_I4 |
| Date string (Hangul’s own) | HWPPIDSI_DATE_STR | 0x14 | VT_LPSTR |
| Paragraph count (Hangul’s own) | HWPPIDSI_PARACOUNT | 0x15 | VT_I4 |
PrvText and PrvImage
PrvText holds a preview of the text as a Unicode (UTF-16LE) string.
PrvImage holds a preview image in BMP or
GIF format.
BinData
Each picture or OLE object attached to the document is a stream of its own in the
BinData storage, described by a
HWPTAG_BIN_DATA
record, which also says whether it is compressed.
DocOptions
Streams for linked documents, distribution, certificate DRM and digital signatures. Their layouts are not published.
| Stream | Contents |
|---|---|
_LinkDoc | Path of the linked document |
DrmLicense | Version definition of the DRM packaging |
DrmRootSect | The encryption algorithm |
CertDrmHeader | Version definition of the DRM packaging |
CertDrmInfo | Certificate DRM information |
DigitalSignature | Digital signature information |
PublicKeyInfo | Public key information |
Scripts
JScriptVersion (table 8): a DWORD high and a DWORD low part of the
script version, 8 bytes. DefaultJScript (table 9):
| Type | Field |
|---|---|
| DWORD + WCHAR[len1] | Script header |
| DWORD + WCHAR[len2] | Script source |
| DWORD + WCHAR[len3] | Pre-source |
| DWORD + WCHAR[len4] | Post-source |
| DWORD | End flag, −1 |
20 + 2 × (len1 + len2 + len3 + len4) bytes. The lengths here are DWORDs, unlike the WORD lengths inside records.
XMLTemplate
Three streams, each a DWORD length and that many WCHARs (tables 10 to 12):
_SchemaName, the schema’s name; Schema, the schema;
Instance, the instance.
DocHistory
The document’s version history (File › Document history; called version comparison
in Hangul 2005 to 2007), supported from Hangul 2005 (6.5.0.724) and file version
5.0.1.7. Each history item is a stream VersionLogn, compressed and
encrypted, and HistoryLastDoc holds the latest document. A stream is a
run of records, each a BYTE record type, a UINT size and that many bytes of data. An
item starts with a start record and ends with an end record:
| Type | Name | Data (tables 154 to 161) |
|---|---|---|
0x10 | HISTORY_RECORD_TYPE_STAG | WORD flag, UINT option: start of an item |
0x11 | HISTORY_RECORD_TYPE_ETAG | None: end of the item |
0x20 | HISTORY_RECORD_TYPE_VERSION | DWORD version |
0x21 | HISTORY_RECORD_TYPE_DATE | SYSTEMDATE: the date |
0x22 | HISTORY_RECORD_TYPE_WRITER | WCHAR string: the author |
0x23 | HISTORY_RECORD_TYPE_DESCRIPTION | WCHAR string: the description |
0x30 | HISTORY_RECORD_TYPE_DIFFDATA | WCHAR string: the comparison, in DiffML |
0x31 | HISTORY_RECORD_TYPE_LASTDOCDATA | WCHAR string: the latest document, in HWPML |
| Flag | Name | The item has |
|---|---|---|
0x01 | HISTORY_INFO_FLAG_VERSION | A version |
0x02 | HISTORY_INFO_FLAG_DATE | A date |
0x04 | HISTORY_INFO_FLAG_WRITER | An author |
0x08 | HISTORY_INFO_FLAG_DESCRIPTION | A description |
0x10 | HISTORY_INFO_FLAG_DIFFDATA | Diff data |
| not given | HISTORY_INFO_FLAG_LASTDOCDATA | The latest document (not recorded; always required) |
0x40 | HISTORY_INFO_FLAG_LOCK | The item is locked |
The one option is HWPVERSION_AUTOSAVE (0x00000001): the
item was saved automatically when the document was saved. The SYSTEMDATE layout and
the DiffML format are not described.
Bibliography
The Bibliography storage holds the document’s bibliography as an XML
file. Its schema is not described.
Distribution documents
A distribution document (file header flag bit 2) is meant to be handed out without
normal editing; it can also forbid copying and printing. Its sections are in
ViewText/Sectionn instead of BodyText/Sectionn,
and are encrypted. These streams are encrypted the same way:
ViewText/Section0…SectionnScripts/JScriptVersionandScripts/DefaultJScriptDocHistory/HistoryLastDocandDocHistory/VersionLog0…VersionLogn
Each of them starts with a HWPTAG_DISTRIBUTE_DOC_DATA record holding
256 bytes of scrambled data. Unscrambled, it gives (distribution specification,
table 3):
| Type | Bytes | Field |
|---|---|---|
| WCHAR[40] | 80 | The SHA-1 hash code of the password used to make the distribution document; its first 16 bytes are the key for the encryption |
| WCHAR | 2 | Options: 0x01 copying forbidden, 0x02 printing forbidden |
Decryption
- Seed. The first 4 bytes of the 256-byte data, as a UINT.
- Random table. Seed the Microsoft Visual C runtime’s random
generator with
srand(seed). Then callrand()in pairs: the first call gives a value A =rand() & 0xFF, the second a count B =(rand() & 0x0F) + 1; append A to the table B times. Repeat until the table holds 256 bytes. - Unscramble. XOR the 256 bytes of data with the table.
- Hash code. offset =
(seed & 0x0F) + 4. The 80 bytes at that offset of the result are the hash code, and the next 2 bytes the option flags. - Records. The rest of the stream – the records after the distribution record – is encrypted with AES-128 in ECB mode, with the first 16 bytes of the hash code as the key. Decrypted, the records read as usual.
The specification does not say what happens when the last value would overrun the 256 bytes (it can only be cut short), nor how decryption and decompression are ordered when the document is also compressed. The hash code lets Hangul lift the restriction or edit the document when the password is given.
Password and DRM encryption
A document protected by a password (file header flag bit 1, with the
EncryptVersion field: 1 Hangul 2.5 and older, 2 Hangul 3.0 Enhanced,
3 Hangul 3.0 Old, 4 Hangul 7.0 and later), certificate encryption (bit 8) and DRM
(bits 4 and 10) are not described in any specification Hancom has published, so how
those streams are encrypted is unknown here.
HWPX and HWPML
Hancom’s specifications say that its XML format HWPML became the Korean industrial standard KS X 6101:2011 under the name OWPML, which is the basis of HWPX, the XML package newer versions of Hangul save. Hancom has published the older HWPML 3.0 specification; no public text of KS X 6101 or of HWPX was found and read, so HWPX is not described on these pages.
Sources
- Hangul document file format 5.0, revision 1.3 – Hancom’s specification (PDF, in Korean), sections 3.2.4–3.2.12 and 4.4
- Hangul document file format: distribution documents, revision 1.2 – Hancom’s specification of distribution documents (PDF, in Korean)
- Hangul document file format 3.0 and HWPML, revision 1.2 – Hancom’s older specification (PDF, in Korean), not used for these pages