现代密码学实验报告

中南大学

现 代 密 码 学 实 验 报 告

学生姓名 张振宇 学 号 0906130221 专业班级 信息安全1302班 指导教师 段桂华 学 院 信息科学与工程学院 完成时间 2015年5月

目 录

实验一 密码算法实验 ............................................... - 2 -

[实验目的] . ................................................................................................ - 2 -

[实验预备] . ................................................................................................ - 2 -

[实验内容] . ................................................................................................ - 2 -

[实验步骤] . ................................................................................................ - 2 -

1. AES 算法 .......................................................................................................... - 3 - 2. RC4算法 ........................................................................................................ - 11 -

[问题讨论] . .............................................................................................. - 15 - 实验二 SKEY 协议设计实验 ...................................... - 16 -

[实验目的] . .............................................................................................. - 16 -

[实验预备] . .............................................................................................. - 16 -

[实验内容] . .............................................................................................. - 16 -

[实验步骤] . .............................................................................................. - 16 -

1. 协议分析 ........................................................................................................ - 17 -

2. 协议实现 ........................................................................................................ - 17 -

3. 运行结果 ........................................................................................................ - 21 -

[问题讨论] . .............................................................................................. - 22 -

实验一 密码算法实验

[实验目的]

1.掌握密码学中经典的对称密码算法AES、RC4的算法原理。

2.掌握AES、RC4的算法流程和实现方法。

[实验预备]

1.AES 算法的基本原理和特点。

2.流密码RC4的密钥流生成以及S 盒初始化过程。

[实验内容]

1. 分析AES、RC4的实现过程。2. 用程序设计语言将算法过程编程实现。

3. 完成字符串数据的加密运算和解密运算

输入十六进制明文:[***********]00AABBCCDDEEFF

输入十六进制密钥:13579BDF02468ACE1234567890ABCDEF

[实验步骤]

1. 预习AES、RC4算法。

2. 写出算法流程,用程序设计语言将算法过程编程实现。

3. 输入指定的明文、密钥进行实验,验证结果。

4. 自己选择不同的输入,记录输出结果。

1.

AES 算法

算法分析

Rijndael (State , ExpandedKey)

{

AddRoundKey (State , ExpandedKey);

for (i =1; i

Round (State , ExpandedKey+Nb * i);

FinalRound (State , ExpandedKey+Nb *Nr )

}

Round (State , RoundKey)

{

ByteSub (State );

ShiftRow (State );

MixColumn (State );

AddRoundKey (State , RoundKey)

}

FinalRound (State , RoundKey)

{

ByteSub (State );

ShiftRow (State );

AddRoundKey (State , RoundKey)

}

编程实现

Subbyte (字节替换)

非线性的字节替代,单独处理每个字节:

求该字节在有限域GF(28) 上的乘法逆,"0" 被映射为自身,

即对于α∈GF(28) ,求β∈GF(28) ,使得α·β=β·α=1mod(x8+x4+x2+x+1)。 对上一步求得的乘法逆作仿射变换

yi=xi + x(i+4)mod8 + x(i+6)mod8 + x(i+7)mod8 + ci

为了数据处理的方便,我在这里使用的是置换表的方法。

public

byte [][] subbyte(byte [][] sub, int r){

byte row, col ;

byte [][] temp=new byte [4][4];

for (int i=0; i

for (int j=0; j

col=(byte )(sub [i ][j ]&0xf );

row=(byte )((sub [i ][j ]>>4)&0xf );

temp[i ][j ]=rsbox [row ][col ];

}

return temp;

}

ShiftRows (行移位变换)

行移位变换完成基于行的循环位移操作,变换方法:

即行移位变换作用于行上,第0行不变,第1行循环左移1个字节,第2行循环左移2个字节,第3行循环左移3个字节。

public byte [][] shift(byte [][]

sub

, int mode){

byte temp;

temp=sub [3][0];

sub[3][0]=sub [3][1];sub [3][1]=sub [3][2];

sub[3][2]=sub [3][3];sub [3][3]=temp ;

temp=sub [2][0];

sub[2][0]=sub [2][2];sub [2][2]=temp ;

temp=sub [2][1];

sub[2][1]=sub [2][3];sub [2][3]=temp ;

temp=sub [1][0];

sub[1][0]=sub [1][3];sub [1][3]=sub [1][2];

sub[1][2]=sub [1][1];sub [1][1]=temp ;

return sub;

}

MixColumns (列混合变换)

逐列混合,方法:

b(x) = (03·x3 + 01·x2 + 01·x + 02) · a(x) mod(x4 + 1)

矩阵表示形式:

public byte [][] mix(byte [][] sub, int mode){

byte count=0;

byte [][] temp=new byte [4][4];

for (int i=0; i

for (int j=0; j

while (count

temp[i ][j ]=(byte )(

temp [i ][j ]^mu (rmut [i ][count ],

sub [count ][j ]));

count++;

}

count=0;

}

}

return temp;

}

public byte

mu(byte b, byte c){

byte ret=0 , count1=0, count2=0;

byte [] barray=new byte [8];

byte [] carray=new byte [8];

byte [] pro=new byte [15];

if (b ==1|c ==0) return c;

if (c ==1) return b;

for (int i=0; i

barray[i ]=(byte )(b &1);

b=(byte )(b >>1);

count1++;

}

for (int i=0; i

carray[i ]=(byte )(c &1);

c=(byte )(c >>1);

count2++;

}

for (int i=0; i

for (int j=0; j

if (barray [i ]>0&carray [j ]>0)

pro[i +j ]=(byte )((pro [i +j ]+1)%2);

}

for (int m=0; m

if (pro [m ]>0)

ret=(byte )((by [m ])^(ret ));

}

return ret;

}

AddRoundKey (轮密钥加密)

简单来说就是逐字节相加,有限域GF(2

8) 上的加法是模2加法,即异或。

public byte [][] add(byte sub[][],byte [][] roundkey){

for (int i=0; i

for (int j=0; j

sub[i ][j ]=(byte )(

sub[i ][j ]^roundkey [i ][j ]);

}

return sub;

}

KeyExpansion (密钥扩展)

将输入的密钥扩展为11组128位密钥组,其中第0组为输入密钥本身 其后第n 组第i 列 为 第n-1组第i 列 与 第n 组第i-1列之和

对于每一组第一列有特殊的处理

将前一列即第n-1组第3列的4个字节循环左移1个字节,并对每个字节进行字节替代变换SubBytes 将第一行与轮常量相加,最后再与前一组该列相加

public byte [][][] key(byte [][] okey){

byte [][][] retarray=new byte [11][4

][4];

for (int i=0; i

for (int j=0; j

retarray[0][j ][i ]=okey [i ][j ];

}

for (int i=1; i

retarray[i ]=tkey (retarray [i -1],r [i ]);

}

return retarray;

}

public byte [][] tkey(byte [][] okey, int ri){

byte [][] temp=new byte [4][4];

byte col, row ;

col=(byte )(okey [1][3]&0xf );

row=(byte )((okey [1][3]>>4)&0xf );

temp[0][0]=(byte )(ri ^sbox [row ][col ]^okey [0][0]);

col=(byte )(okey [2][3]&0xf );

row=(byte )((okey [2][3]>>4)&0xf );

temp[1][0]=(byte )(sbox [row ][col ]^okey [1][0]);

col=(byte )(okey [3][3]&0xf );

row=(byte )((okey [3][3]>>4)&0xf );

temp[2][0]=(byte )(sbox [row ][col ]^okey [2][0]);

col=(byte )(okey [0][3]&0xf );

row=(byte )((okey [0][3]>>4)&0xf );

temp[3][0]=(byte )(sbox [row ][col ]^okey [3][0]);

for (int i=1; i

temp[0][i ]=(byte )(temp [0][i -1]^okey [0][i ]);

temp[1][i ]=(byte )(temp [1][i -1]^okey [1][i ]);

temp[2][i ]=(byte )(temp [2][i -1]^okey [2][i ]);

temp[3][i ]=(byte )(temp [3][i -1]^okey [3][i ]);

}

return temp;

}

数据加密: case 1:

try {

Encrypt en=new Encrypt();

System. out . println (" 请输入明文" );

content=in . readLine ();

System. out . println (" 请输入密钥" );

key=in . readLine ();

out=en . textEncrypt (content , key);

System. out . println (out );

while (true ){

System. out . println ("coyp 一下结果? y/n"); ch=in . readLine ();

if (ch . length ()==1){

if (ch . charAt (0)=='y' |

ch . charAt (0)=='Y' )

{save =out ; break ;}

if (ch . charAt (0)=='n' |

ch . charAt (0)=='N' )

break ;

}

}

}catch (IOException e){

e. printStackTrace ();}

break ;

数据解密:

case 2:

try {

if (save !="" &save !=null ){

while (true ){

System . out . println (" 用一下刚刚copy 的结果? y/n" ch =in . readLine ();

if (ch . length ()==1){

if (ch . charAt (0)=='y' |

ch . charAt (0)=='Y' )

{content =save ; break ;}

);

if (ch . charAt

(

)=='n' |

ch . charAt (0)=='N' )

break ;

}

}

}

else {

System. out . println (" 请输入密文" );

content=in . readLine ();

}

System. out . println (" 请输入密钥" );

key=in . readLine ();

Decrypt de=new Decrypt();

out=de . textDecrypt (content , key);

System. out . print (out );

}catch (IOException e){

e. printStackTrace ();System . out . println (" 未知错误);} break ;

运行结果

2. RC4算法

算法分析

RC4算法的原理包括初始化算法和伪随机子密码生成算法两大部分。

假设S-box 长度和密钥长度均为n 。

算法的初始化部分 for (i =0; i

{

s[i ]=i ;

}

j =0;

for (i =0; i

{

j=(j +s [i ]+k [i ])%n ;

swap(s [i ], s

[j ]);

}

在初始化的过程中,密钥的主要功能是将S-box 搅乱,i 确保S-box 的每个元素都得到处理,j 保证S-box 的搅乱是随机的。而不同的S-box 在经过伪随机子密码生成算法的处理后可以得到不同的子密钥序列。

i =j =0;

while (明文未结束)

{

++i %=n ;

j=(j +s )%n ;

swap(s , s[j ]);

sub_k=s ((s +s [j ])%n );

}

得到的子密码sub_k用以和明文进行异或运算,得到密文,解密过程也完全相同。

编程实现 package RC4;

import java.util.Scanner;

public class RC4 {

public static String decry_RC4(byte [] data, String key) {

if (data == null || key == null ) {

return null ;

}

return asString(RC4Base (data , key));

}

public static String decry_RC4(String data, String key) {

if (data == null || key == null ) {

return null ;

}

return new String(RC4Base (HexString2Bytes (data ), key));

}

public static byte [] encry_RC4_byte(String data, String key) { if (data == null || key == null ) {

return null ;

}

byte b_data[] = data. getBytes ();

return RC4Base(b_data, key);

}

public static String encry_RC4_string(String data, String key) { if (data == null || key == null ) {

return null ;

}

return toHexString(asString (encry_RC4_byte(data , key))); }

private static String asString(byte [] buf) {

StringBuffer strbuf = new StringBuffer(buf . length );

for (int i = 0; i

strbuf. append ((char ) buf[i ]);

}

return strbuf. toString ();

}

private static byte [] initKey(String aKey) {

byte [] b_key = aKey. getBytes ();

byte state[] = new byte [256];

for (int i = 0; i

state[i ] = (byte ) i;

}

int index1 = 0;

int index2 = 0;

if (b_key == null || b_key. length == 0) {

return null ;

}

for (int i = 0; i

index2 = ((b_key[index1] & 0xff )

+ (state [i ] & 0xff ) + index2) & 0xff ;

byte tmp = state[i ];

state[i ] = state[index2];

state[index2] = tmp;

index1 = (index1 + 1) % b_key. length ;

}

return state;

}

private static String toHexString(String s) {

String str = "" ;

for (int i = 0; i

int ch = (int ) s. charAt (i );

String s4 = Integer. toHexString (ch & 0xFF );

if (s4. length () == 1) {

s4 = '0' + s4;

}

str = str + s4;

}

return str; // 0x表示十六进制

}

private static byte [] HexString2Bytes(String src) {

int size = src. length ();

byte [] ret = new byte [size / 2];

byte [] tmp = src. getBytes ();

for (int i = 0; i

ret[i ] = uniteBytes(tmp [i * 2], tmp[i * 2 + 1]);

}

return ret;

}

private static byte uniteBytes(byte src0, byte src1) {

char _b0 = (char ) Byte. decode (

"0x" + new String(new byte [] { src0 })).byteValue ();

_b0 = (char ) (_b0

char _b1 = (char ) Byte. decode (

"0x" + new String(new byte [] { src1 })).byteValue ();

byte ret = (byte ) (_b0 ^ _b1);

return ret;

}

private static byte [] RC4Base(byte [] input, String mKkey) { int x = 0, y = 0;

byte key[] = initKey(mKkey );

int xorIndex;

byte [] result = new byte [input . length ];

for (int i = 0; i

x = (x + 1) & 0xff ;

y = ((key [x ] & 0xff ) + y) & 0xff ;

byte tmp = key[x ];

key[x ] = key[y ];

key[y ] = tmp;

xorIndex = ((key [x ] & 0xff ) + (key [y ] & 0xff )) & 0xff ; result[i ] = (byte ) (input [i ] ^ key[xorIndex ]);

}

return result;

}

public static void main(String [] args) {

System. out . println (" 请输入明文:" );

Scanner in=new Scanner(System . in );

String inputStr, keyStr;

inputStr=in . nextLine ();

System. out . println (" 请输入密钥:" );

keyStr = in. nextLine ();

String str = encry_RC4_string(inputStr , keyStr);

System. out . println (" 加密后的密文:" +str );

System. out . print (" 解密后的明文:" );

System. out . println (decry_RC4(str , keyStr));

}

}

运行结果

测试数据1

测试数据2

[问题讨论]

1. 改变明文或密钥中的一个比特值可能影响AES 值中的多少比特?

答:明文和密钥在S 盒置换时,不同的字节会替换出不同的结果。算法过程

中一共进行了10轮加密,所以改变一个比特值可能影响AES 值中的80

比特(8 x 10)。

2. 在RC4的密钥流生成中,改变初始密钥的一个比特值可能影响输

出中的多少比特?

答:初始密钥的不同会导致S 盒的不同,所以可能影响输出中的256比特。

3. 分析实验中在编辑编译运行等各环节中所出现的问题及解决方法。

答:在AES 算法实现过程中,在对输入数据的处理上遇到了很多的问题,刚

开始的时候习惯性地使用string 的形式保存S 盒等数据,但是由于AES

算法用到了很多的异或和移位操作,使用string 和char 形式数据的弊

端就慢慢地暴露了出来。然后在网上查阅了很多资料,最后选择了使用

byte 类型的数据,在整个算法的实现过程中,进一步加深了我对AES 加

密算法和RC4算法的理解。

实验二 SKEY 协议设计实验

[实验目的]

1.掌握身份认证协议的原理和基本思想。

2.掌握SKEY 协议的机制和实现方法。

[实验预备]

1.SKEY 协议的作用。

2.SKEY 协议的安全性分析。

3.SKEY 协议的实现过程。

[实验内容]

1. 分析SKEY 协议的实现过程。

2. 用程序设计语言将算法过程编程实现。

3. 演示SKEY 协议的身份鉴别过程。

[实验步骤]

1. 预习SKEY 协议的机制。

2. 选择和实现相应的摘要算法MD5或SHA。

3. 写出算法流程,用程序设计语言将协议过程编程实现。

4. 验证SKEY 协议的身份鉴别过程。

1. 协议分析

2. 协议实现

为了便于实现和演示,我采用了一个比较简单的方式进行。要模拟客户端保存数据比较不容易实现,对服务器生成的hash 值,保存在本地文件中, 这个hash 的值是动态变化的,每次hash 都会加上相应的登陆次数(这个hash 方式和一般的skey 协议有些不同),

这样可以动态的获取。通过文件读写的方式获得。对于

生成的

hash

值从100到0次访问的问题也是使用一个文件来储存,每次验证完成后,都会把前一次存的数据减1然后重新的写入文件中。

本次实验使用到了Java 中的文件读写,这是用到的两个辅助文件:

其中int.txt 存储登陆后修改的数据

(写进去的格式不是10进值的,所以在这里不能看出明文)

md5.txt 为存储hash 值的文件:

(共100条密钥)

MD5实现文件: package SKEY;

import

java. security . MessageDigest ;

import java. security . NoSuchAlgorithmException ;

public class MD5String {

private String string ;

// 全局数组

private final static String[] strDigits = {

"0" , "1" , "2" , "3" , "4" , "5" , "6" , "7" ,

public MD5String(String string ) {

this . string =string ;

}

private String byteToArrayString(byte bByte) {

int iRet = bByte;

if (iRet

iRet += 256; "8" , "9" , "A" , "B" , "C" , "D" , "E" , "F" };

}

int iD1 = iRet / 16;

int iD2 = iRet % 16;

return strDigits[iD1] + strDigits[iD2];

}

// 转换字节数组为16进制字串

private String byteToString(byte [] bByte) {

StringBuffer sBuffer = new StringBuffer();

for (int i = 0; i

sBuffer. append (byteToArrayString (bByte [i ])); }

return sBuffer. toString ();

}

public String GetMD5Code() {

String resultString = null ;

try {

resultString = new String(string );

MessageDigest. getInstance ("MD5" );

MessageDigest md = MessageDigest. getInstance ("MD5" ); //该函数返回值为存放返回结果的byte 数组

md. digest (string . getBytes ());

byte [] bytes = md. digest (string . getBytes ()); resultString = byteToString(bytes );

} catch (NoSuchAlgorithmException ex) {

}

return resultString;

}

}

Skey 协议实现文件:

package SKEY;

import java. io . BufferedReader ;

import java. io . BufferedWriter ;

import java. io . File ;

import java. io . FileInputStream ;

import java. io . FileOutputStream ;

import java. io . FileReader ;

import java. io . FileWriter ;

import java. io . IOException ;

public class Skey {

String intsString =

"C://Users//zzy//workspace//Cryptology//int.txt";

String md5sString =

"C://Users//zzy//workspace//Cryptology//md5.txt";

File file_int = new File(intsString );

File file_md5 = new File(md5sString );

//初始化

public void GUI(String string) {

try {

FileOutputStream fos = new FileOutputStream(file_int); FileWriter writer = new FileWriter(file_md5);

BufferedWriter bw = new BufferedWriter(writer );

fos. write (1);

for (int a=1; a

MD5String md5 = new MD5String(string +a );

System. out . println (md5. GetMD5Code ());

bw. write (md5. GetMD5Code ().toString ());

bw. write ("\r\n");

}

bw. close ();

writer. close ();

FileInputStream fis = new FileInputStream(file_int); System. out . print (fis . read ());

fos. close ();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

public int compare(String string, String keys) {

int flag =0;

try {

FileInputStream fis = new FileInputStream(file_int); int a = fis. read ();

FileReader fileReader = new FileReader(file_md5);

BufferedReader bReader = new BufferedReader(fileReader ); //从文件读出来MD5值

String string2 = (String ) readLine (a , bReader);

if (string2. equals (keys )){

flag = 1;

- 20 -

}

FileOutputStream fos = new

FileOutputStream

(file_int); fos. write (a +1);

} catch (Exception e ) {

// TODO Auto-generated catch block

e. printStackTrace ();

}

return flag;

}

private String readLine(int lineNumber,

BufferedReader reader) throws Exception{

String line="" ;

int i=0;

while (i

line=reader . readLine ();

i++;

}

return line;

}

}

3. 运行结果

(初始化)

(认证登录)

- 21 -

(验证成功)

(如果再使用第一次的密钥或者其他密钥登陆)

(验证失败)

[问题讨论]

1. 分析SKEY 的安全性

答:1.每个数只使用一次,对数据库攻击用处不大

2.可防止重放攻击

2. 分析实验中在编辑编译运行等各环节中所出现的问题及解决方法

答:刚开始的时候对skey 协议的原理不太熟悉,导致在实现的初期中觉得

无从下手,后来通过查阅资料完全理解了skey 协议的流程以后,又在文件读写方面遇到了一些问题。包括后面MD5数字摘要算法的应用。通过这个实验,不只是学到了很多密码学方面是知识,更是对我个人编程

能力的一个提高。

- 22 -

中南大学

现 代 密 码 学 实 验 报 告

学生姓名 张振宇 学 号 0906130221 专业班级 信息安全1302班 指导教师 段桂华 学 院 信息科学与工程学院 完成时间 2015年5月

目 录

实验一 密码算法实验 ............................................... - 2 -

[实验目的] . ................................................................................................ - 2 -

[实验预备] . ................................................................................................ - 2 -

[实验内容] . ................................................................................................ - 2 -

[实验步骤] . ................................................................................................ - 2 -

1. AES 算法 .......................................................................................................... - 3 - 2. RC4算法 ........................................................................................................ - 11 -

[问题讨论] . .............................................................................................. - 15 - 实验二 SKEY 协议设计实验 ...................................... - 16 -

[实验目的] . .............................................................................................. - 16 -

[实验预备] . .............................................................................................. - 16 -

[实验内容] . .............................................................................................. - 16 -

[实验步骤] . .............................................................................................. - 16 -

1. 协议分析 ........................................................................................................ - 17 -

2. 协议实现 ........................................................................................................ - 17 -

3. 运行结果 ........................................................................................................ - 21 -

[问题讨论] . .............................................................................................. - 22 -

实验一 密码算法实验

[实验目的]

1.掌握密码学中经典的对称密码算法AES、RC4的算法原理。

2.掌握AES、RC4的算法流程和实现方法。

[实验预备]

1.AES 算法的基本原理和特点。

2.流密码RC4的密钥流生成以及S 盒初始化过程。

[实验内容]

1. 分析AES、RC4的实现过程。2. 用程序设计语言将算法过程编程实现。

3. 完成字符串数据的加密运算和解密运算

输入十六进制明文:[***********]00AABBCCDDEEFF

输入十六进制密钥:13579BDF02468ACE1234567890ABCDEF

[实验步骤]

1. 预习AES、RC4算法。

2. 写出算法流程,用程序设计语言将算法过程编程实现。

3. 输入指定的明文、密钥进行实验,验证结果。

4. 自己选择不同的输入,记录输出结果。

1.

AES 算法

算法分析

Rijndael (State , ExpandedKey)

{

AddRoundKey (State , ExpandedKey);

for (i =1; i

Round (State , ExpandedKey+Nb * i);

FinalRound (State , ExpandedKey+Nb *Nr )

}

Round (State , RoundKey)

{

ByteSub (State );

ShiftRow (State );

MixColumn (State );

AddRoundKey (State , RoundKey)

}

FinalRound (State , RoundKey)

{

ByteSub (State );

ShiftRow (State );

AddRoundKey (State , RoundKey)

}

编程实现

Subbyte (字节替换)

非线性的字节替代,单独处理每个字节:

求该字节在有限域GF(28) 上的乘法逆,"0" 被映射为自身,

即对于α∈GF(28) ,求β∈GF(28) ,使得α·β=β·α=1mod(x8+x4+x2+x+1)。 对上一步求得的乘法逆作仿射变换

yi=xi + x(i+4)mod8 + x(i+6)mod8 + x(i+7)mod8 + ci

为了数据处理的方便,我在这里使用的是置换表的方法。

public

byte [][] subbyte(byte [][] sub, int r){

byte row, col ;

byte [][] temp=new byte [4][4];

for (int i=0; i

for (int j=0; j

col=(byte )(sub [i ][j ]&0xf );

row=(byte )((sub [i ][j ]>>4)&0xf );

temp[i ][j ]=rsbox [row ][col ];

}

return temp;

}

ShiftRows (行移位变换)

行移位变换完成基于行的循环位移操作,变换方法:

即行移位变换作用于行上,第0行不变,第1行循环左移1个字节,第2行循环左移2个字节,第3行循环左移3个字节。

public byte [][] shift(byte [][]

sub

, int mode){

byte temp;

temp=sub [3][0];

sub[3][0]=sub [3][1];sub [3][1]=sub [3][2];

sub[3][2]=sub [3][3];sub [3][3]=temp ;

temp=sub [2][0];

sub[2][0]=sub [2][2];sub [2][2]=temp ;

temp=sub [2][1];

sub[2][1]=sub [2][3];sub [2][3]=temp ;

temp=sub [1][0];

sub[1][0]=sub [1][3];sub [1][3]=sub [1][2];

sub[1][2]=sub [1][1];sub [1][1]=temp ;

return sub;

}

MixColumns (列混合变换)

逐列混合,方法:

b(x) = (03·x3 + 01·x2 + 01·x + 02) · a(x) mod(x4 + 1)

矩阵表示形式:

public byte [][] mix(byte [][] sub, int mode){

byte count=0;

byte [][] temp=new byte [4][4];

for (int i=0; i

for (int j=0; j

while (count

temp[i ][j ]=(byte )(

temp [i ][j ]^mu (rmut [i ][count ],

sub [count ][j ]));

count++;

}

count=0;

}

}

return temp;

}

public byte

mu(byte b, byte c){

byte ret=0 , count1=0, count2=0;

byte [] barray=new byte [8];

byte [] carray=new byte [8];

byte [] pro=new byte [15];

if (b ==1|c ==0) return c;

if (c ==1) return b;

for (int i=0; i

barray[i ]=(byte )(b &1);

b=(byte )(b >>1);

count1++;

}

for (int i=0; i

carray[i ]=(byte )(c &1);

c=(byte )(c >>1);

count2++;

}

for (int i=0; i

for (int j=0; j

if (barray [i ]>0&carray [j ]>0)

pro[i +j ]=(byte )((pro [i +j ]+1)%2);

}

for (int m=0; m

if (pro [m ]>0)

ret=(byte )((by [m ])^(ret ));

}

return ret;

}

AddRoundKey (轮密钥加密)

简单来说就是逐字节相加,有限域GF(2

8) 上的加法是模2加法,即异或。

public byte [][] add(byte sub[][],byte [][] roundkey){

for (int i=0; i

for (int j=0; j

sub[i ][j ]=(byte )(

sub[i ][j ]^roundkey [i ][j ]);

}

return sub;

}

KeyExpansion (密钥扩展)

将输入的密钥扩展为11组128位密钥组,其中第0组为输入密钥本身 其后第n 组第i 列 为 第n-1组第i 列 与 第n 组第i-1列之和

对于每一组第一列有特殊的处理

将前一列即第n-1组第3列的4个字节循环左移1个字节,并对每个字节进行字节替代变换SubBytes 将第一行与轮常量相加,最后再与前一组该列相加

public byte [][][] key(byte [][] okey){

byte [][][] retarray=new byte [11][4

][4];

for (int i=0; i

for (int j=0; j

retarray[0][j ][i ]=okey [i ][j ];

}

for (int i=1; i

retarray[i ]=tkey (retarray [i -1],r [i ]);

}

return retarray;

}

public byte [][] tkey(byte [][] okey, int ri){

byte [][] temp=new byte [4][4];

byte col, row ;

col=(byte )(okey [1][3]&0xf );

row=(byte )((okey [1][3]>>4)&0xf );

temp[0][0]=(byte )(ri ^sbox [row ][col ]^okey [0][0]);

col=(byte )(okey [2][3]&0xf );

row=(byte )((okey [2][3]>>4)&0xf );

temp[1][0]=(byte )(sbox [row ][col ]^okey [1][0]);

col=(byte )(okey [3][3]&0xf );

row=(byte )((okey [3][3]>>4)&0xf );

temp[2][0]=(byte )(sbox [row ][col ]^okey [2][0]);

col=(byte )(okey [0][3]&0xf );

row=(byte )((okey [0][3]>>4)&0xf );

temp[3][0]=(byte )(sbox [row ][col ]^okey [3][0]);

for (int i=1; i

temp[0][i ]=(byte )(temp [0][i -1]^okey [0][i ]);

temp[1][i ]=(byte )(temp [1][i -1]^okey [1][i ]);

temp[2][i ]=(byte )(temp [2][i -1]^okey [2][i ]);

temp[3][i ]=(byte )(temp [3][i -1]^okey [3][i ]);

}

return temp;

}

数据加密: case 1:

try {

Encrypt en=new Encrypt();

System. out . println (" 请输入明文" );

content=in . readLine ();

System. out . println (" 请输入密钥" );

key=in . readLine ();

out=en . textEncrypt (content , key);

System. out . println (out );

while (true ){

System. out . println ("coyp 一下结果? y/n"); ch=in . readLine ();

if (ch . length ()==1){

if (ch . charAt (0)=='y' |

ch . charAt (0)=='Y' )

{save =out ; break ;}

if (ch . charAt (0)=='n' |

ch . charAt (0)=='N' )

break ;

}

}

}catch (IOException e){

e. printStackTrace ();}

break ;

数据解密:

case 2:

try {

if (save !="" &save !=null ){

while (true ){

System . out . println (" 用一下刚刚copy 的结果? y/n" ch =in . readLine ();

if (ch . length ()==1){

if (ch . charAt (0)=='y' |

ch . charAt (0)=='Y' )

{content =save ; break ;}

);

if (ch . charAt

(

)=='n' |

ch . charAt (0)=='N' )

break ;

}

}

}

else {

System. out . println (" 请输入密文" );

content=in . readLine ();

}

System. out . println (" 请输入密钥" );

key=in . readLine ();

Decrypt de=new Decrypt();

out=de . textDecrypt (content , key);

System. out . print (out );

}catch (IOException e){

e. printStackTrace ();System . out . println (" 未知错误);} break ;

运行结果

2. RC4算法

算法分析

RC4算法的原理包括初始化算法和伪随机子密码生成算法两大部分。

假设S-box 长度和密钥长度均为n 。

算法的初始化部分 for (i =0; i

{

s[i ]=i ;

}

j =0;

for (i =0; i

{

j=(j +s [i ]+k [i ])%n ;

swap(s [i ], s

[j ]);

}

在初始化的过程中,密钥的主要功能是将S-box 搅乱,i 确保S-box 的每个元素都得到处理,j 保证S-box 的搅乱是随机的。而不同的S-box 在经过伪随机子密码生成算法的处理后可以得到不同的子密钥序列。

i =j =0;

while (明文未结束)

{

++i %=n ;

j=(j +s )%n ;

swap(s , s[j ]);

sub_k=s ((s +s [j ])%n );

}

得到的子密码sub_k用以和明文进行异或运算,得到密文,解密过程也完全相同。

编程实现 package RC4;

import java.util.Scanner;

public class RC4 {

public static String decry_RC4(byte [] data, String key) {

if (data == null || key == null ) {

return null ;

}

return asString(RC4Base (data , key));

}

public static String decry_RC4(String data, String key) {

if (data == null || key == null ) {

return null ;

}

return new String(RC4Base (HexString2Bytes (data ), key));

}

public static byte [] encry_RC4_byte(String data, String key) { if (data == null || key == null ) {

return null ;

}

byte b_data[] = data. getBytes ();

return RC4Base(b_data, key);

}

public static String encry_RC4_string(String data, String key) { if (data == null || key == null ) {

return null ;

}

return toHexString(asString (encry_RC4_byte(data , key))); }

private static String asString(byte [] buf) {

StringBuffer strbuf = new StringBuffer(buf . length );

for (int i = 0; i

strbuf. append ((char ) buf[i ]);

}

return strbuf. toString ();

}

private static byte [] initKey(String aKey) {

byte [] b_key = aKey. getBytes ();

byte state[] = new byte [256];

for (int i = 0; i

state[i ] = (byte ) i;

}

int index1 = 0;

int index2 = 0;

if (b_key == null || b_key. length == 0) {

return null ;

}

for (int i = 0; i

index2 = ((b_key[index1] & 0xff )

+ (state [i ] & 0xff ) + index2) & 0xff ;

byte tmp = state[i ];

state[i ] = state[index2];

state[index2] = tmp;

index1 = (index1 + 1) % b_key. length ;

}

return state;

}

private static String toHexString(String s) {

String str = "" ;

for (int i = 0; i

int ch = (int ) s. charAt (i );

String s4 = Integer. toHexString (ch & 0xFF );

if (s4. length () == 1) {

s4 = '0' + s4;

}

str = str + s4;

}

return str; // 0x表示十六进制

}

private static byte [] HexString2Bytes(String src) {

int size = src. length ();

byte [] ret = new byte [size / 2];

byte [] tmp = src. getBytes ();

for (int i = 0; i

ret[i ] = uniteBytes(tmp [i * 2], tmp[i * 2 + 1]);

}

return ret;

}

private static byte uniteBytes(byte src0, byte src1) {

char _b0 = (char ) Byte. decode (

"0x" + new String(new byte [] { src0 })).byteValue ();

_b0 = (char ) (_b0

char _b1 = (char ) Byte. decode (

"0x" + new String(new byte [] { src1 })).byteValue ();

byte ret = (byte ) (_b0 ^ _b1);

return ret;

}

private static byte [] RC4Base(byte [] input, String mKkey) { int x = 0, y = 0;

byte key[] = initKey(mKkey );

int xorIndex;

byte [] result = new byte [input . length ];

for (int i = 0; i

x = (x + 1) & 0xff ;

y = ((key [x ] & 0xff ) + y) & 0xff ;

byte tmp = key[x ];

key[x ] = key[y ];

key[y ] = tmp;

xorIndex = ((key [x ] & 0xff ) + (key [y ] & 0xff )) & 0xff ; result[i ] = (byte ) (input [i ] ^ key[xorIndex ]);

}

return result;

}

public static void main(String [] args) {

System. out . println (" 请输入明文:" );

Scanner in=new Scanner(System . in );

String inputStr, keyStr;

inputStr=in . nextLine ();

System. out . println (" 请输入密钥:" );

keyStr = in. nextLine ();

String str = encry_RC4_string(inputStr , keyStr);

System. out . println (" 加密后的密文:" +str );

System. out . print (" 解密后的明文:" );

System. out . println (decry_RC4(str , keyStr));

}

}

运行结果

测试数据1

测试数据2

[问题讨论]

1. 改变明文或密钥中的一个比特值可能影响AES 值中的多少比特?

答:明文和密钥在S 盒置换时,不同的字节会替换出不同的结果。算法过程

中一共进行了10轮加密,所以改变一个比特值可能影响AES 值中的80

比特(8 x 10)。

2. 在RC4的密钥流生成中,改变初始密钥的一个比特值可能影响输

出中的多少比特?

答:初始密钥的不同会导致S 盒的不同,所以可能影响输出中的256比特。

3. 分析实验中在编辑编译运行等各环节中所出现的问题及解决方法。

答:在AES 算法实现过程中,在对输入数据的处理上遇到了很多的问题,刚

开始的时候习惯性地使用string 的形式保存S 盒等数据,但是由于AES

算法用到了很多的异或和移位操作,使用string 和char 形式数据的弊

端就慢慢地暴露了出来。然后在网上查阅了很多资料,最后选择了使用

byte 类型的数据,在整个算法的实现过程中,进一步加深了我对AES 加

密算法和RC4算法的理解。

实验二 SKEY 协议设计实验

[实验目的]

1.掌握身份认证协议的原理和基本思想。

2.掌握SKEY 协议的机制和实现方法。

[实验预备]

1.SKEY 协议的作用。

2.SKEY 协议的安全性分析。

3.SKEY 协议的实现过程。

[实验内容]

1. 分析SKEY 协议的实现过程。

2. 用程序设计语言将算法过程编程实现。

3. 演示SKEY 协议的身份鉴别过程。

[实验步骤]

1. 预习SKEY 协议的机制。

2. 选择和实现相应的摘要算法MD5或SHA。

3. 写出算法流程,用程序设计语言将协议过程编程实现。

4. 验证SKEY 协议的身份鉴别过程。

1. 协议分析

2. 协议实现

为了便于实现和演示,我采用了一个比较简单的方式进行。要模拟客户端保存数据比较不容易实现,对服务器生成的hash 值,保存在本地文件中, 这个hash 的值是动态变化的,每次hash 都会加上相应的登陆次数(这个hash 方式和一般的skey 协议有些不同),

这样可以动态的获取。通过文件读写的方式获得。对于

生成的

hash

值从100到0次访问的问题也是使用一个文件来储存,每次验证完成后,都会把前一次存的数据减1然后重新的写入文件中。

本次实验使用到了Java 中的文件读写,这是用到的两个辅助文件:

其中int.txt 存储登陆后修改的数据

(写进去的格式不是10进值的,所以在这里不能看出明文)

md5.txt 为存储hash 值的文件:

(共100条密钥)

MD5实现文件: package SKEY;

import

java. security . MessageDigest ;

import java. security . NoSuchAlgorithmException ;

public class MD5String {

private String string ;

// 全局数组

private final static String[] strDigits = {

"0" , "1" , "2" , "3" , "4" , "5" , "6" , "7" ,

public MD5String(String string ) {

this . string =string ;

}

private String byteToArrayString(byte bByte) {

int iRet = bByte;

if (iRet

iRet += 256; "8" , "9" , "A" , "B" , "C" , "D" , "E" , "F" };

}

int iD1 = iRet / 16;

int iD2 = iRet % 16;

return strDigits[iD1] + strDigits[iD2];

}

// 转换字节数组为16进制字串

private String byteToString(byte [] bByte) {

StringBuffer sBuffer = new StringBuffer();

for (int i = 0; i

sBuffer. append (byteToArrayString (bByte [i ])); }

return sBuffer. toString ();

}

public String GetMD5Code() {

String resultString = null ;

try {

resultString = new String(string );

MessageDigest. getInstance ("MD5" );

MessageDigest md = MessageDigest. getInstance ("MD5" ); //该函数返回值为存放返回结果的byte 数组

md. digest (string . getBytes ());

byte [] bytes = md. digest (string . getBytes ()); resultString = byteToString(bytes );

} catch (NoSuchAlgorithmException ex) {

}

return resultString;

}

}

Skey 协议实现文件:

package SKEY;

import java. io . BufferedReader ;

import java. io . BufferedWriter ;

import java. io . File ;

import java. io . FileInputStream ;

import java. io . FileOutputStream ;

import java. io . FileReader ;

import java. io . FileWriter ;

import java. io . IOException ;

public class Skey {

String intsString =

"C://Users//zzy//workspace//Cryptology//int.txt";

String md5sString =

"C://Users//zzy//workspace//Cryptology//md5.txt";

File file_int = new File(intsString );

File file_md5 = new File(md5sString );

//初始化

public void GUI(String string) {

try {

FileOutputStream fos = new FileOutputStream(file_int); FileWriter writer = new FileWriter(file_md5);

BufferedWriter bw = new BufferedWriter(writer );

fos. write (1);

for (int a=1; a

MD5String md5 = new MD5String(string +a );

System. out . println (md5. GetMD5Code ());

bw. write (md5. GetMD5Code ().toString ());

bw. write ("\r\n");

}

bw. close ();

writer. close ();

FileInputStream fis = new FileInputStream(file_int); System. out . print (fis . read ());

fos. close ();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

public int compare(String string, String keys) {

int flag =0;

try {

FileInputStream fis = new FileInputStream(file_int); int a = fis. read ();

FileReader fileReader = new FileReader(file_md5);

BufferedReader bReader = new BufferedReader(fileReader ); //从文件读出来MD5值

String string2 = (String ) readLine (a , bReader);

if (string2. equals (keys )){

flag = 1;

- 20 -

}

FileOutputStream fos = new

FileOutputStream

(file_int); fos. write (a +1);

} catch (Exception e ) {

// TODO Auto-generated catch block

e. printStackTrace ();

}

return flag;

}

private String readLine(int lineNumber,

BufferedReader reader) throws Exception{

String line="" ;

int i=0;

while (i

line=reader . readLine ();

i++;

}

return line;

}

}

3. 运行结果

(初始化)

(认证登录)

- 21 -

(验证成功)

(如果再使用第一次的密钥或者其他密钥登陆)

(验证失败)

[问题讨论]

1. 分析SKEY 的安全性

答:1.每个数只使用一次,对数据库攻击用处不大

2.可防止重放攻击

2. 分析实验中在编辑编译运行等各环节中所出现的问题及解决方法

答:刚开始的时候对skey 协议的原理不太熟悉,导致在实现的初期中觉得

无从下手,后来通过查阅资料完全理解了skey 协议的流程以后,又在文件读写方面遇到了一些问题。包括后面MD5数字摘要算法的应用。通过这个实验,不只是学到了很多密码学方面是知识,更是对我个人编程

能力的一个提高。

- 22 -


相关内容

  • 网上支付与电子银行实验报告
  • 网上支付与电子银行实验报告 网上银行安全措施及手段分析与 银行的指纹银行业务发展情况 学生姓名: 桂彬彬 学 号: P2202110110 所在学院: 经济与管理学院 专 业: 信息管理与信息系统 指导教师: 戴 槟 2014年5月10日 目录 第一章 实验内容................... ...

  • 南京理工大学毕业设计开题报告
  • 南 京 理 工 大 学 毕业设计开题报告 学 生 姓 名: 朱林义 学 号: 10212016 专 业: 材料成型及其控制工程 设计(论文)题目:摩托车覆盖件逆向设计----前灯罩.前盖板设计 指 导 教 师: 赵东富 2006 年 4 月 20 日 开题报告填写要求 1.开题报告(含"文 ...

  • 密码学基础课程设计指导书
  • <现代密码学基础> 课程设计指导书 杨柳 编 湖南科技大学计算机科学与工程学院 2014年12月 一.概述 本课程在简要复习数学基础知识之后,探讨了密码学研究的基本问题:通过不安全的通信媒介如何进行安全通信.也可以理解为关心任何希望限制不诚实者达到目的的问题,把度量和评价一个密码体制(协 ...

  • 随着电子商务的发展
  • 维普资讯 http://www.cqvip.com 随着电子商务的发展 ,网上银行.网上合同.电子签名等的应用越来越广泛 , 网络 已经成为我们生活中不 可缺少的一部分 , 在我们的生活中担 当着一个重要的角色. 然而,当电子商务给我们的工作.生活带来便捷的 同时,也不可避免地存在着安全隐患.一直在 ...

  • 综合测评管理系统实验报告
  • 目 录 摘 要............................................................................................................................................... ...

  • 初步认识管理信息系统实验报告
  • 南京信息工程大学 实验(实习)报告 实验(实习)名称 MIS 基础实验 日期 2014.3.21 得分 指导教师 系 经济管理 专业 物流管理 年级 一 班次 1 姓名 徐建华 学号 [1**********] 实验一 初步认识管理信息系统 一.实验目的 (1)初步认识管理信息系统,建立对管理信息系 ...

  • 网络安全应用实训报告
  • 安全技术及应用实训 项目二:网络安全应用实训项目 报告 目 录 任务1 知识剖析 ........................................................................................................... 1 ...

  • 申报副教授业务自传
  • 一.专业知识方面 任现职以来,我注重学习数学教育理论,了解我国基础教育改革的最新动向,xxxx年参加了国家级和自治区级的数学新课程培训,xxxx年参加教育部数学教育高级研讨班,xxxx到南京师范大学作为访学学者进行了为期一年的数学教育理论学习和课题研究工作,我的专业基础知识扎实,数学教育理论研究水平 ...

  • 遗传信息的翻译说课稿
  • <基因指导蛋白质的合成>第二课时 遗传信息的翻译 尊敬的评委.尊敬的同仁: 大家好! 大家刚才欣赏的是<侏罗纪公园1>片段,导演是谁呢?是美国著名电影导演史蒂文·斯皮尔伯格.他是如何让6600万年前的恐龙复活呢?通过影片我们知道:6600万年前的蚊子吸取恐龙的血后变成琥珀,科 ...