一、实验目的
学习ElGamal公私钥加密算法的基本原理和特点,能够编写简单的实验代码实现ElGamal公钥加密和私钥解密过程。
二、实验要求
4. 熟悉ElGamal公私钥加密算法。
5. 了解如何使用Java简单实现ElGamal公私钥加密算法。
6. 掌握ElGamal公私钥加密算法的简单代码实验。
拓展:了解如何计算 的生成元 。
三、开发环境
JDK1.6,Java相关开发环境(本实验以Windows平台为例)
四、实验内容
【1-1】ElGamal公私钥加密算法实验
1、使用如下函数对系统初始化,生成大素数p和算 的生成元 。
public static void init() {
System.out.println("系统正在初始化");
while(true) {
//Runtime.getInstance().exec("cls");
//获得512位长度的大素数q
q=BigInteger.probablePrime(512, new Random());
//计算p=2q
p=q.multiply(new BigInteger("2")).add(new BigInteger("1"));
//判断p是不是素数
if(p.isProbablePrime(20))
break;
}
//找出Zp的生成元g
g=GetPrimordialRoot();
System.out.println("系统初始化完成");
}
使用如下的函数进行密钥初始化
public static void KeyGenerator()throws Exception {
StringBuffer key=new StringBuffer();
//随机生成256位的密钥
for(int i=0;i<256;i++) {
Random ran=new Random();
int x=ran.nextInt(10);
if(x>5)
key=key.append(1);
else
key=key.append(0);
}
//构造私钥钥
SecurityKey privateKey=new SecurityKey(new BigInteger(key.toString(),2),p,g);
//构造公钥
SecurityKey publicKey=new SecurityKey(g.modPow(privateKey.getKey(), p),p,g);
//把公钥和私钥分别存储在publicKey.key和privateKey.key文件里
String path=new File("").getCanonicalPath();
out(path+"\\privateKey.key",privateKey.getKey()+","+privateKey.getP()+","+privateKey.getG());
out(path+"\\publicKey.key",publicKey.getKey()+","+publicKey.getP()+","+publicKey.getG());
System.out.println("你的私钥存放在:"+path+"\\privateKey.key");
System.out.println("你的公钥存放在:"+path+"\\publicKey.key");
}
给定公钥和待加密消息,使用如下的函数进行加密:
//加密算法 如果待加密消息过长,可分段传入。
public static String encrypt(SecurityKey Publickey,String data){
try {
BigInteger M=ChangeBase.ecode(data);
StringBuffer C=new StringBuffer();
Random ran=new Random();
//k<p-1.我们这里取他的子集
int k=ran.nextInt(1000000000);
//计算c1
BigInteger C1=Publickey.getG().modPow(new BigInteger(k+""), Publickey.getP());
//计算c2
BigInteger C2=Publickey.getKey().modPow(new BigInteger(k+""),Publickey.getP())
.multiply(M).mod(Publickey.getP());
C.append(C1+":"+C2+",");
return Base64.getEncoder().encodeToString(C.toString().getBytes());
}
catch(Exception ex)
{
ex.printStackTrace();
}
return null;
}
给定私钥和待解密的密文,使用如下的函数进行解密:
//解密算法
public static String decrypt(SecurityKey Privatekey,String data) {
try {
String ciphertext= new String(Base64.getDecoder().decode(data),"utf8");
//分解密文
String[] CS=ciphertext.split(",");
List<Byte> Plaintext=new ArrayList<>();
String C=CS[0];
//获得每块的C1和C2
BigInteger C1=new BigInteger(C.split(":")[0]);
BigInteger C2=new BigInteger(C.split(":")[1]);
//在这里不能简单的用除法,而是乘以逆元
BigInteger m=C2.multiply(C1.modPow(Privatekey.getKey().negate(), Privatekey.getP())).mod(Privatekey.getP());
BigInteger[] bigs= {m};
return ChangeBase.decode(bigs);
} catch(Exception ex){
ex.printStackTrace();
}
return null;
}
全部代码:
ChangeBase类
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
//压缩密文长度
public class ChangeBase {
//把传进来的明文编译成一个大数。
public static BigInteger ecode(String m) throws Exception{
byte[] ms=m.getBytes("utf8");
StringBuffer sb=new StringBuffer("11111111");
for(int j=0;j<ms.length;j++)
{
if(j<ms.length) {
String big= new BigInteger(Byte.toUnsignedInt(ms[j])+"").toString(2);
while(big.length()<8)
big=0+big;
sb.append(big);
}
}
return new BigInteger(sb+"",2);
}
//把传进来的大数编译成明文
public static String decode(BigInteger[] datas) throws Exception{
List<Byte> bss=new ArrayList<>();
for(int j=0;j<datas.length;j++) {
BigInteger data=datas[j];
String data0b=data.toString(2);
for(int i=1;i<data0b.length()/8;i++)
{
byte b=(byte)Integer.parseInt(new BigInteger(data0b.substring(i*8, i*8+8),2)+"");
bss.add(b);
}
}
Byte[] bs=new Byte[bss.size()];
byte[] bs1=new byte[bss.size()];
bss.toArray(bs);
for(int i=0;i<bs.length;i++)
{
bs1[i]=bs[i];
}
return new String(bs1,"utf8");
}
}
SecurityKey类
import java.math.BigInteger;
public class SecurityKey {
private BigInteger key;
private BigInteger p;
private BigInteger g;
public SecurityKey(BigInteger key,BigInteger p,BigInteger g) {
this.key=key;
this.p=p;
this.g=g;
}
public BigInteger getKey() {
return key;
}
public void setKey(BigInteger key) {
this.key = key;
}
public BigInteger getP() {
return p;
}
public void setP(BigInteger p) {
this.p = p;
}
public BigInteger getG() {
return g;
}
public void setG(BigInteger g) {
this.g = g;
}
}
ElGamal类
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
public class ElGamal {
static BigInteger p=null;//p=2q+1
static BigInteger q=null;
static BigInteger g=null;
//获取Zp的生成元(p的本源根)g
public static BigInteger GetPrimordialRoot() {
BigInteger PrimordialRoot=new BigInteger("2");
while(PrimordialRoot.compareTo(p.subtract(new BigInteger("1")))==-1) {
//判断是否为本源根,具体证明见附件
if(PrimordialRoot.modPow(new BigInteger("2"), p).equals(new
BigInteger("1"))||PrimordialRoot.modPow(q, p).equals(new BigInteger("1")))
PrimordialRoot=PrimordialRoot.add(new BigInteger("1"));
else
break;
}
if(PrimordialRoot.compareTo(p.subtract(new BigInteger("1")))==-1)
return PrimordialRoot;
else
return null;
}
//初始化系统,生成大素数p,p的本源根g。
public static void init() {
System.out.println("系统正在初始化");
while(true) {
//Runtime.getInstance().exec("cls");
//获得512位长度的大素数q
q=BigInteger.probablePrime(512, new Random());
//计算p=2q
p=q.multiply(new BigInteger("2")).add(new BigInteger("1"));
//判断p是不是素数
if(p.isProbablePrime(20))
break;
}
//找出Zp的生成元g
g=GetPrimordialRoot();
System.out.println("系统初始化完成");
}
//生成公私钥对
public static void KeyGenerator()throws Exception {
StringBuffer key=new StringBuffer();
//随机生成256位的密钥
for(int i=0;i<256;i++) {
Random ran=new Random();
int x=ran.nextInt(10);
if(x>5)
key=key.append(1);
else
key=key.append(0);
}
//构造私钥钥
SecurityKey privateKey=new SecurityKey(new BigInteger(key.toString(),2),p,g);
//构造公钥
SecurityKey publicKey=new SecurityKey(g.modPow(privateKey.getKey(), p),p,g);
//把公钥和私钥分别存储在publicKey.key和privateKey.key文件里
String path=new File("").getCanonicalPath();
out(path+"\\privateKey.key",privateKey.getKey()+","+privateKey.getP()+","+privateKey.getG());
out(path+"\\publicKey.key",publicKey.getKey()+","+publicKey.getP()+","+publicKey.getG());
System.out.println("你的私钥存放在:"+path+"\\privateKey.key");
System.out.println("你的公钥存放在:"+path+"\\publicKey.key");
}
//加密算法
public static String encrypt(SecurityKey Publickey,String data){
try {
BigInteger M=ChangeBase.ecode(data);
StringBuffer C=new StringBuffer();
Random ran=new Random();
//k<p-1.我们这里取他的子集
int k=ran.nextInt(1000000000);
//计算c1
BigInteger C1=Publickey.getG().modPow(new BigInteger(k+""), Publickey.getP());
//计算c2
BigInteger C2=Publickey.getKey().modPow(new BigInteger(k+""), Publickey.getP()).multiply(M).mod(Publickey.getP());
C.append(C1+":"+C2+",");
return Base64.getEncoder().encodeToString(C.toString().getBytes());
}
catch(Exception ex)
{
ex.printStackTrace();
}
return null;
}
//解密算法
public static String decrypt(SecurityKey Privatekey,String data) {
try {
String ciphertext= new String(Base64.getDecoder().decode(data),"utf8");
//分解密文
String[] CS=ciphertext.split(",");
List<Byte> Plaintext=new ArrayList<>();
String C=CS[0];
//获得每块的C1和C2
BigInteger C1=new BigInteger(C.split(":")[0]);
BigInteger C2=new BigInteger(C.split(":")[1]);
//在这里不能简单的用除法,而是乘以逆元
BigInteger m=C2.multiply(C1.modPow(Privatekey.getKey().negate(), Privatekey.getP())).mod(Privatekey.getP());
BigInteger[] bigs= {m};
return ChangeBase.decode(bigs);
}
catch(Exception ex)
{
ex.printStackTrace();
}
return null;
}
//封装输出流
public static void out(String path,String val) {
try {
val=Base64.getEncoder().encodeToString(val.getBytes("utf8"));
FileWriter fw=new FileWriter(path);
BufferedWriter bw=new BufferedWriter(fw);
PrintWriter outs=new PrintWriter(bw);
outs.println(val);
outs.flush();
outs.close();
}
catch(Exception ex) {
ex.printStackTrace();
}
}
//从文件中读取公私钥
public static SecurityKey read(String path){
SecurityKey sk=null;
try {
File f=new File(path);
FileReader fr=new FileReader(f);
BufferedReader br=new BufferedReader(fr);
String line=null;
StringBuffer sb=new StringBuffer();
while((line=br.readLine())!=null)
{
byte[] b= Base64.getDecoder().decode(line);
String[] key=new String(b,"utf8").split(",");
if(key.length<3)
throw new Exception("文件错误");
sk=new SecurityKey(new BigInteger(key[0]),new BigInteger(key[1]),new BigInteger(key[2]));
}
br.close();
return sk;
}
catch(Exception ex)
{
ex.printStackTrace();
}
return sk;
}
public static void main(String[] args) {
try {
//执行系统初始化生成p,g
init();
//构造公私钥
KeyGenerator();
Scanner sc=new Scanner(System.in);
String str ="";
sc.useDelimiter("\n");
System.out.print("请输入公钥地址按回车结束:");
if(sc.hasNext())
{
str=sc.next();
}
//获取公钥
SecurityKey publicKey= read(str.substring(0,str.length()-1));
System.out.print("请输入需要加密的文字按回车结束:");
if(sc.hasNext())
{
str=sc.next();
} //加密明文
String c=encrypt(publicKey,str);
System.out.println("加密结果:"+c);
System.out.print("请输入私钥地址按回车可对密文数据进行解密:");
if(sc.hasNext())
{
str=sc.next();
}
//获得私钥
SecurityKey privateKey= read(str.substring(0,str.length()-1));
//解密密文
String m=decrypt(privateKey,c);
System.out.println("解密明文:"+m);
sc.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
}