ooxml_crypt 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ooxml_crypt/version.rb +1 -1
  3. data/vendor/cybozulib/common.mk +3 -3
  4. data/vendor/cybozulib/common.props +1 -1
  5. data/vendor/cybozulib/debug.props +1 -1
  6. data/vendor/cybozulib/include/cybozu/atomic.hpp +15 -5
  7. data/vendor/cybozulib/include/cybozu/bfd.hpp +1 -1
  8. data/vendor/cybozulib/include/cybozu/bit_operation.hpp +8 -10
  9. data/vendor/cybozulib/include/cybozu/crypto.hpp +59 -5
  10. data/vendor/cybozulib/include/cybozu/endian.hpp +0 -2
  11. data/vendor/cybozulib/include/cybozu/inttype.hpp +17 -3
  12. data/vendor/cybozulib/include/cybozu/link_libeay32.hpp +1 -1
  13. data/vendor/cybozulib/include/cybozu/link_mpir.hpp +1 -1
  14. data/vendor/cybozulib/include/cybozu/link_ssleay32.hpp +1 -1
  15. data/vendor/cybozulib/include/cybozu/random_generator.hpp +1 -0
  16. data/vendor/cybozulib/include/cybozu/sha2.hpp +102 -0
  17. data/vendor/cybozulib/sample/proj/ssl_smpl/ssl_smpl.vcxproj +1 -1
  18. data/vendor/cybozulib/sample/proj/stacktrace_smpl/stacktrace_smpl.vcxproj +1 -1
  19. data/vendor/cybozulib/test/Makefile +3 -3
  20. data/vendor/cybozulib/test/base/proj/array_test/array_test.vcxproj +1 -1
  21. data/vendor/cybozulib/test/base/proj/atoi_test/atoi_test.vcxproj +1 -1
  22. data/vendor/cybozulib/test/base/proj/atomic_test/atomic_test.vcxproj +1 -1
  23. data/vendor/cybozulib/test/base/proj/base64_test/base64_test.vcxproj +1 -1
  24. data/vendor/cybozulib/test/base/proj/condition_variable_cs_test/condition_variable_cs_test.vcxproj +1 -1
  25. data/vendor/cybozulib/test/base/proj/condition_variable_test/condition_variable_test.vcxproj +1 -1
  26. data/vendor/cybozulib/test/base/proj/config_test/config_test.vcxproj +1 -1
  27. data/vendor/cybozulib/test/base/proj/csv_test/csv_test.vcxproj +1 -1
  28. data/vendor/cybozulib/test/base/proj/endian_test/endian_test.vcxproj +1 -1
  29. data/vendor/cybozulib/test/base/proj/env_test/env_test.vcxproj +1 -1
  30. data/vendor/cybozulib/test/base/proj/event_test/event_test.vcxproj +1 -1
  31. data/vendor/cybozulib/test/base/proj/file_test/file_test.vcxproj +1 -1
  32. data/vendor/cybozulib/test/base/proj/itoa_test/itoa_test.vcxproj +1 -1
  33. data/vendor/cybozulib/test/base/proj/mecab_test/mecab_test.vcxproj +1 -1
  34. data/vendor/cybozulib/test/base/proj/minixml_test/minixml_test.vcxproj +1 -1
  35. data/vendor/cybozulib/test/base/proj/mmap_test/mmap_test.vcxproj +1 -1
  36. data/vendor/cybozulib/test/base/proj/serializer_test/serializer_test.vcxproj +1 -1
  37. data/vendor/cybozulib/test/base/proj/sha1_test/sha1_test.vcxproj +1 -1
  38. data/vendor/cybozulib/test/base/proj/stream_test/stream_test.vcxproj +1 -1
  39. data/vendor/cybozulib/test/base/proj/string_operation_test/string_operation_test.vcxproj +1 -1
  40. data/vendor/cybozulib/test/base/proj/string_test/string_test.vcxproj +1 -1
  41. data/vendor/cybozulib/test/base/proj/thread_test/thread_test.vcxproj +1 -1
  42. data/vendor/cybozulib/test/base/proj/time_test/time_test.vcxproj +1 -1
  43. data/vendor/cybozulib/test/base/proj/tls_test/tls_test.vcxproj +1 -1
  44. data/vendor/cybozulib/test/base/proj/zlib_test/zlib_test.vcxproj +1 -1
  45. data/vendor/cybozulib/test/base/sha2_test.cpp +1 -1
  46. data/vendor/cybozulib/test/base/zlib_test.cpp +2 -0
  47. data/vendor/msoffice/Makefile +2 -2
  48. data/vendor/msoffice/bin/msoffice-crypt.exe +0 -0
  49. data/vendor/msoffice/common.mk +11 -6
  50. data/vendor/msoffice/common.props +25 -25
  51. data/vendor/msoffice/debug.props +13 -13
  52. data/vendor/msoffice/include/crypto_util.hpp +454 -450
  53. data/vendor/msoffice/readme.md +2 -0
  54. data/vendor/msoffice/release.props +27 -27
  55. data/vendor/msoffice/test/Makefile +4 -1
  56. data/vendor/msoffice/test/proj/cfb/cfb_test.vcxproj +89 -89
  57. data/vendor/msoffice/test/proj/hash/hash_test.vcxproj +89 -89
  58. data/vendor/msoffice/test_all.py +4 -4
  59. metadata +7 -7
@@ -1,450 +1,454 @@
1
- #pragma once
2
- /**
3
- @file
4
- Copyright (C) 2012 Cybozu Labs, Inc., all rights reserved.
5
- */
6
- #include "util.hpp"
7
- #include <cybozu/crypto.hpp>
8
- #include <cybozu/stream.hpp>
9
- #include <cybozu/string.hpp>
10
- #include <cybozu/minixml.hpp>
11
- #include <cybozu/endian.hpp>
12
- #include "custom_sha1.hpp"
13
- //#define DEBUG_CLK
14
-
15
- #ifdef DEBUG_CLK
16
- #define XBYAK_NO_OP_NAMES
17
- #include <xbyak/xbyak_util.h>
18
- #endif
19
-
20
- namespace ms {
21
-
22
- // [OFFCRYPTO] 2.3.4.13 encryptedVerifierHashInput step 2
23
- static const std::string blkKey_VerifierHashInput("\xfe" "\xa7" "\xd2" "\x76" "\x3b" "\x4b" "\x9e" "\x79", 8);
24
- // [OFFCRYPTO] 2.3.4.13 encryptedVerifierHashValue step 2
25
- static const std::string blkKey_encryptedVerifierHashValue("\xd7" "\xaa" "\x0f" "\x6d" "\x30" "\x61" "\x34" "\x4e", 8);
26
- // [OFFCRYPTO] 2.3.4.13 encryptedKeyValue step 2
27
- static const std::string blkKey_encryptedKeyValue("\x14" "\x6e" "\x0b" "\xe7" "\xab" "\xac" "\xd0" "\xd6", 8);
28
- // [OFFCRYPTO] 2.3.4.14 DataIntegrity Generation step 3
29
- static const std::string blkKey_dataIntegrity1("\x5f" "\xb2" "\xad" "\x01" "\x0c" "\xb9" "\xe1" "\xf6", 8);
30
- // [OFFCRYPTO] 2.3.4.14 DataIntegrity Generation step 6
31
- static const std::string blkKey_dataIntegrity2("\xa0" "\x67" "\x7f" "\x02" "\xb2" "\x2c" "\x84" "\x33", 8);
32
-
33
- inline void normalizeKey(std::string& key, size_t keySize)
34
- {
35
- key.resize(keySize, char(0x36));
36
- }
37
-
38
- #ifdef DEBUG_CLK
39
- Xbyak::util::Clock clk;
40
- struct XXX {
41
- ~XXX()
42
- {
43
- printf("%.1f Mclk\n", clk.getClock() / double(clk.getCount()) * 1e-6);
44
- }
45
- } xxx;
46
- #endif
47
-
48
- // #define USE_CUSTOM_SHA1
49
-
50
- inline std::string hashPassword(cybozu::crypto::Hash::Name name, const std::string& salt, const std::string& pass, int spinCount)
51
- {
52
- #ifdef USE_CUSTOM_SHA1
53
- if (name != cybozu::crypto::Hash::N_SHA1) {
54
- throw cybozu::Exception("hashPassword") << "not support" << cybozu::crypto::Hash::getName(name);
55
- }
56
- #endif
57
- cybozu::crypto::Hash s(name);
58
- std::string h = s.digest(salt + pass);
59
- #ifdef DEBUG_CLK
60
- clk.begin();
61
- #endif
62
- #ifdef USE_CUSTOM_SHA1
63
- assert(h.size() == 20);
64
- CustomSha1::digest(&h[0], spinCount);
65
- #else
66
- for (int i = 0; i < spinCount; i++) {
67
- char iter[4];
68
- cybozu::Set32bitAsLE(iter, i);
69
- s.update(iter, sizeof(iter));
70
- s.digest(&h[0], &h[0], h.size());
71
- }
72
- #endif
73
- #ifdef DEBUG_CLK
74
- clk.end();
75
- #endif
76
- return h;
77
- }
78
-
79
- #ifdef SHA1_USE_SIMD
80
- template<int n>
81
- inline void sha1PasswordX(std::string out[n], const std::string& salt, const std::string pass[n], int spinCount)
82
- {
83
- for (int i = 0; i < n; i++) {
84
- out[i] = cybozu::crypto::Hash::digest(cybozu::crypto::Hash::N_SHA1, salt + pass[i]);
85
- }
86
- CustomSha1::digestX<n>(out, spinCount);
87
- }
88
- #endif
89
-
90
- /*
91
- [MS-OFFCRYPTO] 2.3.4.10
92
- */
93
- struct CipherParam {
94
- cybozu::crypto::Cipher::Name cipherName;
95
- std::string cipherNameStr;
96
- size_t saltSize;
97
- size_t blockSize;
98
- size_t keyBits;
99
-
100
- cybozu::crypto::Hash::Name hashName;
101
- std::string hashNameStr;
102
- int hashSize;
103
- std::string saltValue;
104
-
105
- CipherParam()
106
- : saltSize(0)
107
- , blockSize(0)
108
- , keyBits(0)
109
- , hashSize(0)
110
- {
111
- }
112
- void put() const
113
- {
114
- printf("cipherName = %s\n", cipherNameStr.c_str());
115
- printf("saltSize = %d\n", (int)saltSize);
116
- printf("blockSize = %d\n", (int)blockSize);
117
- printf("keyBits = %d\n", (int)keyBits);
118
- printf("hashName = %s\n", hashNameStr.c_str());
119
- printf("hashSize = %d\n", hashSize);
120
- printf("saltValue = "); dump(saltValue, false);
121
- }
122
- explicit CipherParam(const cybozu::minixml::Node *node)
123
- {
124
- setByXml(node);
125
- }
126
- void setByXml(const cybozu::minixml::Node *node)
127
- {
128
- saltSize = cybozu::atoi(node->attr["saltSize"]);
129
- blockSize = cybozu::atoi(node->attr["blockSize"]);
130
- keyBits = cybozu::atoi(node->attr["keyBits"]);
131
- hashSize = cybozu::atoi(node->attr["hashSize"]);
132
- saltValue = dec64(node->attr["saltValue"]);
133
-
134
- if (saltSize < 1 || saltSize > 65536) {
135
- throw cybozu::Exception("ms:CipherParam:saltSize") << saltSize;
136
- }
137
- if (blockSize < 2 || blockSize > 4096 || (blockSize & 1)) {
138
- throw cybozu::Exception("ms:CipherParam:blockSize") << blockSize;
139
- }
140
- const std::string& chaining = node->attr["cipherChaining"];
141
- cipherNameStr = node->attr["cipherAlgorithm"];
142
-
143
- if (cipherNameStr == "AES" && keyBits == 128 && chaining == "ChainingModeCBC") {
144
- cipherName = cybozu::crypto::Cipher::N_AES128_CBC;
145
- } else if (cipherNameStr == "AES" && keyBits == 256 && chaining == "ChainingModeCBC") {
146
- cipherName = cybozu::crypto::Cipher::N_AES256_CBC;
147
- } else {
148
- throw cybozu::Exception("ms:CipherParam:cipherNameStr") << cipherNameStr << keyBits << chaining;
149
- }
150
- hashNameStr = node->attr["hashAlgorithm"];
151
-
152
- if (hashNameStr == "SHA1" && hashSize == 20) {
153
- hashName = cybozu::crypto::Hash::N_SHA1;
154
- } else if (hashNameStr == "SHA256" && hashSize == 32) {
155
- hashName = cybozu::crypto::Hash::N_SHA256;
156
- } else if (hashNameStr == "SHA384" && hashSize == 48) {
157
- hashName = cybozu::crypto::Hash::N_SHA384;
158
- } else if (hashNameStr == "SHA512" && hashSize == 64) {
159
- hashName = cybozu::crypto::Hash::N_SHA512;
160
- } else {
161
- throw cybozu::Exception("ms:CipherParam:hashNameStr") << hashNameStr << hashSize;
162
- }
163
- }
164
- void setByName(cybozu::crypto::Cipher::Name cipherName, cybozu::crypto::Hash::Name hashName)
165
- {
166
- this->cipherName = cipherName;
167
- this->hashName = hashName;
168
-
169
- switch (cipherName) {
170
- case cybozu::crypto::Cipher::N_AES128_CBC:
171
- saltSize = 16;
172
- blockSize = 16;
173
- keyBits = 128;
174
- cipherNameStr = "AES";
175
- break;
176
- case cybozu::crypto::Cipher::N_AES256_CBC:
177
- saltSize = 16;
178
- blockSize = 16;
179
- keyBits = 256;
180
- cipherNameStr = "AES";
181
- break;
182
- default:
183
- throw cybozu::Exception("ms:CipherParam:not support cipherName") << cipherName;
184
- }
185
- if (saltSize == 0 || saltSize > 65536) throw cybozu::Exception("ms:CipherParam:setByName:bad saltSize") << saltSize;
186
-
187
- switch (hashName) {
188
- case cybozu::crypto::Hash::N_SHA1:
189
- hashSize = 20;
190
- hashNameStr = "SHA1";
191
- break;
192
- case cybozu::crypto::Hash::N_SHA256:
193
- hashSize = 32;
194
- hashNameStr = "SHA256";
195
- break;
196
- case cybozu::crypto::Hash::N_SHA384:
197
- hashSize = 48;
198
- hashNameStr = "SHA384";
199
- break;
200
- case cybozu::crypto::Hash::N_SHA512:
201
- hashSize = 64;
202
- hashNameStr = "SHA512";
203
- break;
204
- default:
205
- throw cybozu::Exception("ms:CipherParam:setByName:not support hash") << hashName;
206
- }
207
- }
208
- };
209
-
210
- } // ms
211
-
212
- #include "standard_encryption.hpp"
213
-
214
- namespace ms {
215
-
216
- #ifdef __GNUC__ // defined in sys/sysmacros.h
217
- #undef major
218
- #undef minor
219
- #endif
220
- struct EncryptionInfo {
221
- int spinCount;
222
- uint16_t major;
223
- uint16_t minor;
224
- cybozu::MiniXml xml;
225
- CipherParam keyData;
226
- std::string encryptedHmacKey;
227
- std::string encryptedHmacValue;
228
- CipherParam encryptedKey;
229
- std::string encryptedVerifierHashInput;
230
- std::string encryptedVerifierHashValue;
231
- std::string encryptedKeyValue;
232
- // for LibreOffice
233
- bool isStandardEncryption;
234
- EncryptionHeader seHeader;
235
- EncryptionVerifier seVerifier;
236
-
237
- EncryptionInfo()
238
- : spinCount(0)
239
- , major(0)
240
- , minor(0)
241
- , isStandardEncryption(false)
242
- {
243
- }
244
- explicit EncryptionInfo(const std::string& data)
245
- : spinCount(0)
246
- , major(0)
247
- , minor(0)
248
- , isStandardEncryption(false)
249
- {
250
- if (data.size() < 8) {
251
- throw cybozu::Exception("ms:EncryptionInfo:data.size") << data.size();
252
- }
253
- const char *p = &data[0];
254
- major = cybozu::Get16bitAsLE(p + 0);
255
- minor = cybozu::Get16bitAsLE(p + 2);
256
- // [MS-OFFCRYPTO] 2.3.4.10
257
- if (major == 4 && minor == 4) {
258
- setAgileEncryptionInfo(data);
259
- return;
260
- }
261
- if ((major == 3 || major == 4) && minor == 2) {
262
- setStandardEncryptionInfo(data);
263
- isStandardEncryption = true;
264
- return;
265
- }
266
- throw cybozu::Exception("ms:EncryptionInfo:not support version") << major << minor;
267
- }
268
- void put() const
269
- {
270
- if (!isDebug(0)) return;
271
- printf("major = %d\n", major);
272
- printf("minor = %d\n", minor);
273
- printf("isStandardEncryption = %d\n", isStandardEncryption);
274
- if (isStandardEncryption) {
275
- seHeader.put();
276
- seVerifier.put();
277
- } else {
278
- printf("spinCount = %d\n", spinCount);
279
- puts("keyData");
280
- keyData.put();
281
- printf("encryptedHmacKey = "); dump(encryptedHmacKey, false);
282
- printf("encryptedHmacValue = "); dump(encryptedHmacValue, false);
283
- puts("encryptedKey");
284
- encryptedKey.put();
285
- printf("encryptedVerifierHashInput = "); dump(encryptedVerifierHashInput, false);
286
- printf("encryptedVerifierHashValue = "); dump(encryptedVerifierHashValue, false);
287
- printf("encryptedKeyValue = "); dump(encryptedKeyValue, false);
288
- }
289
- }
290
-
291
- void setStandardEncryptionInfo(const std::string& data)
292
- {
293
- const size_t encryptionHeaderSizePos = 8;
294
- size_t dataSize = data.size();
295
- const char *p = data.c_str();
296
- if (dataSize < encryptionHeaderSizePos + 4) {
297
- throw cybozu::Exception("ms:StandardEncryption2007Info:bad data size") << dataSize;
298
- }
299
- const uint32_t encryptionHeaderSize = cybozu::Get32bitAsLE(p + encryptionHeaderSizePos);
300
- if (encryptionHeaderSize > dataSize) {
301
- throw cybozu::Exception("ms:setStandardEncryptionInfo:bad size") << encryptionHeaderSize << dataSize;
302
- }
303
- p += encryptionHeaderSizePos + 4;
304
- dataSize -= encryptionHeaderSizePos + 4;
305
- seHeader.analyze(p, encryptionHeaderSize);
306
- seHeader.put();
307
-
308
- p += encryptionHeaderSize;
309
- dataSize -= encryptionHeaderSize;
310
- printf("dataSize=%u\n", (uint32_t)dataSize);
311
- seVerifier.analyze(p, dataSize);
312
- seVerifier.put();
313
- }
314
-
315
- void setAgileEncryptionInfo(const std::string& data)
316
- {
317
- const char *p = &data[0];
318
- const uint32_t reserved = cybozu::Get32bitAsLE(p + 4);
319
- MS_ASSERT_EQUAL(reserved, 0x40u);
320
- xml.parse(p + 8, p + data.size());
321
-
322
- // keyData
323
- const cybozu::minixml::Node *keyDataNode = xml.get().getFirstTagByName("keyData");
324
- if (keyDataNode == 0) throw cybozu::Exception("ms:EncryptionInfo:no keyData");
325
- keyData.setByXml(keyDataNode);
326
- // dataIntegrity
327
- const cybozu::minixml::Node *dataIntegrity = xml.get().getFirstTagByName("dataIntegrity");
328
- if (dataIntegrity == 0) throw cybozu::Exception("ms:EncryptionInfo:no dataIntegrity");
329
- encryptedHmacKey = dec64(dataIntegrity->attr["encryptedHmacKey"]);
330
- encryptedHmacValue = dec64(dataIntegrity->attr["encryptedHmacValue"]);
331
-
332
- // keyEncryptor
333
- const cybozu::minixml::Node *encryptedKeyNode = xml.get().getFirstTagByName("p:encryptedKey");
334
- if (encryptedKeyNode == 0) throw cybozu::Exception("ms:EncryptionInfo:no p:encryptedKey");
335
- encryptedKey.setByXml(encryptedKeyNode);
336
- spinCount = cybozu::atoi(encryptedKeyNode->attr["spinCount"]);
337
- encryptedVerifierHashInput = dec64(encryptedKeyNode->attr["encryptedVerifierHashInput"]);
338
- encryptedVerifierHashValue = dec64(encryptedKeyNode->attr["encryptedVerifierHashValue"]);
339
- encryptedKeyValue = dec64(encryptedKeyNode->attr["encryptedKeyValue"]);
340
- }
341
- std::string addHeader(const std::string& xmlStr) const
342
- {
343
- char buf[8];
344
- const uint16_t major = 4;
345
- const uint16_t minor = 4;
346
- const uint32_t reserved = 0x40u;
347
- cybozu::Set16bitAsLE(buf + 0, major);
348
- cybozu::Set16bitAsLE(buf + 2, minor);
349
- cybozu::Set32bitAsLE(buf + 4, reserved);
350
- return std::string(buf, sizeof(buf)) + xmlStr;
351
- }
352
- std::string toXml(bool isOffice2013 = false) const
353
- {
354
- char buf[2048];
355
- CYBOZU_SNPRINTF(buf, sizeof(buf),
356
- "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
357
- "<encryption xmlns=\"http://schemas.microsoft.com/office/2006/encryption\""
358
- " xmlns:p=\"http://schemas.microsoft.com/office/2006/keyEncryptor/password\""
359
- // " xmlns:c=\"http://schemas.microsoft.com/office/2006/keyEncryptor/certificate\""
360
- "%s"
361
- ">"
362
- "<keyData saltSize=\"%d\" blockSize=\"%d\" keyBits=\"%d\" hashSize=\"%d\""
363
- " cipherAlgorithm=\"%s\" cipherChaining=\"ChainingModeCBC\" hashAlgorithm=\"%s\""
364
- " saltValue=\"%s\"/>"
365
- "<dataIntegrity encryptedHmacKey=\"%s\""
366
- " encryptedHmacValue=\"%s\"/><keyEncryptors>"
367
- "<keyEncryptor uri=\"http://schemas.microsoft.com/office/2006/keyEncryptor/password\">"
368
- "<p:encryptedKey spinCount=\"%d\" saltSize=\"%d\" blockSize=\"%d\" keyBits=\"%d\" hashSize=\"%d\""
369
- " cipherAlgorithm=\"%s\" cipherChaining=\"ChainingModeCBC\" hashAlgorithm=\"%s\""
370
- " saltValue=\"%s\""
371
- " encryptedVerifierHashInput=\"%s\""
372
- " encryptedVerifierHashValue=\"%s\""
373
- " encryptedKeyValue=\"%s\"/></keyEncryptor></keyEncryptors></encryption>",
374
- isOffice2013 ? " xmlns:c=\"http://schemas.microsoft.com/office/2006/keyEncryptor/certificate\"" : "",
375
- int(keyData.saltSize), int(keyData.blockSize), int(keyData.keyBits), int(keyData.hashSize),
376
- keyData.cipherNameStr.c_str(), keyData.hashNameStr.c_str(),
377
- enc64(keyData.saltValue).c_str(),
378
- enc64(encryptedHmacKey).c_str(),
379
- enc64(encryptedHmacValue).c_str(),
380
- spinCount,
381
- int(encryptedKey.saltSize), int(encryptedKey.blockSize), int(encryptedKey.keyBits), int(encryptedKey.hashSize),
382
- encryptedKey.cipherNameStr.c_str(), encryptedKey.hashNameStr.c_str(),
383
- enc64(encryptedKey.saltValue).c_str(),
384
- enc64(encryptedVerifierHashInput).c_str(),
385
- enc64(encryptedVerifierHashValue).c_str(),
386
- enc64(encryptedKeyValue).c_str()
387
- );
388
- return buf;
389
- }
390
- };
391
-
392
- inline std::string cipher(cybozu::crypto::Cipher::Name name, const char *msg, size_t msgLen, const std::string& key, const std::string& iv, cybozu::crypto::Cipher::Mode mode)
393
- {
394
- cybozu::crypto::Cipher cipher(name);
395
- cipher.setup(mode, key, iv);
396
-
397
- std::string ret;
398
- ret.resize(msgLen + 128/* margin */);
399
-
400
- const size_t roundMsgLen = msgLen & ~15;
401
-
402
- if (roundMsgLen > 0) {
403
- int writeSize = cipher.update(&ret[0], msg, (int)roundMsgLen);
404
- if (writeSize < 0) {
405
- throw cybozu::Exception("ms:cipher:update");
406
- }
407
- }
408
- const int remainSize = int(msgLen - roundMsgLen);
409
- if (remainSize > 0) {
410
- std::string remain(msg + roundMsgLen, remainSize);
411
- remain.resize(16);
412
- int writeSize = cipher.update(&ret[roundMsgLen], &remain[0], 16);
413
- if (writeSize < 0) {
414
- throw cybozu::Exception("ms:cipher:update:remain");
415
- }
416
- ret.resize(roundMsgLen + 16);
417
- } else {
418
- ret.resize(msgLen);
419
- }
420
- return ret;
421
- }
422
-
423
- inline std::string cipher(cybozu::crypto::Cipher::Name name, const std::string& msg, const std::string& key, const std::string& iv, cybozu::crypto::Cipher::Mode mode)
424
- {
425
- return cipher(name, msg.c_str(), msg.size(), key, iv, mode);
426
- }
427
-
428
- inline std::string generateIv(const CipherParam& param, const std::string& blockKey, const std::string& salt)
429
- {
430
- std::string ret;
431
- if (blockKey.empty()) {
432
- ret = salt;
433
- } else {
434
- ret = cybozu::crypto::Hash::digest(param.hashName, salt + blockKey);
435
- }
436
- normalizeKey(ret, param.blockSize);
437
- return ret;
438
- }
439
-
440
- /*
441
- [MS-OFFCRYPTO] 2.3.4.11
442
- */
443
- inline std::string generateKey(const CipherParam& param, const std::string& hash, const std::string& blockKey)
444
- {
445
- std::string ret = cybozu::crypto::Hash::digest(param.hashName, hash + blockKey);
446
- normalizeKey(ret, param.keyBits / 8);
447
- return ret;
448
- }
449
-
450
- } // ms
1
+ #pragma once
2
+ /**
3
+ @file
4
+ Copyright (C) 2012 Cybozu Labs, Inc., all rights reserved.
5
+ */
6
+ #include "util.hpp"
7
+ #include <cybozu/crypto.hpp>
8
+ #include <cybozu/stream.hpp>
9
+ #include <cybozu/string.hpp>
10
+ #include <cybozu/minixml.hpp>
11
+ #include <cybozu/endian.hpp>
12
+ #if CYBOZU_HOST == CYBOZU_HOST_INTEL
13
+ // #define USE_CUSTOM_SHA1
14
+ #endif
15
+ #ifdef USE_CUSTOM_SHA1
16
+ #include "custom_sha1.hpp"
17
+ #endif
18
+ //#define DEBUG_CLK
19
+
20
+ #ifdef DEBUG_CLK
21
+ #define XBYAK_NO_OP_NAMES
22
+ #include <xbyak/xbyak_util.h>
23
+ #endif
24
+
25
+ namespace ms {
26
+
27
+ // [OFFCRYPTO] 2.3.4.13 encryptedVerifierHashInput step 2
28
+ static const std::string blkKey_VerifierHashInput("\xfe" "\xa7" "\xd2" "\x76" "\x3b" "\x4b" "\x9e" "\x79", 8);
29
+ // [OFFCRYPTO] 2.3.4.13 encryptedVerifierHashValue step 2
30
+ static const std::string blkKey_encryptedVerifierHashValue("\xd7" "\xaa" "\x0f" "\x6d" "\x30" "\x61" "\x34" "\x4e", 8);
31
+ // [OFFCRYPTO] 2.3.4.13 encryptedKeyValue step 2
32
+ static const std::string blkKey_encryptedKeyValue("\x14" "\x6e" "\x0b" "\xe7" "\xab" "\xac" "\xd0" "\xd6", 8);
33
+ // [OFFCRYPTO] 2.3.4.14 DataIntegrity Generation step 3
34
+ static const std::string blkKey_dataIntegrity1("\x5f" "\xb2" "\xad" "\x01" "\x0c" "\xb9" "\xe1" "\xf6", 8);
35
+ // [OFFCRYPTO] 2.3.4.14 DataIntegrity Generation step 6
36
+ static const std::string blkKey_dataIntegrity2("\xa0" "\x67" "\x7f" "\x02" "\xb2" "\x2c" "\x84" "\x33", 8);
37
+
38
+ inline void normalizeKey(std::string& key, size_t keySize)
39
+ {
40
+ key.resize(keySize, char(0x36));
41
+ }
42
+
43
+ #ifdef DEBUG_CLK
44
+ Xbyak::util::Clock clk;
45
+ struct XXX {
46
+ ~XXX()
47
+ {
48
+ printf("%.1f Mclk\n", clk.getClock() / double(clk.getCount()) * 1e-6);
49
+ }
50
+ } xxx;
51
+ #endif
52
+
53
+
54
+ inline std::string hashPassword(cybozu::crypto::Hash::Name name, const std::string& salt, const std::string& pass, int spinCount)
55
+ {
56
+ #ifdef USE_CUSTOM_SHA1
57
+ if (name != cybozu::crypto::Hash::N_SHA1) {
58
+ throw cybozu::Exception("hashPassword") << "not support" << cybozu::crypto::Hash::getName(name);
59
+ }
60
+ #endif
61
+ cybozu::crypto::Hash s(name);
62
+ std::string h = s.digest(salt + pass);
63
+ #ifdef DEBUG_CLK
64
+ clk.begin();
65
+ #endif
66
+ #ifdef USE_CUSTOM_SHA1
67
+ assert(h.size() == 20);
68
+ CustomSha1::digest(&h[0], spinCount);
69
+ #else
70
+ for (int i = 0; i < spinCount; i++) {
71
+ char iter[4];
72
+ cybozu::Set32bitAsLE(iter, i);
73
+ s.update(iter, sizeof(iter));
74
+ s.digest(&h[0], &h[0], h.size());
75
+ }
76
+ #endif
77
+ #ifdef DEBUG_CLK
78
+ clk.end();
79
+ #endif
80
+ return h;
81
+ }
82
+
83
+ #ifdef SHA1_USE_SIMD
84
+ template<int n>
85
+ inline void sha1PasswordX(std::string out[n], const std::string& salt, const std::string pass[n], int spinCount)
86
+ {
87
+ for (int i = 0; i < n; i++) {
88
+ out[i] = cybozu::crypto::Hash::digest(cybozu::crypto::Hash::N_SHA1, salt + pass[i]);
89
+ }
90
+ CustomSha1::digestX<n>(out, spinCount);
91
+ }
92
+ #endif
93
+
94
+ /*
95
+ [MS-OFFCRYPTO] 2.3.4.10
96
+ */
97
+ struct CipherParam {
98
+ cybozu::crypto::Cipher::Name cipherName;
99
+ std::string cipherNameStr;
100
+ size_t saltSize;
101
+ size_t blockSize;
102
+ size_t keyBits;
103
+
104
+ cybozu::crypto::Hash::Name hashName;
105
+ std::string hashNameStr;
106
+ int hashSize;
107
+ std::string saltValue;
108
+
109
+ CipherParam()
110
+ : saltSize(0)
111
+ , blockSize(0)
112
+ , keyBits(0)
113
+ , hashSize(0)
114
+ {
115
+ }
116
+ void put() const
117
+ {
118
+ printf("cipherName = %s\n", cipherNameStr.c_str());
119
+ printf("saltSize = %d\n", (int)saltSize);
120
+ printf("blockSize = %d\n", (int)blockSize);
121
+ printf("keyBits = %d\n", (int)keyBits);
122
+ printf("hashName = %s\n", hashNameStr.c_str());
123
+ printf("hashSize = %d\n", hashSize);
124
+ printf("saltValue = "); dump(saltValue, false);
125
+ }
126
+ explicit CipherParam(const cybozu::minixml::Node *node)
127
+ {
128
+ setByXml(node);
129
+ }
130
+ void setByXml(const cybozu::minixml::Node *node)
131
+ {
132
+ saltSize = cybozu::atoi(node->attr["saltSize"]);
133
+ blockSize = cybozu::atoi(node->attr["blockSize"]);
134
+ keyBits = cybozu::atoi(node->attr["keyBits"]);
135
+ hashSize = cybozu::atoi(node->attr["hashSize"]);
136
+ saltValue = dec64(node->attr["saltValue"]);
137
+
138
+ if (saltSize < 1 || saltSize > 65536) {
139
+ throw cybozu::Exception("ms:CipherParam:saltSize") << saltSize;
140
+ }
141
+ if (blockSize < 2 || blockSize > 4096 || (blockSize & 1)) {
142
+ throw cybozu::Exception("ms:CipherParam:blockSize") << blockSize;
143
+ }
144
+ const std::string& chaining = node->attr["cipherChaining"];
145
+ cipherNameStr = node->attr["cipherAlgorithm"];
146
+
147
+ if (cipherNameStr == "AES" && keyBits == 128 && chaining == "ChainingModeCBC") {
148
+ cipherName = cybozu::crypto::Cipher::N_AES128_CBC;
149
+ } else if (cipherNameStr == "AES" && keyBits == 256 && chaining == "ChainingModeCBC") {
150
+ cipherName = cybozu::crypto::Cipher::N_AES256_CBC;
151
+ } else {
152
+ throw cybozu::Exception("ms:CipherParam:cipherNameStr") << cipherNameStr << keyBits << chaining;
153
+ }
154
+ hashNameStr = node->attr["hashAlgorithm"];
155
+
156
+ if (hashNameStr == "SHA1" && hashSize == 20) {
157
+ hashName = cybozu::crypto::Hash::N_SHA1;
158
+ } else if (hashNameStr == "SHA256" && hashSize == 32) {
159
+ hashName = cybozu::crypto::Hash::N_SHA256;
160
+ } else if (hashNameStr == "SHA384" && hashSize == 48) {
161
+ hashName = cybozu::crypto::Hash::N_SHA384;
162
+ } else if (hashNameStr == "SHA512" && hashSize == 64) {
163
+ hashName = cybozu::crypto::Hash::N_SHA512;
164
+ } else {
165
+ throw cybozu::Exception("ms:CipherParam:hashNameStr") << hashNameStr << hashSize;
166
+ }
167
+ }
168
+ void setByName(cybozu::crypto::Cipher::Name cipherName, cybozu::crypto::Hash::Name hashName)
169
+ {
170
+ this->cipherName = cipherName;
171
+ this->hashName = hashName;
172
+
173
+ switch (cipherName) {
174
+ case cybozu::crypto::Cipher::N_AES128_CBC:
175
+ saltSize = 16;
176
+ blockSize = 16;
177
+ keyBits = 128;
178
+ cipherNameStr = "AES";
179
+ break;
180
+ case cybozu::crypto::Cipher::N_AES256_CBC:
181
+ saltSize = 16;
182
+ blockSize = 16;
183
+ keyBits = 256;
184
+ cipherNameStr = "AES";
185
+ break;
186
+ default:
187
+ throw cybozu::Exception("ms:CipherParam:not support cipherName") << cipherName;
188
+ }
189
+ if (saltSize == 0 || saltSize > 65536) throw cybozu::Exception("ms:CipherParam:setByName:bad saltSize") << saltSize;
190
+
191
+ switch (hashName) {
192
+ case cybozu::crypto::Hash::N_SHA1:
193
+ hashSize = 20;
194
+ hashNameStr = "SHA1";
195
+ break;
196
+ case cybozu::crypto::Hash::N_SHA256:
197
+ hashSize = 32;
198
+ hashNameStr = "SHA256";
199
+ break;
200
+ case cybozu::crypto::Hash::N_SHA384:
201
+ hashSize = 48;
202
+ hashNameStr = "SHA384";
203
+ break;
204
+ case cybozu::crypto::Hash::N_SHA512:
205
+ hashSize = 64;
206
+ hashNameStr = "SHA512";
207
+ break;
208
+ default:
209
+ throw cybozu::Exception("ms:CipherParam:setByName:not support hash") << hashName;
210
+ }
211
+ }
212
+ };
213
+
214
+ } // ms
215
+
216
+ #include "standard_encryption.hpp"
217
+
218
+ namespace ms {
219
+
220
+ #ifdef __GNUC__ // defined in sys/sysmacros.h
221
+ #undef major
222
+ #undef minor
223
+ #endif
224
+ struct EncryptionInfo {
225
+ int spinCount;
226
+ uint16_t major;
227
+ uint16_t minor;
228
+ cybozu::MiniXml xml;
229
+ CipherParam keyData;
230
+ std::string encryptedHmacKey;
231
+ std::string encryptedHmacValue;
232
+ CipherParam encryptedKey;
233
+ std::string encryptedVerifierHashInput;
234
+ std::string encryptedVerifierHashValue;
235
+ std::string encryptedKeyValue;
236
+ // for LibreOffice
237
+ bool isStandardEncryption;
238
+ EncryptionHeader seHeader;
239
+ EncryptionVerifier seVerifier;
240
+
241
+ EncryptionInfo()
242
+ : spinCount(0)
243
+ , major(0)
244
+ , minor(0)
245
+ , isStandardEncryption(false)
246
+ {
247
+ }
248
+ explicit EncryptionInfo(const std::string& data)
249
+ : spinCount(0)
250
+ , major(0)
251
+ , minor(0)
252
+ , isStandardEncryption(false)
253
+ {
254
+ if (data.size() < 8) {
255
+ throw cybozu::Exception("ms:EncryptionInfo:data.size") << data.size();
256
+ }
257
+ const char *p = &data[0];
258
+ major = cybozu::Get16bitAsLE(p + 0);
259
+ minor = cybozu::Get16bitAsLE(p + 2);
260
+ // [MS-OFFCRYPTO] 2.3.4.10
261
+ if (major == 4 && minor == 4) {
262
+ setAgileEncryptionInfo(data);
263
+ return;
264
+ }
265
+ if ((major == 3 || major == 4) && minor == 2) {
266
+ setStandardEncryptionInfo(data);
267
+ isStandardEncryption = true;
268
+ return;
269
+ }
270
+ throw cybozu::Exception("ms:EncryptionInfo:not support version") << major << minor;
271
+ }
272
+ void put() const
273
+ {
274
+ if (!isDebug(0)) return;
275
+ printf("major = %d\n", major);
276
+ printf("minor = %d\n", minor);
277
+ printf("isStandardEncryption = %d\n", isStandardEncryption);
278
+ if (isStandardEncryption) {
279
+ seHeader.put();
280
+ seVerifier.put();
281
+ } else {
282
+ printf("spinCount = %d\n", spinCount);
283
+ puts("keyData");
284
+ keyData.put();
285
+ printf("encryptedHmacKey = "); dump(encryptedHmacKey, false);
286
+ printf("encryptedHmacValue = "); dump(encryptedHmacValue, false);
287
+ puts("encryptedKey");
288
+ encryptedKey.put();
289
+ printf("encryptedVerifierHashInput = "); dump(encryptedVerifierHashInput, false);
290
+ printf("encryptedVerifierHashValue = "); dump(encryptedVerifierHashValue, false);
291
+ printf("encryptedKeyValue = "); dump(encryptedKeyValue, false);
292
+ }
293
+ }
294
+
295
+ void setStandardEncryptionInfo(const std::string& data)
296
+ {
297
+ const size_t encryptionHeaderSizePos = 8;
298
+ size_t dataSize = data.size();
299
+ const char *p = data.c_str();
300
+ if (dataSize < encryptionHeaderSizePos + 4) {
301
+ throw cybozu::Exception("ms:StandardEncryption2007Info:bad data size") << dataSize;
302
+ }
303
+ const uint32_t encryptionHeaderSize = cybozu::Get32bitAsLE(p + encryptionHeaderSizePos);
304
+ if (encryptionHeaderSize > dataSize) {
305
+ throw cybozu::Exception("ms:setStandardEncryptionInfo:bad size") << encryptionHeaderSize << dataSize;
306
+ }
307
+ p += encryptionHeaderSizePos + 4;
308
+ dataSize -= encryptionHeaderSizePos + 4;
309
+ seHeader.analyze(p, encryptionHeaderSize);
310
+ seHeader.put();
311
+
312
+ p += encryptionHeaderSize;
313
+ dataSize -= encryptionHeaderSize;
314
+ printf("dataSize=%u\n", (uint32_t)dataSize);
315
+ seVerifier.analyze(p, dataSize);
316
+ seVerifier.put();
317
+ }
318
+
319
+ void setAgileEncryptionInfo(const std::string& data)
320
+ {
321
+ const char *p = &data[0];
322
+ const uint32_t reserved = cybozu::Get32bitAsLE(p + 4);
323
+ MS_ASSERT_EQUAL(reserved, 0x40u);
324
+ xml.parse(p + 8, p + data.size());
325
+
326
+ // keyData
327
+ const cybozu::minixml::Node *keyDataNode = xml.get().getFirstTagByName("keyData");
328
+ if (keyDataNode == 0) throw cybozu::Exception("ms:EncryptionInfo:no keyData");
329
+ keyData.setByXml(keyDataNode);
330
+ // dataIntegrity
331
+ const cybozu::minixml::Node *dataIntegrity = xml.get().getFirstTagByName("dataIntegrity");
332
+ if (dataIntegrity == 0) throw cybozu::Exception("ms:EncryptionInfo:no dataIntegrity");
333
+ encryptedHmacKey = dec64(dataIntegrity->attr["encryptedHmacKey"]);
334
+ encryptedHmacValue = dec64(dataIntegrity->attr["encryptedHmacValue"]);
335
+
336
+ // keyEncryptor
337
+ const cybozu::minixml::Node *encryptedKeyNode = xml.get().getFirstTagByName("p:encryptedKey");
338
+ if (encryptedKeyNode == 0) throw cybozu::Exception("ms:EncryptionInfo:no p:encryptedKey");
339
+ encryptedKey.setByXml(encryptedKeyNode);
340
+ spinCount = cybozu::atoi(encryptedKeyNode->attr["spinCount"]);
341
+ encryptedVerifierHashInput = dec64(encryptedKeyNode->attr["encryptedVerifierHashInput"]);
342
+ encryptedVerifierHashValue = dec64(encryptedKeyNode->attr["encryptedVerifierHashValue"]);
343
+ encryptedKeyValue = dec64(encryptedKeyNode->attr["encryptedKeyValue"]);
344
+ }
345
+ std::string addHeader(const std::string& xmlStr) const
346
+ {
347
+ char buf[8];
348
+ const uint16_t major = 4;
349
+ const uint16_t minor = 4;
350
+ const uint32_t reserved = 0x40u;
351
+ cybozu::Set16bitAsLE(buf + 0, major);
352
+ cybozu::Set16bitAsLE(buf + 2, minor);
353
+ cybozu::Set32bitAsLE(buf + 4, reserved);
354
+ return std::string(buf, sizeof(buf)) + xmlStr;
355
+ }
356
+ std::string toXml(bool isOffice2013 = false) const
357
+ {
358
+ char buf[2048];
359
+ CYBOZU_SNPRINTF(buf, sizeof(buf),
360
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
361
+ "<encryption xmlns=\"http://schemas.microsoft.com/office/2006/encryption\""
362
+ " xmlns:p=\"http://schemas.microsoft.com/office/2006/keyEncryptor/password\""
363
+ // " xmlns:c=\"http://schemas.microsoft.com/office/2006/keyEncryptor/certificate\""
364
+ "%s"
365
+ ">"
366
+ "<keyData saltSize=\"%d\" blockSize=\"%d\" keyBits=\"%d\" hashSize=\"%d\""
367
+ " cipherAlgorithm=\"%s\" cipherChaining=\"ChainingModeCBC\" hashAlgorithm=\"%s\""
368
+ " saltValue=\"%s\"/>"
369
+ "<dataIntegrity encryptedHmacKey=\"%s\""
370
+ " encryptedHmacValue=\"%s\"/><keyEncryptors>"
371
+ "<keyEncryptor uri=\"http://schemas.microsoft.com/office/2006/keyEncryptor/password\">"
372
+ "<p:encryptedKey spinCount=\"%d\" saltSize=\"%d\" blockSize=\"%d\" keyBits=\"%d\" hashSize=\"%d\""
373
+ " cipherAlgorithm=\"%s\" cipherChaining=\"ChainingModeCBC\" hashAlgorithm=\"%s\""
374
+ " saltValue=\"%s\""
375
+ " encryptedVerifierHashInput=\"%s\""
376
+ " encryptedVerifierHashValue=\"%s\""
377
+ " encryptedKeyValue=\"%s\"/></keyEncryptor></keyEncryptors></encryption>",
378
+ isOffice2013 ? " xmlns:c=\"http://schemas.microsoft.com/office/2006/keyEncryptor/certificate\"" : "",
379
+ int(keyData.saltSize), int(keyData.blockSize), int(keyData.keyBits), int(keyData.hashSize),
380
+ keyData.cipherNameStr.c_str(), keyData.hashNameStr.c_str(),
381
+ enc64(keyData.saltValue).c_str(),
382
+ enc64(encryptedHmacKey).c_str(),
383
+ enc64(encryptedHmacValue).c_str(),
384
+ spinCount,
385
+ int(encryptedKey.saltSize), int(encryptedKey.blockSize), int(encryptedKey.keyBits), int(encryptedKey.hashSize),
386
+ encryptedKey.cipherNameStr.c_str(), encryptedKey.hashNameStr.c_str(),
387
+ enc64(encryptedKey.saltValue).c_str(),
388
+ enc64(encryptedVerifierHashInput).c_str(),
389
+ enc64(encryptedVerifierHashValue).c_str(),
390
+ enc64(encryptedKeyValue).c_str()
391
+ );
392
+ return buf;
393
+ }
394
+ };
395
+
396
+ inline std::string cipher(cybozu::crypto::Cipher::Name name, const char *msg, size_t msgLen, const std::string& key, const std::string& iv, cybozu::crypto::Cipher::Mode mode)
397
+ {
398
+ cybozu::crypto::Cipher cipher(name);
399
+ cipher.setup(mode, key, iv);
400
+
401
+ std::string ret;
402
+ ret.resize(msgLen + 128/* margin */);
403
+
404
+ const size_t roundMsgLen = msgLen & ~15;
405
+
406
+ if (roundMsgLen > 0) {
407
+ int writeSize = cipher.update(&ret[0], msg, (int)roundMsgLen);
408
+ if (writeSize < 0) {
409
+ throw cybozu::Exception("ms:cipher:update");
410
+ }
411
+ }
412
+ const int remainSize = int(msgLen - roundMsgLen);
413
+ if (remainSize > 0) {
414
+ std::string remain(msg + roundMsgLen, remainSize);
415
+ remain.resize(16);
416
+ int writeSize = cipher.update(&ret[roundMsgLen], &remain[0], 16);
417
+ if (writeSize < 0) {
418
+ throw cybozu::Exception("ms:cipher:update:remain");
419
+ }
420
+ ret.resize(roundMsgLen + 16);
421
+ } else {
422
+ ret.resize(msgLen);
423
+ }
424
+ return ret;
425
+ }
426
+
427
+ inline std::string cipher(cybozu::crypto::Cipher::Name name, const std::string& msg, const std::string& key, const std::string& iv, cybozu::crypto::Cipher::Mode mode)
428
+ {
429
+ return cipher(name, msg.c_str(), msg.size(), key, iv, mode);
430
+ }
431
+
432
+ inline std::string generateIv(const CipherParam& param, const std::string& blockKey, const std::string& salt)
433
+ {
434
+ std::string ret;
435
+ if (blockKey.empty()) {
436
+ ret = salt;
437
+ } else {
438
+ ret = cybozu::crypto::Hash::digest(param.hashName, salt + blockKey);
439
+ }
440
+ normalizeKey(ret, param.blockSize);
441
+ return ret;
442
+ }
443
+
444
+ /*
445
+ [MS-OFFCRYPTO] 2.3.4.11
446
+ */
447
+ inline std::string generateKey(const CipherParam& param, const std::string& hash, const std::string& blockKey)
448
+ {
449
+ std::string ret = cybozu::crypto::Hash::digest(param.hashName, hash + blockKey);
450
+ normalizeKey(ret, param.keyBits / 8);
451
+ return ret;
452
+ }
453
+
454
+ } // ms