// 参考: // 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.
|