切换到宽版
  • 5950阅读
  • 2回复

密码学专区 [复制链接]

上一主题 下一主题
离线r134a
 
只看楼主 倒序阅读 0 发表于: 2006-07-31
置换和替代是加密学的基本原则,任何复杂的加密算法都是由这两个基本运算组合而成。加密算法根据密钥的不同分成对称加密和非对称加密,前者加密和解密共享相同的密钥,后者使用不同的密钥。被加密的信息成为明文,用P表示,加密后的信息成为密文用C表示,密钥用K表示,其函数关系表示为:
          C = E(P,K)
其中E表示加密
          P = D(C,K)
其中D表示解密

栅栏技术是这样一种置换技术,它的密钥是根据深度计算出来的一个矩阵,例如有以下明文:

meetmeafterthetogaparty

我们设深度为2,则矩阵如下:

m e m a t r h r h t g p r y
e t e f e t e t e o a a t

加密算法就是从第一行第一个字符开始逐列读取组成密文:

mematrhrhtgpryetefeteteoaat

如果深度为m,密钥就是一个m*n矩阵,其中m表示行的个数,n表示列的个数,n = L div m {注:L是明文的长度},如果L mod m <> 0 ,那么n = (L + L mod m) div m。

解密的算法就是从矩阵的第一列的第一个字符开始逐行读取还原成明文。

下面是pascal代码:

program zhalan;

{$APPTYPE CONSOLE}

var
P,C: AnsiString; //P—明文,C—密文
H,i,n: byte; //H—深度
K: array of AnsiString; //密钥,矩阵
L,j,w,t: Cardinal; //L—明文长度,w—列宽

procedure E(); //加密算法
var
i: byte; //行高
j: Cardinal; //列宽
begin
setlength(C,L);
t := 1;
for i := 1 to H do
begin
  n := i - 1;
  for j := 1 to w do
  begin
    if K[n][j] <> '' then
    begin
    C[t] := K[n][j];
    inc(t);
    end;
  end;
end;
end;

procedure D(); //解密算法
var
i: byte; //行高
j: Cardinal; //列宽
begin
t := 1;
for j := 1 to w do
begin
  for i := 1 to H do
  begin
    P[t] := K[i-1][j];
    inc(t);
  end;
end;
P := Trim(P);
end;

begin
write('请输入原文:');
readln(P);
L := length(P);

write('请输入深度:');
readln(H);

{计算密钥}
setlength(K,H); //第一个元素为矩阵第一行,最后一个元素为矩阵第H行
if L mod H = 0 then
  w := L div H
else
  w := ( L + ( L mod H ) ) div H;
for i := 1 to H do
begin
  n := i - 1;
  setlength(K[n],w);
  j := i;
  t := 1;
  while j <= L do
  begin
    K[n][t] := P[j]; //给第i行第t列赋值
    inc(j,H); //下标指向第i行第t+1列
    inc(t);
  end;
end;

{加密}
E();
writeln(C);
{解密}
D();
writeln(P);
readln;
end.
可能还有比以上简洁的代码,上面的代码意在说清栅栏本质。现在可以把输入输出替换成pascal的文件操作了,这样我们就可以对某个文件进行置换加密,当对文件进行加密时,密钥必须保存到一个二进制文件中,以便解密。
转入正提:大家需要Pascal版本的DES加密算法吗?它可是以前美国标准的加密算法呀!以后我还会发布Pascal版本的RSA算法以及网上流行的加密算法MD5(包括其前身M1到M4)。

这些加密算法的发布包括一个dll函数库,同时可提供Pascal源代码!

关键是:有多少程序爱好者真心急迫需要这些加密算法的代码呢?这时我需要知道的答案!
上述代码用动态一维数组和动态字符串来模仿动态二维数组(用于存放矩阵),主要是因为现在的pascal还不提供对多维动态数组的支持,如果是VB,则可以定义一个动态数组并随时改变维数。


再来一个最简单的替代技术——Caesar加密,这是凯撒大帝给他的情人写情书是用的加密技术,我们把它扩展了,字符集从26个英文字母变成ASCII码集:

unit CaesarUnit;

interface

function E(p: char; k: byte): char;
function D(C: char; k: byte): char;
procedure Caesar(p: PChar; k: byte);
procedure UnCaesar(c: PChar; k: byte);

implementation

function E(p: char; k: byte): char;
var
c: char;
begin
{p是明文,k是密钥,c是密文}
{1≤k≤127}
c := chr( ( ord(p) + k ) Mod 128 );
Result := c;
end;

function D(C: char; k: byte): char;
var
p: char;
begin
p := chr( ( ord(C) - k ) Mod 128 );
if ord(P) < 0 then P := chr( ord(P) + 128 );
Result := p;
end;

procedure Caesar(p: PChar; k: byte);
begin
p^ := chr( ( ord(p^) + k ) Mod 128 );
end;

procedure UnCaesar(c: PChar; k: byte);
begin
c^ := chr( ( ord(c^) - k ) Mod 128 );
if ord(c^) < 0 then c^ := chr( ord(c^) + 128 );
end;

end.
program example;

{$APPTYPE CONSOLE}

uses
CaesarUnit in '..\CaesarUnit.pas';

var
P,C: AnsiString;
i: integer;
begin
readln(P);
{加密}
setlength(C,length(P));
C := Trim(C);
for i := 1 to length(P) do
begin
Caesar(@P,3);
C := C + P;
end;
writeln(C);
{end}
P := '';
{解密}
for i := 1 to length(C) do
begin
UnCaesar(@C,3);
P := P + C;
end;
writeln(P);
{end}
readln;
end.
DES分为多过版本,我现发布S-DES版本,这个版本用于理解DES算法。
在开始之前,先搞清楚十进制转换成二进制的代码是必须的。

program Project1;

{$APPTYPE CONSOLE}

var
bit: Array[0..9] of char;
key, temp: word;

procedure getbit();
var
i,t: byte;
begin
t := 0;
for i := 9 downto 0 do
begin
if ( ( key SHR t ) AND temp ) = 1 then
bit := '1'
else
bit := '0';
inc(t);
end;

end;

begin
temp := 1;
readln(key);
getbit;
writeln(bit);
readln;
end.

程序功能:取16位无符号整数的低10位。
S-DES的密钥只有低10位参与运算,被移位和置换后变成两个子密钥分别用于函数fk1和fk2。
上面的代码使用位运算,这样不但可以提高运行效率,还可以使代码简洁明了!

SHR是右移运算。
unit SDES;

interface

type

SDES_KEY = array[1..10] of Char;
SDES_SUB_KEY = array[1..8] of Char;

TSDES = class(TObject)
private
protected
KEY: SDES_KEY; //密钥
KEY_ONE,KEY_TWO: SDES_SUB_KEY; //子密钥
P: AnsiString; //明文
C: AnsiString; //密文
SDES_BIT: word;
{和计算密钥相关的一组方法}
procedure INTTOBYTE(aKey: word);
procedure P10(aKey: SDES_KEY);
procedure LS1();
procedure P8(var SUB_KEY: SDES_SUB_KEY);
procedure LS2();
{和加密解密相关的一组方法}
public
Constructor Create(aKey: Char; aP: AnsiString);
{和测试相关的一组方法}
function get_KEY_ONE(): AnsiString;
function get_KEY_TWO(): AnsiString;
{提供给程序员的S-DES加密解密接口}
end;

implementation

Constructor TSDES.Create(aKey: Char; aP: AnsiString);
begin
SDES_BIT := 1;
INTTOBYTE(ord(akey));
//writeln(KEY);
P10(KEY);
//writeln(KEY);
LS1();
p8(KEY_ONE);
LS2();
p8(KEY_TWO);
P := aP;
end;

{把输入的Unicode字符的序号转换成二进制,取其低十位}
procedure TSDES.INTTOBYTE(aKey: word);
var
i,t: byte;
begin
t := 0;
for i := 10 downto 1 do
begin
if ( ( aKey SHR t ) AND SDES_BIT ) = 1 then
KEY := '1'
else
KEY := '0';
inc(t);
end;
end;

{置换十位密钥}
procedure TSDES.P10(aKey: SDES_KEY);
begin
KEY[1] := aKey[3];
KEY[2] := aKey[5];
KEY[3] := aKey[2];
KEY[4] := aKey[7];
KEY[5] := aKey[4];
KEY[6] := aKey[10];
KEY[7] := aKey[1];
KEY[8] := akey[9];
KEY[9] := aKey[8];
KEY[10] := aKey[6];
end;

{对置换后的10位密钥的前五个比特和后五个比特
分别进行一次1位的循环左移操作}
procedure TSDES.LS1();
var
temp:Char;
i: byte;
begin
temp := KEY[1];
for i := 1 to 4 do
KEY := KEY[i+1];
KEY[5] := temp;
temp := KEY[6];
for i := 6 to 9 do
KEY := KEY[i+1];
KEY[10] := temp;
end;

{对10位密钥的前五个比特和后五个比特分别进行
一次2位的循环左移操作}
procedure TSDES.LS2();
var
temp:String[2];
i: byte;
begin
temp[1] := KEY[1];
temp[2] := KEY[2];
for i := 1 to 3 do
KEY := KEY[i+2];
KEY[4] := temp[1];
KEY[5] := temp[2];
temp[1] := KEY[6];
temp[2] := KEY[7];
for i := 6 to 8 do
KEY := KEY[i+2];
KEY[9] := temp[1];
KEY[10] := temp[2];
end;

{对循环左移后的10位密钥进行置换得出KEY_ONE或者KEY_TWO}
procedure TSDES.P8(var SUB_KEY: SDES_SUB_KEY);
begin
SUB_KEY[1] := KEY[6];
SUB_KEY[2] := KEY[3];
SUB_KEY[3] := KEY[7];
SUB_KEY[4] := KEY[4];
SUB_KEY[5] := KEY[8];
SUB_KEY[6] := KEY[5];
SUB_KEY[7] := KEY[10];
SUB_KEY[8] := KEY[9];
end;

function TSDES.get_KEY_ONE(): AnsiString;
begin
Result := KEY_ONE;
end;

function TSDES.get_KEY_TWO(): AnsiString;
begin
Result := KEY_TWO;
end;

end.


以上是SDES的密钥生成算法,当用户输入一个原始密要得时候,将生成两个子密钥用于加密和解密,关于加密和解密的算法会和dll等同时发布(共享版)。

注意:以上代码使用object pascal的类封装,面向过程的pascal代码会在发布加密解密算法是同时发布,也就是说这个SDES代码会发布两个版本:面向对象和面向过程。现在读不懂无所谓,以后会发布详细的文档说明,这里只是给大家一个感性认识。

下面是一个调用的例程:

program Project1;

{$APPTYPE CONSOLE}

uses
SDES in '..\SDES.pas';

var
sdes1: TSDES;
key: Char;
p: AnsiString;
sub_key: String[8];

begin
write('请输入明文:');
readln(p);
write('请输入密钥:');
readln(key);
sdes1 := TSDES.Create(key,p);
sub_key := sdes1.get_KEY_ONE;
writeln(sub_key);
sub_key := sdes1.get_KEY_TWO;
writeln(sub_key);
sdes1.Free;
readln;
end.

以上代码在Borland Delphi下调试通过!


以上资料全部摘自网上! 版权没有,盗版不究!
.


祝大家明年NOIP大获全盛!


.
离线arronking
只看该作者 1 发表于: 2006-07-31
哈哈,小弟弟跟着我发啊
大秦魂不相信强盗悔忏,
只能用复仇雪耻的战争,
讨回我秦汉高贵的尊严。
强秦何曾看过六国脸色,
大汉何曾求过匈奴道歉?
用无坚不摧的滚滚铁骑,
踏平那敌国的巍峨宫殿!
离线r134a
只看该作者 2 发表于: 2006-07-31
引用第1楼arronking2006-07-31 11:34发表的“”:
哈哈,小弟弟跟着我发啊


就算是吧。~~
.


祝大家明年NOIP大获全盛!


.
快速回复
限100 字节
 
上一个 下一个