LibreOfficeまたはOpenOfficeを用いて、Microsoft '.doc'、'.xls'ファイルへ、Java、C++、C#、Python、BeanShell、JavaScript、Basicから
話題
About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: Javaプログラミング言語
About: C++
About: Microsoft .NET Framework
About: Pythonプログラミング言語
About: LibreOffice Basic
About: Apache OpenOffice Basic
About: BeanShell
About: JavaScript
この記事の目次
- 開始コンテキスト
- ターゲットコンテキスト
- オリエンテーション
- 本体
- 1: 編集パスワードのハッシュを生成する
- 2: 1つのドキュメント格納プロパティをセットする
- 3: サンプルプログラムを実行する
- 4: 結びとその先
開始コンテキスト
- 読者は、UNOがサポートしているプログラミング言語群(Java、C++、Microsoft .NET Frameworkプログラミング言語群(C#およびVisual Basic.NET、ほとんどの場合)、Python、LibreOfficeまたはApache OpenOffice Basic、BeanShell、JavaScript)の1つの基本的知識を持っている。
- 読者は、UNOとは何か、UNOはLibreOfficeまたはApache OpenOfficeとどう関係しているかの知識を持っている。
- 読者は、UNOの基本的構成要素とそれらにこのシリーズで使われる用語体系の知識を持っている。
- 読者は、LibreOfficeまたはApache OpenOfficeのインスタンスへのUNOオブジェクト群コンテキストを取得する方法の知識(外部コンソールJava、C++、C#、Pythonプログラムでそうする方法についてのいくつかの記事があります。外部GUI Javaプログラムでそうする方法についての記事があります。外部GUI C++、C#、Pythonプログラムでそうする方法についての記事は以後、公開されます)を持っている。
- 読者は、UNOを用いて意図するドキュメントにアクセスしてそのドキュメントをファイルに格納する方法の知識を持っている(LibreOfficeまたはApache OpenOfficeをファイルコンバーターとして使用する方法についての記事(コンセプト、あるJava実装、あるC++実装、あるC#実装、あるPython実装、あるLibreOfficeまたはApache OpenOffice Basic実装)がその情報の大部分を含んでいます。
ターゲットコンテキスト
- 読者は、MicrosoftバイナリーWordまたはExcel('.doc'、'.xls')ファイルに編集パスワードを自分のプログラムからセットする方法を知る。
Hypothesizer 7、Objector 37A、Objector 37Bがコンピューターの前にいる。
オリエンテーション
Hypothesizer 7
本記事の第1パートでは、OpenDocumentフォーマットファイルに編集パスワードを私たちのプログラムからセットする方法を議論しました。
本記事の本パートでは、Microsoft OfficeバイナリーWordまたはExcelフォーマット('.doc'、'.xls')ファイルに編集パスワードを私たちのプログラムからセットする方法を知ります。
Objector 37A
実のところ、LibreOffice GUIは、編集パスワードを'.doc'ファイルに適切にセットしないんだよ。つまり、Microsoft Wordプログラムは、私が指定したパスワードではファイルを編集させてくれない。
Hypothesizer 7
サー、それはLibreOfficeのバグです。
Objector 37A
バグ?
Hypothesizer 7
はい。パスワードのハッシュを生成するロジックが間違っています。
Objector 37A
そのバグについて大勢が不平を言ったりしてないのか?そのバグは長いこと修正されず放置されてるようだが...
Hypothesizer 7
多分、その機能を欲している人が元々多くないのでしょう。
Objector 37A
なんで?
Hypothesizer 7
多分、編集パスワードは、ファイルが悪意をもって編集されるのを防ぐのにあまり効果的ではないからでしょう(本記事の第1パートの'オリエンテーション'で論じたように)、まあ、ファイルが意図せずに編集されるのを防ぐための措置としてある程度の有用性があると私は思いますが。もしくは、その旧式フォーマットはもうあまり使われていないというだけかもしれません。
Objector 37B
実のところ、私は、その機能を、もう固定されたものとしている一部のファイルを自分自身が誤って編集してしまうのを防ぐために使いたいわけ、それらのファイルを他人が触るとは全く想像してない自分のプライベートな環境でね。
Hypothesizer 7
マダム、それは妥当な使用法だと思います。
Objector 37A
とにかく、君が本記事で紹介する方法でもパスワードを適切にセットできないのかね?
Hypothesizer 7
実のところ、できます、あなたのプログラムがハッシュを正しく生成しますので。
Objector 37A
おお、それじゃあ、私のプログラムがハッシュを生成するのか...
Hypothesizer 7
はい、ハッシュ化ロジックが本記事のメインテーマです。
本体
1: 編集パスワードのハッシュを生成する
Hypothesizer 7
Officeドキュメントファイルに編集パスワードを設定することの面倒な部分は、編集パスワードのハッシュを生成することです。
実のところ、ハッシュ化アルゴリズムは、Microsoftバイナリーフォーマット毎に異なります。
以下は、'.doc'ファイル用のハッシュを生成する私のJavaファンクションです。
@Java ソースコード
package theBiasPlanet.unoUtilities.cryptography;
public class MicrosoftPasswordsHasher {
private static final int c_numberOfInitializationCodes = 15;
private static final short [] c_initializationCodes = new short [] {(short) 0xE1F0, (short) 0x1D0F, (short) 0xCC9C, (short) 0x84C0, (short) 0x110C, (short) 0x0E10, (short) 0xF1CE, (short) 0x313E, (short) 0x1872, (short) 0xE139, (short) 0xD40F, (short) 0x84F9, (short) 0x280C, (short) 0xA96A, (short) 0x4EC3};
private static final int c_numberOfEncryptionMatrixColumns = 7;
private static final short [] [] c_encryptionMatrix = new short [] [] {
{ (short) 0xAEFC, (short) 0x4DD9, (short) 0x9BB2, (short) 0x2745, (short) 0x4E8A, (short) 0x9D14, (short) 0x2A09},
{ (short) 0x7B61, (short) 0xF6C2, (short) 0xFDA5, (short) 0xEB6B, (short) 0xC6F7, (short) 0x9DCF, (short) 0x2BBF},
{ (short) 0x4563, (short) 0x8AC6, (short) 0x05AD, (short) 0x0B5A, (short) 0x16B4, (short) 0x2D68, (short) 0x5AD0},
{ (short) 0x0375, (short) 0x06EA, (short) 0x0DD4, (short) 0x1BA8, (short) 0x3750, (short) 0x6EA0, (short) 0xDD40},
{ (short) 0xD849, (short) 0xA0B3, (short) 0x5147, (short) 0xA28E, (short) 0x553D, (short) 0xAA7A, (short) 0x44D5},
{ (short) 0x6F45, (short) 0xDE8A, (short) 0xAD35, (short) 0x4A4B, (short) 0x9496, (short) 0x390D, (short) 0x721A},
{ (short) 0xEB23, (short) 0xC667, (short) 0x9CEF, (short) 0x29FF, (short) 0x53FE, (short) 0xA7FC, (short) 0x5FD9},
{ (short) 0x47D3, (short) 0x8FA6, (short) 0x8FA6, (short) 0x1EDA, (short) 0x3DB4, (short) 0x7B68, (short) 0xF6D0},
{ (short) 0xB861, (short) 0x60E3, (short) 0xC1C6, (short) 0x93AD, (short) 0x377B, (short) 0x6EF6, (short) 0xDDEC},
{ (short) 0x45A0, (short) 0x8B40, (short) 0x06A1, (short) 0x0D42, (short) 0x1A84, (short) 0x3508, (short) 0x6A10},
{ (short) 0xAA51, (short) 0x4483, (short) 0x8906, (short) 0x022D, (short) 0x045A, (short) 0x08B4, (short) 0x1168},
{ (short) 0x76B4, (short) 0xED68, (short) 0xCAF1, (short) 0x85C3, (short) 0x1BA7, (short) 0x374E, (short) 0x6E9C},
{ (short) 0x3730, (short) 0x6E60, (short) 0xDCC0, (short) 0xA9A1, (short) 0x4363, (short) 0x86C6, (short) 0x1DAD},
{ (short) 0x3331, (short) 0x6662, (short) 0xCCC4, (short) 0x89A9, (short) 0x0373, (short) 0x06E6, (short) 0x0DCC},
{ (short) 0x1021, (short) 0x2042, (short) 0x4084, (short) 0x8108, (short) 0x1231, (short) 0x2462, (short) 0x48C4}
};
public static int hashIn32bits (String a_originalDatum) {
int l_hash = 0;
int l_originalDatumLength = a_originalDatum.length ();
if (l_originalDatumLength > 0) {
if (l_originalDatumLength > c_numberOfInitializationCodes) {
l_originalDatumLength = c_numberOfInitializationCodes;
}
int l_highHash = c_initializationCodes [l_originalDatumLength - 1];
int l_lowHash = 0;
char l_character = 0x0000;
byte l_byte = 0x00;
byte l_highByte = 0x00;
byte l_lowByte = 0x00;
for (int l_characterIndex = 0; l_characterIndex < l_originalDatumLength; l_characterIndex ++) {
l_character = a_originalDatum.charAt (l_characterIndex);
l_highByte = (byte) (l_character >>> 8);
l_lowByte = (byte) (l_character & 0xFF);
l_byte = l_lowByte != 0x00 ? l_lowByte : l_highByte;
for (int l_matrixcolumnIndex = 0; l_matrixcolumnIndex < c_numberOfEncryptionMatrixColumns; l_matrixcolumnIndex ++) {
if ((l_byte & (1 << l_matrixcolumnIndex)) != 0) {
l_highHash = (short) (l_highHash ^ c_encryptionMatrix [c_numberOfInitializationCodes - l_originalDatumLength + l_characterIndex] [l_matrixcolumnIndex]);
}
}
l_character = a_originalDatum.charAt (l_originalDatumLength -1 - l_characterIndex);
l_highByte = (byte) (l_character >>> 8);
l_lowByte = (byte) (l_character & 0xFF);
l_byte = l_lowByte != 0x00 ? l_lowByte : l_highByte;
l_lowHash = ( ( (l_lowHash >>> 14) & 0x0001 ) | ( (l_lowHash << 1) & 0x7FFF)) ^ l_byte;
}
l_lowHash = ( ( (l_lowHash >>> 14) & 0x0001) | ( (l_lowHash << 1) & 0x7FFF)) ^ l_originalDatumLength ^ 0xCE4B;
l_hash = (l_highHash << 16) | l_lowHash;
}
return l_hash;
}
~
}
Objector 37B
...ハッシュは整数なの?
Hypothesizer 7
それは、32ビット群配列で、最終的にはUNO 'long'データになります。
Objector 37B
ふーん。
Hypothesizer 7
ご注意いただきたいのですが、'l_highHash'および'l_lowhHash'は本当は16ビット群配列ですが、Javaのビット群シフト操作は自動的に(余計なことに、私の意見では)任意の'short'データを'int'データに変換するので、それらに私は'int'変数群を使用します、'short'変数群ではなく。
Objector 37B
はあ?
Hypothesizer 7
例えば、私たちが'(0b1111111111111111 << 1) >>> 1'で欲しいのは、
'0b1111111111111111' ->
'0b1111111111111110' ->
'0b0111111111111111'
ですが、Javaが行なうのは、
'0b1111111111111111' ->
'0b11111111111111111111111111111111' ->
'0b11111111111111111111111111111110' ->
'0b01111111111111111111111111111111'であり、それは問題です。
Objector 37B
...最後尾16ビット群が正しければオーケーだけど、そうなってないってこと?
Hypothesizer 7
そのとおりです。そこで、私たちはそれを始めから'int'に入れて、以下のようにします
'0b00000000000000001111111111111111' ->
'0b00000000000000011111111111111110' ->
'0b00000000000000001111111111111111'。
Objector 37B
ああ、最後尾16ビット群が望みどおりになってるわね。
Hypothesizer 7
以下が、'.doc'ファイル用のハッシュを生成する私のC++、C#、Pythonファンクションです。
@C++ ソースコード
#ifndef __theBiasPlanet_unoUtilities_cryptography_MicrosoftPasswordsHasher_hpp__
#define __theBiasPlanet_unoUtilities_cryptography_MicrosoftPasswordsHasher_hpp__
#include <string>
using namespace ::std;
namespace theBiasPlanet {
namespace unoUtilities {
namespace cryptography {
class __theBiasPlanet_unoUtilities_symbolExportingOrImportingForVisualCplusplus__ MicrosoftPasswordsHasher {
private:
static int const c_numberOfInitializationCodes;
static unsigned short const c_initializationCodes [];
static int const c_numberOfEncryptionMatrixColumns = 7;
static unsigned short const c_encryptionMatrix [] [c_numberOfEncryptionMatrixColumns];
public:
static long hashIn32bits (string const & a_originalDatum);
~
};
}
}
}
#endif
#include "theBiasPlanet/unoUtilities/cryptography/MicrosoftPasswordsHasher.hpp"
namespace theBiasPlanet {
namespace unoUtilities {
namespace cryptography {
int const MicrosoftPasswordsHasher::c_numberOfInitializationCodes = 15;
unsigned short const MicrosoftPasswordsHasher::c_initializationCodes [] = {(unsigned short) 0xE1F0, (unsigned short) 0x1D0F, (unsigned short) 0xCC9C, (unsigned short) 0x84C0, (unsigned short) 0x110C, (unsigned short) 0x0E10, (unsigned short) 0xF1CE, (unsigned short) 0x313E, (unsigned short) 0x1872, (unsigned short) 0xE139, (unsigned short) 0xD40F, (unsigned short) 0x84F9, (unsigned short) 0x280C, (unsigned short) 0xA96A, (unsigned short) 0x4EC3};
int const MicrosoftPasswordsHasher::c_numberOfEncryptionMatrixColumns;
unsigned short const MicrosoftPasswordsHasher::c_encryptionMatrix [] [MicrosoftPasswordsHasher::c_numberOfEncryptionMatrixColumns] = {
{ (unsigned short) 0xAEFC, (unsigned short) 0x4DD9, (unsigned short) 0x9BB2, (unsigned short) 0x2745, (unsigned short) 0x4E8A, (unsigned short) 0x9D14, (unsigned short) 0x2A09},
{ (unsigned short) 0x7B61, (unsigned short) 0xF6C2, (unsigned short) 0xFDA5, (unsigned short) 0xEB6B, (unsigned short) 0xC6F7, (unsigned short) 0x9DCF, (unsigned short) 0x2BBF},
{ (unsigned short) 0x4563, (unsigned short) 0x8AC6, (unsigned short) 0x05AD, (unsigned short) 0x0B5A, (unsigned short) 0x16B4, (unsigned short) 0x2D68, (unsigned short) 0x5AD0},
{ (unsigned short) 0x0375, (unsigned short) 0x06EA, (unsigned short) 0x0DD4, (unsigned short) 0x1BA8, (unsigned short) 0x3750, (unsigned short) 0x6EA0, (unsigned short) 0xDD40},
{ (unsigned short) 0xD849, (unsigned short) 0xA0B3, (unsigned short) 0x5147, (unsigned short) 0xA28E, (unsigned short) 0x553D, (unsigned short) 0xAA7A, (unsigned short) 0x44D5},
{ (unsigned short) 0x6F45, (unsigned short) 0xDE8A, (unsigned short) 0xAD35, (unsigned short) 0x4A4B, (unsigned short) 0x9496, (unsigned short) 0x390D, (unsigned short) 0x721A},
{ (unsigned short) 0xEB23, (unsigned short) 0xC667, (unsigned short) 0x9CEF, (unsigned short) 0x29FF, (unsigned short) 0x53FE, (unsigned short) 0xA7FC, (unsigned short) 0x5FD9},
{ (unsigned short) 0x47D3, (unsigned short) 0x8FA6, (unsigned short) 0x8FA6, (unsigned short) 0x1EDA, (unsigned short) 0x3DB4, (unsigned short) 0x7B68, (unsigned short) 0xF6D0},
{ (unsigned short) 0xB861, (unsigned short) 0x60E3, (unsigned short) 0xC1C6, (unsigned short) 0x93AD, (unsigned short) 0x377B, (unsigned short) 0x6EF6, (unsigned short) 0xDDEC},
{ (unsigned short) 0x45A0, (unsigned short) 0x8B40, (unsigned short) 0x06A1, (unsigned short) 0x0D42, (unsigned short) 0x1A84, (unsigned short) 0x3508, (unsigned short) 0x6A10},
{ (unsigned short) 0xAA51, (unsigned short) 0x4483, (unsigned short) 0x8906, (unsigned short) 0x022D, (unsigned short) 0x045A, (unsigned short) 0x08B4, (unsigned short) 0x1168},
{ (unsigned short) 0x76B4, (unsigned short) 0xED68, (unsigned short) 0xCAF1, (unsigned short) 0x85C3, (unsigned short) 0x1BA7, (unsigned short) 0x374E, (unsigned short) 0x6E9C},
{ (unsigned short) 0x3730, (unsigned short) 0x6E60, (unsigned short) 0xDCC0, (unsigned short) 0xA9A1, (unsigned short) 0x4363, (unsigned short) 0x86C6, (unsigned short) 0x1DAD},
{ (unsigned short) 0x3331, (unsigned short) 0x6662, (unsigned short) 0xCCC4, (unsigned short) 0x89A9, (unsigned short) 0x0373, (unsigned short) 0x06E6, (unsigned short) 0x0DCC},
{ (unsigned short) 0x1021, (unsigned short) 0x2042, (unsigned short) 0x4084, (unsigned short) 0x8108, (unsigned short) 0x1231, (unsigned short) 0x2462, (unsigned short) 0x48C4}
};
}
}
}
#include "theBiasPlanet/unoUtilities/cryptography/MicrosoftPasswordsHasher.hpp"
#include <limits>
#include "theBiasPlanet/coreUtilities/stringsHandling/StringHandler.hpp"
using namespace ::theBiasPlanet::coreUtilities::stringsHandling;
namespace theBiasPlanet {
namespace unoUtilities {
namespace cryptography {
long MicrosoftPasswordsHasher::hashIn32bits (string const & a_originalDatum) {
unsigned long l_hash = 0;
u16string l_originalDatumInUtf16 = StringHandler::getUtf16String (a_originalDatum);
int l_originalDatumLength = l_originalDatumInUtf16.length ();
if (l_originalDatumLength > 0) {
if (l_originalDatumLength > c_numberOfInitializationCodes) {
l_originalDatumLength = c_numberOfInitializationCodes;
}
unsigned short l_highHash = c_initializationCodes [l_originalDatumLength - 1];
unsigned short l_lowHash = 0;
unsigned short l_character = 0x0000;
unsigned char l_byte = 0x00;
unsigned char l_highByte = 0x00;
unsigned char l_lowByte = 0x00;
for (int l_characterIndex = 0; l_characterIndex < l_originalDatumLength; l_characterIndex ++) {
l_character = l_originalDatumInUtf16 [l_characterIndex];
l_highByte = (unsigned char) (l_character >> 8);
l_lowByte = (unsigned char) (l_character & 0xFF);
l_byte = l_lowByte != 0x00 ? l_lowByte : l_highByte;
for (int l_matrixcolumnIndex = 0; l_matrixcolumnIndex < c_numberOfEncryptionMatrixColumns; l_matrixcolumnIndex ++) {
if ((l_byte & (1 << l_matrixcolumnIndex)) != 0) {
l_highHash = (unsigned short) (l_highHash ^ c_encryptionMatrix [c_numberOfInitializationCodes - l_originalDatumLength + l_characterIndex] [l_matrixcolumnIndex]);
}
}
l_character = l_originalDatumInUtf16 [l_originalDatumLength -1 - l_characterIndex];
l_highByte = (unsigned char) (l_character >> 8);
l_lowByte = (unsigned char) (l_character & 0xFF);
l_byte = l_lowByte != 0x00 ? l_lowByte : l_highByte;
l_lowHash = ( ( (l_lowHash >> 14) & 0x0001 ) | ( (l_lowHash << 1) & 0x7FFF)) ^ l_byte;
}
l_lowHash = ( ( (l_lowHash >> 14) & 0x0001) | ( (l_lowHash << 1) & 0x7FFF)) ^ l_originalDatumLength ^ 0xCE4B;
l_hash = (l_highHash << 16) | l_lowHash;
}
return (long) l_hash;
}
~
}
}
}
@C# ソースコード
namespace theBiasPlanet {
namespace unoUtilities {
namespace cryptography {
using System;
using System.Text;
public class MicrosoftPasswordsHasher {
private const int c_numberOfInitializationCodes = 15;
private static readonly ushort [] c_initializationCodes = new ushort [] {(ushort) 0xE1F0, (ushort) 0x1D0F, (ushort) 0xCC9C, (ushort) 0x84C0, (ushort) 0x110C, (ushort) 0x0E10, (ushort) 0xF1CE, (ushort) 0x313E, (ushort) 0x1872, (ushort) 0xE139, (ushort) 0xD40F, (ushort) 0x84F9, (ushort) 0x280C, (ushort) 0xA96A, (ushort) 0x4EC3};
private const int c_numberOfEncryptionMatrixColumns = 7;
private static readonly ushort [, ] c_encryptionMatrix = new ushort [, ] {
{ (ushort) 0xAEFC, (ushort) 0x4DD9, (ushort) 0x9BB2, (ushort) 0x2745, (ushort) 0x4E8A, (ushort) 0x9D14, (ushort) 0x2A09},
{ (ushort) 0x7B61, (ushort) 0xF6C2, (ushort) 0xFDA5, (ushort) 0xEB6B, (ushort) 0xC6F7, (ushort) 0x9DCF, (ushort) 0x2BBF},
{ (ushort) 0x4563, (ushort) 0x8AC6, (ushort) 0x05AD, (ushort) 0x0B5A, (ushort) 0x16B4, (ushort) 0x2D68, (ushort) 0x5AD0},
{ (ushort) 0x0375, (ushort) 0x06EA, (ushort) 0x0DD4, (ushort) 0x1BA8, (ushort) 0x3750, (ushort) 0x6EA0, (ushort) 0xDD40},
{ (ushort) 0xD849, (ushort) 0xA0B3, (ushort) 0x5147, (ushort) 0xA28E, (ushort) 0x553D, (ushort) 0xAA7A, (ushort) 0x44D5},
{ (ushort) 0x6F45, (ushort) 0xDE8A, (ushort) 0xAD35, (ushort) 0x4A4B, (ushort) 0x9496, (ushort) 0x390D, (ushort) 0x721A},
{ (ushort) 0xEB23, (ushort) 0xC667, (ushort) 0x9CEF, (ushort) 0x29FF, (ushort) 0x53FE, (ushort) 0xA7FC, (ushort) 0x5FD9},
{ (ushort) 0x47D3, (ushort) 0x8FA6, (ushort) 0x8FA6, (ushort) 0x1EDA, (ushort) 0x3DB4, (ushort) 0x7B68, (ushort) 0xF6D0},
{ (ushort) 0xB861, (ushort) 0x60E3, (ushort) 0xC1C6, (ushort) 0x93AD, (ushort) 0x377B, (ushort) 0x6EF6, (ushort) 0xDDEC},
{ (ushort) 0x45A0, (ushort) 0x8B40, (ushort) 0x06A1, (ushort) 0x0D42, (ushort) 0x1A84, (ushort) 0x3508, (ushort) 0x6A10},
{ (ushort) 0xAA51, (ushort) 0x4483, (ushort) 0x8906, (ushort) 0x022D, (ushort) 0x045A, (ushort) 0x08B4, (ushort) 0x1168},
{ (ushort) 0x76B4, (ushort) 0xED68, (ushort) 0xCAF1, (ushort) 0x85C3, (ushort) 0x1BA7, (ushort) 0x374E, (ushort) 0x6E9C},
{ (ushort) 0x3730, (ushort) 0x6E60, (ushort) 0xDCC0, (ushort) 0xA9A1, (ushort) 0x4363, (ushort) 0x86C6, (ushort) 0x1DAD},
{ (ushort) 0x3331, (ushort) 0x6662, (ushort) 0xCCC4, (ushort) 0x89A9, (ushort) 0x0373, (ushort) 0x06E6, (ushort) 0x0DCC},
{ (ushort) 0x1021, (ushort) 0x2042, (ushort) 0x4084, (ushort) 0x8108, (ushort) 0x1231, (ushort) 0x2462, (ushort) 0x48C4}
};
public static int hashIn32bits (String a_originalDatum) {
uint l_hash = 0;
int l_originalDatumLength = a_originalDatum.Length;
if (l_originalDatumLength > 0) {
if (l_originalDatumLength > c_numberOfInitializationCodes) {
l_originalDatumLength = c_numberOfInitializationCodes;
}
ushort l_highHash = c_initializationCodes [l_originalDatumLength - 1];
ushort l_lowHash = 0;
char l_character = (char) 0x0000;
byte l_byte = 0x00;
byte l_highByte = 0x00;
byte l_lowByte = 0x00;
for (int l_characterIndex = 0; l_characterIndex < l_originalDatumLength; l_characterIndex ++) {
l_character = a_originalDatum [l_characterIndex];
l_highByte = (byte) (l_character >> 8);
l_lowByte = (byte) (l_character & 0xFF);
l_byte = l_lowByte != 0x00 ? l_lowByte : l_highByte;
for (int l_matrixcolumnIndex = 0; l_matrixcolumnIndex < c_numberOfEncryptionMatrixColumns; l_matrixcolumnIndex ++) {
if ((l_byte & (1 << l_matrixcolumnIndex)) != 0) {
l_highHash = (ushort) (l_highHash ^ c_encryptionMatrix [c_numberOfInitializationCodes - l_originalDatumLength + l_characterIndex, l_matrixcolumnIndex]);
}
}
l_character = a_originalDatum [l_originalDatumLength -1 - l_characterIndex];
l_highByte = (byte) (l_character >> 8);
l_lowByte = (byte) (l_character & 0xFF);
l_byte = l_lowByte != 0x00 ? l_lowByte : l_highByte;
l_lowHash = (ushort) (( ( (l_lowHash >> 14) & 0x0001 ) | ( (l_lowHash << 1) & 0x7FFF)) ^ l_byte);
}
l_lowHash = (ushort) (( ( (l_lowHash >> 14) & 0x0001) | ( (l_lowHash << 1) & 0x7FFF)) ^ l_originalDatumLength ^ 0xCE4B);
l_hash = (uint) ((l_highHash << 16) | l_lowHash);
}
return (int) l_hash;
}
~
}
}
}
}
@Python ソースコード
from typing import List
class MicrosoftPasswordsHasher:
c_numberOfInitializationCodes: int = 15
c_initializationCodes: List [int] = [0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3]
c_numberOfEncryptionMatrixColumns: int = 7
c_encryptionMatrix: List [List [int]] = [
[ 0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09],
[ 0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF],
[ 0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0],
[ 0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40],
[ 0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5],
[ 0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A],
[ 0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9],
[ 0x47D3, 0x8FA6, 0x8FA6, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0],
[ 0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC],
[ 0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10],
[ 0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168],
[ 0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C],
[ 0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD],
[ 0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC],
[ 0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4]
]
@staticmethod
def hashIn32bits (a_originalDatum: str) -> int:
l_hash: int = 0
l_originalDatumLength: int = len (a_originalDatum)
if l_originalDatumLength > 0:
if l_originalDatumLength > MicrosoftPasswordsHasher.c_numberOfInitializationCodes:
l_originalDatumLength = MicrosoftPasswordsHasher.c_numberOfInitializationCodes
l_highHash: int = MicrosoftPasswordsHasher.c_initializationCodes [l_originalDatumLength - 1]
l_lowHash: int = 0
l_character: int = 0x0000
l_byte: int = 0x00
l_highByte: int = 0x00
l_lowByte: int = 0x00
l_characterIndex: int = 0
for l_characterIndex in range (0, l_originalDatumLength, 1):
l_character = ord (a_originalDatum [l_characterIndex])
l_highByte = (l_character >> 8)
l_lowByte = (l_character & 0xFF)
l_byte = l_lowByte if l_lowByte != 0x00 else l_highByte
l_matrixcolumnIndex: int = 0
for l_matrixcolumnIndex in range (0, MicrosoftPasswordsHasher.c_numberOfEncryptionMatrixColumns, 1):
if (l_byte & (1 << l_matrixcolumnIndex)) != 0:
l_highHash = (l_highHash ^ MicrosoftPasswordsHasher.c_encryptionMatrix [MicrosoftPasswordsHasher.c_numberOfInitializationCodes - l_originalDatumLength + l_characterIndex] [l_matrixcolumnIndex])
l_character = ord (a_originalDatum [l_originalDatumLength -1 - l_characterIndex])
l_highByte = (l_character >> 8)
l_lowByte = (l_character & 0xFF)
l_byte = l_lowByte if l_lowByte != 0x00 else l_highByte
l_lowHash = ( ( (l_lowHash >> 14) & 0x0001 ) | ( (l_lowHash << 1) & 0x7FFF)) ^ l_byte
l_lowHash = ( ( (l_lowHash >> 14) & 0x0001) | ( (l_lowHash << 1) & 0x7FFF)) ^ l_originalDatumLength ^ 0xCE4B
l_hash = (l_highHash << 16) | l_lowHash
return l_hash
~
Objector 37B
ふーん。
Hypothesizer 7
他方では、以下が、'.xls'ファイル用のハッシュを生成する私のJavaファンクションです。
@Java ソースコード
package theBiasPlanet.unoUtilities.cryptography;
public class MicrosoftPasswordsHasher {
~
public static short hashIn16bits (String a_originalDatum) {
int l_hash = 0;
byte [] l_originalDatumUtf8BytesArray = null;
try {
l_originalDatumUtf8BytesArray = a_originalDatum.getBytes ("UTF-8");
}
catch (Exception l_exception) {
// Is supposed to never happen.
}
int l_originalDatumUtf8BytesArrayLength = l_originalDatumUtf8BytesArray.length;
if (l_originalDatumUtf8BytesArrayLength <= Short.MAX_VALUE) {
for (int l_byteIndex = l_originalDatumUtf8BytesArrayLength - 1; l_byteIndex >= 0; l_byteIndex --) {
l_hash = ( (l_hash >>> 14) & 0x01) | ( (l_hash << 1) & 0x7FFF);
l_hash ^= l_originalDatumUtf8BytesArray [l_byteIndex];
}
l_hash = ( (l_hash >>> 14) & 0x01) | ( (l_hash << 1) & 0x7FFF);
l_hash ^= (0x8000 | ('N' << 8) | 'K');
l_hash ^= l_originalDatumUtf8BytesArrayLength;
}
return (short) l_hash;
}
}
Objector 37B
...今回は、ハッシュは16ビット群配列ってこと?
Hypothesizer 7
はい、しかし、それも最終的にはUNO 'long'データになります。
Objector 37B
それじゃあ、その'long'データの前部16ビット群は全'0'にするってこと?
Hypothesizer 7
はい。
この場合も、'l_hash'は本当は16ビット群配列ですが、私は'int'変数を使用します、上に挙げられたのと同じ理由のために。
Objector 37B
もちろん。
Hypothesizer 7
以下が、'.xls'ファイル用のハッシュを生成する私のC++、C#、Pythonファンクションです。
@C++ ソースコード
#ifndef __theBiasPlanet_unoUtilities_cryptography_MicrosoftPasswordsHasher_hpp__
#define __theBiasPlanet_unoUtilities_cryptography_MicrosoftPasswordsHasher_hpp__
#include <string>
#include "theBiasPlanet/unoUtilities/visualCplusplusSpecificHeaders/VisualCplusplusSpecificDefinitions.hpp"
using namespace ::std;
namespace theBiasPlanet {
namespace unoUtilities {
namespace cryptography {
class __theBiasPlanet_unoUtilities_symbolExportingOrImportingForVisualCplusplus__ MicrosoftPasswordsHasher {
private:
~
public:
~
static short hashIn16bits (string const & a_originalDatum);
};
}
}
}
#endif
#include "theBiasPlanet/unoUtilities/cryptography/MicrosoftPasswordsHasher.hpp"
#include <limits>
#include "theBiasPlanet/coreUtilities/stringsHandling/StringHandler.hpp"
using namespace ::theBiasPlanet::coreUtilities::stringsHandling;
namespace theBiasPlanet {
namespace unoUtilities {
namespace cryptography {
~
short MicrosoftPasswordsHasher::hashIn16bits (string const & a_originalDatum) {
unsigned short l_hash = 0;
int l_originalDatumLength = a_originalDatum.length ();
if (l_originalDatumLength <= numeric_limits <short>::max ()) {
for (int l_byteIndex = l_originalDatumLength - 1; l_byteIndex >= 0; l_byteIndex --) {
l_hash = ( (l_hash >> 14) & 0x01) | ( (l_hash << 1) & 0x7FFF);
l_hash ^= a_originalDatum [l_byteIndex];
}
l_hash = ( (l_hash >> 14) & 0x01) | ( (l_hash << 1) & 0x7FFF);
l_hash ^= (0x8000 | ('N' << 8) | 'K');
l_hash ^= l_originalDatumLength;
}
return (short) l_hash;
}
}
}
}
@C# ソースコード
namespace theBiasPlanet {
namespace unoUtilities {
namespace cryptography {
using System;
using System.Text;
public class MicrosoftPasswordsHasher {
~
public static short hashIn16bits (String a_originalDatum) {
ushort l_hash = 0;
byte [] l_originalDatumUtf8BytesArray = null;
try {
l_originalDatumUtf8BytesArray = Encoding.UTF8.GetBytes (a_originalDatum);
}
catch (Exception l_exception) {
// Is supposed to never happen.
}
int l_originalDatumUtf8BytesArrayLength = l_originalDatumUtf8BytesArray.Length;
if (l_originalDatumUtf8BytesArrayLength <= Int16.MaxValue) {
for (int l_byteIndex = l_originalDatumUtf8BytesArrayLength - 1; l_byteIndex >= 0; l_byteIndex --) {
l_hash = (ushort) (( (l_hash >> 14) & 0x01) | ( (l_hash << 1) & 0x7FFF));
l_hash ^= l_originalDatumUtf8BytesArray [l_byteIndex];
}
l_hash = (ushort) (( (l_hash >> 14) & 0x01) | ( (l_hash << 1) & 0x7FFF));
l_hash ^= (0x8000 | ('N' << 8) | 'K');
l_hash ^= (ushort) l_originalDatumUtf8BytesArrayLength;
}
return (short)l_hash;
}
}
}
}
}
@Python ソースコード
from typing import List
class MicrosoftPasswordsHasher:
~
@staticmethod
def hashIn16bits (a_originalDatum: str) -> int:
l_hash: int = 0
l_originalDatumUtf8BytesArray: bytes = b''
try:
l_originalDatumUtf8BytesArray = a_originalDatum.encode (UTF-8)
except (Exception) as l_exception:
# Is supposed to never happen.
None
l_originalDatumUtf8BytesArrayLength: int = len (l_originalDatumUtf8BytesArray)
if l_originalDatumUtf8BytesArrayLength <= 2**15 - 1:
l_byteIndex: int = 0
for l_byteIndex in range (l_originalDatumUtf8BytesArrayLength - 1, 0 - 1, -1):
l_hash = ( (l_hash >> 14) & 0x01) | ( (l_hash << 1) & 0x7FFF)
l_hash ^= l_originalDatumUtf8BytesArray [l_byteIndex]
l_hash = ( (l_hash >> 14) & 0x01) | ( (l_hash << 1) & 0x7FFF)
l_hash ^= (0x8000 | (ord ('N') << 8) | ord ('K'))
l_hash ^= l_originalDatumUtf8BytesArrayLength
return l_hash
Objector 37B
あなたの'話題'に挙げられてる他の言語の実装はどうなったの?
Hypothesizer 7
それらは、それらを欲しい方にお任せします。
Objector 37B
...
2: 1つのドキュメント格納プロパティをセットする
Hypothesizer 7
セットすべきドキュメント群プロパティは'ModifyPasswordInfo'です(OpenDocumentフォーマット群の場合と同じく)、しかし今回は、値はUNO 'long'データです。
Javaにおいては、そのプロパティに、前セクションで得られたハッシュをただ入れればいいだけです。
C++およびC#においては、前セクションで得られたハッシュをUNO 'Any'にラップして、そのUNO 'Any'データをプロパティに入れます。
Pythonにおいては、前セクションで得られたハッシュの'signed long'('.doc'フォーマットの場合)または'signed short'('.xls'フォーマットの場合)データを取得し、その符号付きデータをUNO 'Any'にラップし、そのUNO 'Any'データをプロパティに入れます。
Objector 37A
はあ?なんでPythonの場合だけそんな大騒ぎをするのか?
Hypothesizer 7
それは、前セクションにて私たちは望みのビット群配列をハッシュ'int'データの中へセットしましたが、UNOはそのビット群配列そのものではなく、'int'変数の数字値を見るからです。
Objector 37A
はあ?
Hypothesizer 7
例えば、ハッシュ'int'データの中に'0xFFFFFFFF'をセットしたとすると、それは、'-1'ではなく、'4294967295'であり、それは、'long'の範囲になく、エラーを起こします。したがって、私たちは'4294967295'を'-1'に変換しなければならず、それがUNOにおいて'0xFFFFFFFF'になります。
Objector 37A
ふーむ...まあいいけど。
3: サンプルプログラムを実行する
Hypothesizer 7
実は、編集パスワードをセットする機能は、ある以前の記事(コンセプト、あるJava実装、あるC++実装、あるC#実装、あるPython実装)で紹介されたファイルコンバージョンサンプルプログラムに実装されています。
当該プロジェクトを入手・ビルドする方法およびプログラム群を実行する方法は、上記以前の記事に記述されており、編集パスワードをセットするためのファイルコンバージョン命令CSVファイル仕様は、本記事の第1パートに記述されています。
4: 結びとその先
Hypothesizer 7
これで、MicrosoftバイナリーWordまたはExcel('.doc'または'.xls')ファイルに編集パスワードを私たちのプログラムからセットする方法を知りました。
編集パスワードがいかなる目的のためにどれだけ効果的であるかを意識する必要がありますが、実際的に妥当なユースケースはいくらかあるでしょう。
Office Open XMLフォーマットファイルに編集パスワードを私たちのプログラムからセットする方法を、本記事の次のパートで見ましょう。