// 参考:
// http://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%8B%E3%82%B0%E3%83%9E_(%E6%9A%97%E5%8F%B7%E6%A9%9F)
// http://www.infonet.co.jp/ueyama/ip/history/enigma.html
unit enigmaunit;
interface
uses
Classes, SysUtils;
const
// 利用できる文字種:
// ・文字種は偶数でなくてはならない。
// (リフレクタを使う構造上の制限)
// ・オリジナルのエニグマで利用できる文字種は'A'..'Z'の26文字だが、
// このユニットでは"0x20..0x7e" + 0x09(TAB)の96文字が使える。
CHAR_MAX = 96;
// ロータの数:
// ・ロータを増やす場合にはRotors配列を増やし、ROTOR_MAX定数を増やす必要がある。
// ・"ロータ数=キーの長さ"となる。
// ・ロータ数は任意
ROTOR_MAX = 3;
// エンコード&デコード
function Exec_Enigma(Src, Key: String): String;
// ロータ用テーブル生成
function Genareate_Rotor: String;
// ロータ用テーブル生成
function Genareate_Refrector: String;
// キーの自動生成
function GenarateKey: String;
implementation
{ Char2Index Begin }
function Char2Index(C: Char): Byte;
begin
if C = #$09 then
result := $5F
else
result := Ord(C) - $20;
end;
{ Char2Index End }
{ Index2Char Begin }
function Index2Char(B: Byte): Char;
begin
if B = $5F then
result := #$09
else
result := Chr(B + $20);
end;
{ Index2Char End }
// エンコード&デコード
// -----------------------------------------------------------------------------
function Exec_Enigma(Src, Key: String): String;
const
// ロータ:
// ・3つのロータを定義している。
// ・ロータを増やす場合にはRotors配列を増やし、ROTOR_MAX定数を増やす必要がある。
// ・Genareate_Rotorでロータを再生成可能
Rotors:array[0..ROTOR_MAX - 1, 0..CHAR_MAX - 1] of SmallInt =
(
// fast rotor
(
13, 83, 67, 43, 54, 70, 81, 14, 36, 26, 71, 8, 55, 55, 8, 63,
-11, 76, 22, 30, 40, 35, 50, 30, 26, 51, 22,-19,-28, 34, 12, 31,
-3, 1, -8, 55, -5, 1, -6,-23, 19,-17,-24, 23, -3,-34, 27, -2,
-25,-22,-35, 26,-40,-50, 31,-35, 18,-20, -6, 27, 10, 19,-56, 29,
-36,-48,-62,-57, 15, 10,-27,-24, -7,-71, -3,-74, 12, 17,-21,-65,
-71,-42,-21,-53,-33,-52, -4, 4,-63, 6, -1,-36,-56,-86,-30,-41
),
// midium rotor
(
64, 27, 4, 31, 90, 69, 43, 13, 49, 53, 79, 69, 26, 6, 4, 73,
-4,-10, 30, 42, 20, 42, 28, 63, 44, 30, 30, 60, 38, 50, 40, 45,
3,-32, 9, 37, -3,-32, 33, 44, -3,-32,-13,-17, 33, 6, -2,-30,
-34, 36,-29, 14, -6,-28,-50,-53, -3,-18, -4, 0,-19,-50,-47,-41,
-6, 26,-34,-64,-37,-53,-43,-47, 1, 9, 18,-15,-31, -8,-48,-12,
-70,-29, -4,-60, -9, -1,-86,-74,-52, 4, -9,-49, -2,-85, 1,-48
),
// slow rotor
(
44, 73, 16, 77, 65, 19, 55, 66, -3, 40, 60, 36, 43, 2, 17, 22,
46, 47,-12, 15, 58, 33, 8, 3,-12, 58, 31, -2, 4, 48,-10,-31,
18, 26, -1, 40, 49, 31, 34, 2, 55, 46,-29, 20, 42,-31, 43,-24,
-29,-10,-15,-50,-25,-45, -9, 38,-35,-15,-47, 1,-31, 23,-10,-53,
30,-61,-44, 21,-32, -3, -5,-68,-56,-27, 7, 7,-23,-60,-69, 0,
-52,-14,-31, 9, -8,-14,-28, 4,-32,-46,-52,-84,-44,-53,-92, -5
)
);
// リフレクタ(反転ロータ):
// ・Genareate_Refrectorでリフレクタを再生成可能
Refrector:array[0..CHAR_MAX - 1] of Byte =
(
$5B, $21, $5E, $0E, $49, $4A, $58, $36, $57, $3C, $30, $53, $3E, $46, $03, $16,
$3A, $34, $23, $31, $1B, $25, $0F, $22, $2D, $24, $38, $14, $28, $4F, $32, $43,
$50, $01, $17, $12, $19, $15, $2E, $41, $1C, $2C, $45, $5D, $29, $18, $26, $5C,
$0A, $13, $1E, $48, $11, $39, $07, $56, $1A, $35, $10, $5A, $09, $51, $0C, $4C,
$54, $27, $4D, $1F, $44, $2A, $0D, $55, $33, $04, $05, $4E, $3F, $42, $4B, $1D,
$20, $3D, $59, $0B, $40, $47, $37, $08, $06, $52, $3B, $00, $2F, $2B, $02, $5F
);
var
i, l: Integer;
Idx: Byte;
Dmy: String;
R_Idx: array [0..ROTOR_MAX - 1] of Byte;
F_RT: array [0..ROTOR_MAX - 1, 0..CHAR_MAX - 1] of Byte;
R_RT: array [0..ROTOR_MAX - 1, 0..CHAR_MAX - 1] of Byte;
{ Create_Rotor Begin }
procedure Create_Rotor(Index, Index2: Integer);
var
i: Integer;
begin
for i := 0 to CHAR_MAX - 1 do
begin
F_RT[Index, i] := (Rotors[Index, (Index2 + i) mod CHAR_MAX] + (Index2 + i)) mod CHAR_MAX;
R_RT[Index, F_RT[Index, i]] := i;
end;
end;
{ Create_Rotor End }
{ Rotate Begin }
procedure Rotate(i: Integer);
begin
Inc(R_Idx[i]);
if R_Idx[i] = CHAR_MAX then
begin
R_Idx[i] := 0;
if i < ROTOR_MAX then
Rotate(i + 1);
end;
Create_Rotor(i, R_Idx[i]);
end;
{ Rotate End }
begin
result := '';
// 入力チェック
if Src = '' then
Exit;
if Length(Key) < ROTOR_MAX then
Exit;
// キーからロータ位置を設定
for i := 0 to ROTOR_MAX - 1 do
begin
R_Idx[i] := Char2Index(Key[i + 1]);
Create_Rotor(i, R_Idx[i]);
end;
// 文字列を暗号化/復号
Dmy := '';
for i := 1 to Length(Src) do
begin
Idx := Char2Index(Src[i]);
for l := 0 to ROTOR_MAX - 1 do
Idx := F_RT[l, Idx];
Idx := Refrector[Idx];
for l := ROTOR_MAX - 1 downto 0 do
Idx := R_RT[l, Idx];
Dmy := Dmy + Index2Char(Idx);
// ロータ回転
Rotate(0);
end;
result := Dmy;
end;
// ロータ用テーブル生成
// -----------------------------------------------------------------------------
function Genareate_Rotor: String;
var
i, Idx: Byte;
List: TList;
Dmy: String;
Dmy2: String;
begin
Randomize;
result := '';
List := TList.Create;
try
for i := 0 to CHAR_MAX - 1 do
List.Add(Pointer(i));
Dmy := '';
for i := 0 to CHAR_MAX - 1 do
begin
Idx := Random(List.Count);
Dmy2 := IntToStr(Integer(List.Items[Idx]) - i);
Dmy := Dmy + StringOfChar(' ', 3 - Length(Dmy2)) + Dmy2;
List.Delete(Idx);
if i < CHAR_MAX - 1 then
Dmy := Dmy + ',';
if (i mod 16) = 15 then
Dmy := Dmy + #$0D#$0A;
end;
finally
List.Free;
end;
result := Dmy;
end;
// リフレクタ用テーブル生成
// -----------------------------------------------------------------------------
function Genareate_Refrector: String;
var
i, Idx, Idx2: Byte;
Idx3: Integer;
List: TList;
Dmy: String;
RF: array [0..CHAR_MAX - 1] of Byte;
begin
Randomize;
result := '';
List := TList.Create;
try
for i := 0 to CHAR_MAX - 1 do
begin
List.Add(Pointer(i));
RF[i] := $FF;
end;
for i := 0 to CHAR_MAX - 1 do
begin
if RF[i] <> $FF then
Continue;
Idx := Random(List.Count);
Idx2 := Integer(List.Items[Idx]);
RF[i] := Idx2;
RF[Idx2] := i;
List.Delete(Idx);
Idx3 := List.IndexOf(Pointer(i));
if Idx3 > -1 then
List.Delete(Idx3);
end;
Dmy := '';
for i := 0 to CHAR_MAX - 1 do
begin
Dmy := Dmy + Format('$%.2x', [RF[i]]);
if i < CHAR_MAX - 1 then
Dmy := Dmy + ',';
if (i mod 16) = 15 then
Dmy := Dmy + #$0D#$0A;
end;
finally
List.Free;
end;
result := Dmy;
end;
// キーの自動生成
// -----------------------------------------------------------------------------
// ※自動生成キーにはTAB文字が含まれない(入力の便宜上)。
function GenarateKey: String;
var
Dmy: String;
i: Integer;
begin
Randomize;
Dmy := '';
for i := 0 to ROTOR_MAX - 1 do
Dmy := Dmy + Index2Char(Random(CHAR_MAX - 1));
result := Dmy;
end;
end.
|