DanaにRC4暗号化機能を組み込むマクロ.ファイルを開くときと保存するときにperlの外部プログラムを呼び出すことで,特別な操作不要で暗号化保存できるようにした.

Danaに暗号化を組み込む

訳あって,テキストファイルを暗号化して保存したくなった.色々考えたが,テキストエディタに暗号化保存の機能があれば便利だ. そこで,常用しているテキストエディタ(Dana)に,暗号化保存の機能を持たせることにした.

Dana Scriptマクロを使って実装するが,暗号化処理は荷が重いので,別途perlで作った. 暗号化のアルゴリズムには,普段使い慣れていてお手軽な,Crypt::RC4を使った.

 Dana → Dana Script → Perl外部プログラム(暗号化にはCrypt::RC4を利用)

1.インストール

ファイルの配置

必要なもの
  • Perl (Active Perlとか)
  • Crypt::RC4
  • このページの末尾にある Angou.das と Angou.pl

Crypt::RC4が使える状態のPerl環境が必要. とは言っても,Crypt::RC4自体は,Perlのlib\ の下にCryptというディレクトリを作って,そこにダウンロードしてきたRC4.pmを置くだけですむはず.

そして,Angou.das と Angou.pl を,Dane.exeがインストールされているディレクトリに置けば良い.

Danaの設定

「ツール」-「設定」の,「組込スクリプト」タブで,スクリプト名Angouを登録すればよい.
dana_crypt1.png

2.使い方

暗号化モードの設定

暗号化して保存したいファイルを開いた状態で,「ツール」-「暗号化」を実行し,出てくるメニューで,
dana_crypt2.png

「ファイルを暗号化に設定する(E)」を選択すると,そのファイルは暗号化保存のモードになります. なお,このとき暗号化保存の目印のために,先頭行に

 @SAngou[PLAIN]
という文字列が挿入されます.これが暗号化モードの情報ですので,これを消すと暗号化保存されなくなってしまいますのでご注意.

プログラムソースなど,余計な文字列が入るとまずい場合は,コメント行にするなどして回避してください.例えばPerlだと,# でコメント行なので,

 # @SAngou[PLAIN]
として回避できます.

保存する

この状態でファイルを保存しようとすると,暗号化キーを入力するダイアログが出ます.(「パラメータを入力」)
dana_crypt3.png

ここで暗号化のキーを入力すると,ファイルが暗号で保存されます.開くときは,これと同じキーを入力してファイルを復号化することになります.

暗号保存されたファイルの例

@SAngou
37518713d607b600ee8748cf99f2c9b43f7e2a919f92c7387b3ca49a3b9b8975969652
c9d74e362d1a574b6187e0e383f8818c5182af346e8a8d5fd08340f277253ed7c5bb05
7d48f13ac457d1e519b45e67090f9ace42e2075a34201f700f927b7c4424b814861f4c
・・・
このように,実際にディスクに保存されるのは,ファイルの内容をキーを使ってRC4アルゴリズムで暗号化した結果を,16進数で出力したものになります.

開く

こうして暗号保存されたファイルをDanaで開こうとすると,保存時と同じように暗号化キーを入力するダイアログが出ます.

ここで保存時と同じキーを入力すれば,正しく復号化されてDana上に表示されます. 間違ったキーを入力した場合は,ハナモゲラが表示されます.もし保存したときのキーを忘れてしまうと,復元不可能,ゲームオーバーです.

3.よくあるトラブル

  • 暗号化されない - perl.exeにパスが通っていない.PATHを通すか,Angou.dasの記述を修正する.ENCRYPT_PROGRAM,DECRYPT_PROGRAMに代入している"perl.exe"を,フルパスで記述する

4.その他

RC4よりもっと強力な暗号化アルゴリズム(AESとか)を使ったAngou.plを作って,これと差し替えれば,さらに強力な暗号化ができますなぁ.

また,暗号化されているとは言っても,ブルートフォースでガシガシ計算されればそのうち解読されるでしょうから, 過度に期待するのは禁物です.あまり重要な用途には使わないのが安全だと思います.

5.ソース

Angou.das
'
' 暗号化スクリプト for Dana
'

Const STATE_INIT        = 0
Const STATE_WHO_ARE_YOU = 14
Const STATE_CALL_MENU   = 13
Const STATE_BEFORE_SAVE = 4
Const STATE_AFTER_SAVE  = 5
Const STATE_TIMER       = 11

Const T_SET_ANGOU = 100
Const T_RESET_ANGOU = 101
Const T_EXIT     = 999

Const ANGOU_TOPLINE = "@SAngou"

Dim hMenu%
Dim plain$
Dim angouFlg%
Dim initialized%

Dim ENCRYPT_PROGRAM$
Dim DECRYPT_PROGRAM$
Dim TMPFILE$

Main ()
	Select Case .DanaState
	Case STATE_INIT
		' 暗号化/復号化外部プログラムのフルパス
		' 暗号化/復号化外部プログラムは,以下の仕様を満たす必要がある
		'  %1 : 秘密鍵文字列
		'  %2 : 入力ファイル名
		'  %3 : 出力ファイル名 (処理に失敗した場合は,作成してはいけない)
		ENCRYPT_PROGRAM = "perl.exe " + Chr(34) + .HomePath + "Angou.pl" + Chr(34) + " E"
		DECRYPT_PROGRAM = "perl.exe " + Chr(34) + .HomePath + "Angou.pl" + Chr(34) + " D"

		TMPFILE = Environ("TEMP") + "\Angou_das.tmp"

		hMenu% = NewMenu()
		AddMenuItem(hMenu%, "ファイルを暗号化に設定する(&E)", T_SET_ANGOU)
		AddMenuItem(hMenu%, "ファイルの暗号化を解除する(&D)", T_RESET_ANGOU)
		AddMenuItem(hMenu%, "暗号化アドインの終了(&X)", T_EXIT)

		StayResident()

	Case STATE_WHO_ARE_YOU
		.ParmStrA = "Angou Script ver1.00/by kamoland.com"

	Case STATE_CALL_MENU
		OnCallMenu()

	Case STATE_BEFORE_SAVE
		OnBeforeSave(.ParmStrA)

	Case STATE_AFTER_SAVE
		OnAfterSave(.ParmStrA)

	Case STATE_TIMER
		OnTimer()

	Case Else
	End Select

End

' Before save file Event
Proc OnBeforeSave(strName$)
	angouFlg% = isAngouFile()

	if angouFlg% = TRUE then
		' 暗号化フラグがONの場合は,暗号化して保存する
		FKill(TMPFILE)
		Command("SelectAll")
		plain$ = GetSelected()
		ShellCmd(ENCRYPT_PROGRAM + " %I %T " + TMPFILE, "I")

		if Dir(TMPFILE) <> "" then
			PasteFromFile(TMPFILE)
			Command("TextTop")
			InsertString(ANGOU_TOPLINE + Chr(&H0D) + Chr(&H0A))
			FKill(TMPFILE)
		else
			' tmpfileが作成されなかった場合は,プロンプトでキャンセルされたので
			' 保存してはいけない
			.ParmA = 0
			return
		end if
	end if
End Proc

' After save file Event
Proc OnAfterSave(strName$)
	if angouFlg% = TRUE then
		' 平文に戻す
		Command("SelectAll")
		DelSelect()
		Command("TextTop")
		InsertString(plain$)
		' 編集フラグをOFFにする
		SetModified(False)
	end if
End Proc

' 1 second interval Event
Proc OnTimer()
	if initialized% = FALSE then
		OpenWithDecrypt()
	end if

End Proc

' Menu call Event
Proc OnCallMenu()
	Dim nRC%
	nRC = DoMenu(hMenu%)
	Select Case nRC
	Case T_SET_ANGOU
		if isAngouFile() = FALSE then
			Command("TextTop")
			InsertString(ANGOU_TOPLINE + "[PLAIN]" + Chr(&H0D) + Chr(&H0A))
		else
			msgbox("このファイルは既に暗号化モードです")
		end if

	Case T_RESET_ANGOU
		if isAngouFile() = TRUE then
			Command("TextTop")
			Command("DeleteLine")
		else
			msgbox("このファイルは暗号化モードではありません")
		end if

	Case T_EXIT
		DiscardMenu(hMenu%)
		Terminate()
	End Select
End Proc

' 開いたファイルが暗号化ファイルの場合は,復号化する
Proc OpenWithDecrypt()
	if initialized% = TRUE then
		return
	end if
	initialized% = TRUE

	if isAngouFile() = TRUE then
		' 先頭行は,識別用なので削除する
		Command("TextTop")
		Command("DeleteLine")

		' ファイルを復号化する
		FKill(TMPFILE)
		Command("SelectAll")
		ShellCmd(DECRYPT_PROGRAM + " %I %T " + TMPFILE, "I")

		' 復号化に成功した場合は,結果を貼り付ける
		if Dir(TMPFILE) <> "" then
			PasteFromFile(TMPFILE)
			FKill(TMPFILE)
		end if

		' 編集フラグをOFFに戻す
		SetModified(False)

		Command("TextTop")
	end if

End Proc

' ファイルの先頭行を調べて,暗号化ファイルかどうかを判定する
Proc isAngouFile()
	Dim angou%
	Dim top$

	top$ = LoadThisLine(GetTopLine())
	if InstrMB(top$, ANGOU_TOPLINE) > 0 then
		angou% = TRUE
	else
		angou% = FALSE
	end if

	return angou%
End Proc

Angou.pl

#!/usr/bin/perl

use strict;
use Crypt::RC4;

my($mode, $pass, $in_fname, $out_fname) = @ARGV;

my $in = '';
open(IN, $in_fname) or die "Can't open $in_fname $!\n";
while (<IN>) {
	$in .= $_;
}
close(IN);

my $out = '';
if (lc $mode eq 'e') {
	my $hex = RC4_hex($pass, $in);
	my $width = 70;
	for (my $i = 0; $i < length($hex); $i += $width) {
		$out .= substr($hex, $i, $width)."\n";
	}
} elsif (lc $mode eq 'd') {
	$in =~ s/\r//g;
	$in =~ s/\n//g;
	$out = RC4_dec_hex($pass, $in);
} else {
	die "Invalid mode\n";
}

open(OUT, ">$out_fname") or die "Can't open $out_fname $!\n";
print OUT $out;
close(OUT);

sub RC4_hex {
	my($pass, $plain) = @_;

	my $encbin = RC4($pass, $plain);
	my(@enchex) = ();
	foreach (split(//,$encbin)) {
		push(@enchex, unpack("h2",$_));
	}
	return join('',@enchex);
}

sub RC4_dec_hex {
	my($pass, $enchex) = @_;

	my(@encbin) = ();
	while (length($enchex) > 0) {
		push(@encbin, pack("h2", $enchex));
		$enchex = substr($enchex, 2);
	}

	my $dec = RC4($pass, join('', @encbin));
	return $dec;
}
kamolandをフォローしましょう


© 2019 KMIソフトウェア