数字签名的编程实现

实用数字签名的步骤
(1)发送方使用MD5算法对原始信息进行计算,获得一个固定长度的信息摘要
(2)发送方用自己的私钥加密生成的信息生成发送方的数字签名,发送方把这个数字签名作为发送信息的附件和明文信息,一同用接收方的公钥进行加密,将加密后的密文一同发送给接收方;
(3)接收方首先把接收到的密文用自己的私钥解密,得到明文信息和数字签名,再用发送方的公钥对数字签名进行解密,然后使用相同的单向散列算法来计算解密得到的明文信息,得到信息摘要;对比计算出来的信息摘要和发送方发送过来的信息摘要是否一致

以下是我写的主要代码如下:

 

/*
 * md5对原始信息计算得到一个固定长度的信息摘要
 */

public class MD5Algorithmic {
 private String MD5;

 public MD5Algorithmic(String msg) {
  MD5 = msg;
 }
 /*
  * @return  一个固定长度的信息摘要
  */
 public String getDigest() {
  try {
   MessageDigest md = MessageDigest.getInstance("MD5");
   byte[] md5 = md.digest(MD5.getBytes());
   StringBuffer sb = new StringBuffer();
   String part = null;
   for (int i = 0; i < md5.length; i++) {
    part = Integer.toHexString(md5[i] & 0xFF);
    if (part.length() == 1) {
     part = "0" + part;
    }
    sb.append(part);
   }
   //System.out.println(sb.append(part));
   return sb.toString();
  } catch (NoSuchAlgorithmException ex) {
  }
  return null;

 }
}

 

/**
 * RSA 工具类。提供加密,解密,生成密钥对等方法。
 * 需要到http://www.bouncycastle.org/下载bcprov-jdk14-123.jar。
 */
public class RSAUtil {

 /**
  * 生成密钥对
  *
  * @return KeyPair
  * @throws EncryptException
  */
 public static KeyPair generateKeyPair() {
  try {
   KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA",
     new org.bouncycastle.jce.provider.BouncyCastleProvider());
   final int KEY_SIZE = 1024;// 没什么好说的了,这个值关系到块加密的大小,可以更改,但是不要太大,否则效率会低
   keyPairGen.initialize(KEY_SIZE, new SecureRandom());
   KeyPair keyPair = keyPairGen.genKeyPair();
   return keyPair;
  } catch (Exception e) {
   
  }
  return null;
 }

 /**
  * 生成公钥
  *
  * @param modulus
  * @param publicExponent
  * @return RSAPublicKey
  * @throws EncryptException
  */
 public static RSAPublicKey generateRSAPublicKey(byte[] modulus,
   byte[] publicExponent) {
  KeyFactory keyFac = null;
  try {
   keyFac = KeyFactory.getInstance("RSA",
     new org.bouncycastle.jce.provider.BouncyCastleProvider());
  } catch (NoSuchAlgorithmException ex) {
   
  }

  RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
    modulus), new BigInteger(publicExponent));
  try {
   return (RSAPublicKey) keyFac.generatePublic(pubKeySpec);
  } catch (InvalidKeySpecException ex) {
   
  }
  return null;
 }

 /**
  * 生成私钥
  *
  * @param modulus
  * @param privateExponent
  * @return RSAPrivateKey
  * @throws EncryptException
  */
 public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus,
   byte[] privateExponent) {
  KeyFactory keyFac = null;
  try {
   keyFac = KeyFactory.getInstance("RSA",
     new org.bouncycastle.jce.provider.BouncyCastleProvider());
  } catch (NoSuchAlgorithmException ex) {
   
  }

  RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(
    modulus), new BigInteger(privateExponent));
  try {
   return (RSAPrivateKey) keyFac.generatePrivate(priKeySpec);
  } catch (InvalidKeySpecException ex) {
   
  }
  return null;
 }

 /**
  * 加密
  *
  * @param key
  *            加密的密钥
  * @param data
  *            待加密的明文数据
  * @return 加密后的数据
  * @throws EncryptException
  */
 public static byte[] encrypt(Key key, byte[] data) {
  try {
   Cipher cipher = Cipher.getInstance("RSA",
     new org.bouncycastle.jce.provider.BouncyCastleProvider());
   cipher.init(Cipher.ENCRYPT_MODE, key);
   int blockSize = cipher.getBlockSize();// 获得加密块大小,如:加密前数据为128个byte,而key_size=1024
   // 加密块大小为127
   // byte,加密后为128个byte;因此共有2个加密块,第一个127
   // byte第二个为1个byte
   int outputSize = cipher.getOutputSize(data.length);// 获得加密块加密后块大小
   int leavedSize = data.length % blockSize;
   int blocksSize = leavedSize != 0 ? data.length / blockSize + 1
     : data.length / blockSize;
   byte[] raw = new byte[outputSize * blocksSize];
   int i = 0;
   while (data.length - i * blockSize > 0) {
    if (data.length - i * blockSize > blockSize)
     cipher.doFinal(data, i * blockSize, blockSize, raw, i
       * outputSize);
    else
     cipher.doFinal(data, i * blockSize, data.length - i
       * blockSize, raw, i * outputSize);
    // 这里面doUpdate方法不可用,查看源代码后发现每次doUpdate后并没有什么实际动作除了把byte[]放到ByteArrayOutputStream中,而最后doFinal的时候才将所有的byte[]进行加密,可是到了此时加密块大小很可能已经超出了OutputSize所以只好用dofinal方法。

    i++;
   }
   return raw;
  } catch (Exception e) {
   
  }
  return null;
 }

 /**
  * 解密
  *
  * @param key
  *            解密的密钥
  * @param raw
  *            已经加密的数据
  * @return 解密后的明文
  * @throws EncryptException
  */
 public static byte[] decrypt(Key key, byte[] raw) {
  try {
   Cipher cipher = Cipher.getInstance("RSA",
     new org.bouncycastle.jce.provider.BouncyCastleProvider());
   cipher.init(cipher.DECRYPT_MODE, key);
   int blockSize = cipher.getBlockSize();
   ByteArrayOutputStream bout = new ByteArrayOutputStream(64);
   int j = 0;

   while (raw.length - j * blockSize > 0) {
    bout.write(cipher.doFinal(raw, j * blockSize, blockSize));
    j++;
   }
   return bout.toByteArray();
  } catch (Exception e) {
   
  }
  return null;
 }

 /**
  *
  * @param args
  * @throws Exception
  */
 public static void main(String[] args) throws Exception {
  KeyPair keyPair = RSAUtil.generateKeyPair();
  RSAPublicKey pubKey = (RSAPublicKey) keyPair.getPublic();
  RSAPrivateKey priKey = (RSAPrivateKey) keyPair.getPrivate();
  ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
    "src/client/APriKey.txt"));
  out.writeObject(priKey);
  out = new ObjectOutputStream(new FileOutputStream("src/server/APubKey.txt"));
  out.writeObject(pubKey);
  KeyPair keyPair2 = RSAUtil.generateKeyPair();
  RSAPublicKey pubKey2 = (RSAPublicKey) keyPair.getPublic();
  RSAPrivateKey priKey2 = (RSAPrivateKey) keyPair.getPrivate();
  ObjectOutputStream out2 = new ObjectOutputStream(new FileOutputStream(
    "src/server/BPriKey.txt"));
  out2.writeObject(priKey2);
  out2= new ObjectOutputStream(new FileOutputStream("src/client/BPubKey.txt"));
  out2.writeObject(pubKey2);
  out2.close();

 }
}

 

 

 

public class ClientApp extends JApplet implements Runnable {
 private JTextField inputField;
 private JTextArea displayArea;
 private String message;// 发送的原文
 private DataInputStream input;
 private DataOutputStream output;
 private Socket connection;
 private PrivateKey APriKey;
 private PublicKey bPubKey;
 MD5Algorithmic md5;
 String Msg_Digest;
 public ClientApp(){
  md5=new MD5Algorithmic("");
  Msg_Digest=new String();
  // 读取私钥
  ObjectInputStream inStream;
  try {
   inStream = new ObjectInputStream(new FileInputStream(
     "client/APriKey.txt"));
   try {
    APriKey = (PrivateKey) inStream.readObject();
   } catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   // 读取公钥
   inStream = new ObjectInputStream(new FileInputStream(
     "client/BPubKey.txt"));
   try {
    bPubKey = (PublicKey) inStream.readObject();
   } catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   inStream.close();
  } catch (FileNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 private void displayMessage(final String message) {
  SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    displayArea.append(message + "\n");
    displayArea.setCaretPosition(displayArea.getText().length());
   }
  });
 }

 /*
  * run前初始化
  */
 public void init() {
  Container container = getContentPane();
  displayArea = new JTextArea(4, 60);
  displayArea.setEditable(false);
  container.add(new JScrollPane(displayArea), BorderLayout.CENTER);
  inputField = new JTextField();
  
  inputField.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent event) {
    message = inputField.getText().trim();// 发送的原文 
    inputField.setEditable(true);
    md5 = new MD5Algorithmic(message);
    Msg_Digest = md5.getDigest();
    displayMessage(message);
    inputField.setText("");
    //发送
    // 发送方用自己的私钥加密Msa_Digest,生成数字签名,signatrue
    byte[] signatrue = new byte[1024];
    signatrue = RSAUtil.encrypt(APriKey, Msg_Digest.getBytes());
    // 发送方把原文message和数字签名signatrue用bPubKey加密
    byte[] encrypt1 = new byte[1024];
    encrypt1 = RSAUtil.encrypt(bPubKey, message.getBytes());
    byte[] encrypt2=new byte[1024];
    encrypt2 = RSAUtil.encrypt(bPubKey,signatrue);
    try {
     output.write(encrypt2);
     output.write(encrypt1);
     output.flush();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    
   }
  });
  container.add(inputField, BorderLayout.SOUTH);

 }

 public void start() {
  try {
   connection = new Socket(getCodeBase().getHost(), 12345);
   input = new DataInputStream(connection.getInputStream());
   output = new DataOutputStream(connection.getOutputStream());
  } catch (IOException ioException) {
   ioException.printStackTrace();
  }
  
  Thread outputThread = new Thread(this);
  outputThread.start();
 }

 public void run() {
  try {
   while(true)
   {
    
   step1(); 
   }
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }
 private String byteToString( byte[] buf ){
  String res = "";
  for( int i = 0 ; i < buf.length ; i ++ )
   res += (char) buf[i];
  return res;
 }
 private byte[] getByte()
 {
  
  try {
   byte[] buf = new byte[1024];
   int cnt = input.read( buf );
   byte[] tmp = new byte[1024];
   for( int i = 0 ; i < cnt ; i ++ )  tmp[i] = buf[i];
   return tmp;
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return null;
  
 }
 /*
  * 接收比较判断
  */
 private void step1() throws IOException {
  String msg1;
  String msg2;
  byte[] temp=RSAUtil.decrypt(APriKey, getByte());//私钥解密数字签名
  msg1 = byteToString(RSAUtil.decrypt(APriKey,getByte()));// 私钥解密明文信息
  msg2 = byteToString(RSAUtil.decrypt(bPubKey,temp));// 公钥jie密数字签名
  // 由明文信息得到信息摘要
  MD5Algorithmic md5 = new MD5Algorithmic(msg1);
  displayMessage("接收到的明文信息:"+msg1);
  msg1 = md5.getDigest();
  System.out.println(msg1);
  System.out.println(msg2);
  displayMessage("计算接收明文信息得到的信息摘要:"+msg1);
  displayMessage("发送方给我的信息摘要:"+msg2); 
  if (msg1.equals(msg2)) {
   displayMessage("数字签名确实是发送方的。");
  } else
   displayMessage("收到的信息是伪造的或中途被篡改的。");

 }

 /*
  * 发送
  */
 private void step2() throws IOException {
  inputField.setEditable(true);
  

 }
}

 

 

public class Server extends JApplet implements Runnable {
 private JTextField inputField;
 private JTextArea displayArea;
 private String message;// 发送的原文
 private DataInputStream input;
 private DataOutputStream output;
 private ServerSocket server;
 private Socket connection;
 private PrivateKey bPriKey;
 private PublicKey APubKey;
 MD5Algorithmic md5;
 String Msg_Digest;

 public Server() {
  try {
   server = new ServerSocket(12345, 1);
   try {
    // 读取私钥
    ObjectInputStream inStream;
    inStream = new ObjectInputStream(new FileInputStream(
      "server/BPriKey.txt"));
    try {
     bPriKey = (PrivateKey) inStream.readObject();
    } catch (ClassNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    // 读取公钥
    inStream = new ObjectInputStream(new FileInputStream(
      "server/APubKey.txt"));
    try {
     APubKey = (PublicKey) inStream.readObject();
    } catch (ClassNotFoundException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    
    inStream.close();
   } catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }

 private void displayMessage(final String message) {
  SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    displayArea.append(message + "\n");
    displayArea.setCaretPosition(displayArea.getText().length());
   }
  });
 }

 public void start() {
  try {
   connection = server.accept();
   input = new DataInputStream(connection.getInputStream());
   output = new DataOutputStream(connection.getOutputStream());
  } catch (IOException ioException) {
   ioException.printStackTrace();
  }
  
  Thread outputThread = new Thread(this);
  outputThread.start();
 }

 /*
  * run前初始化
  */
 public void init() {
  Container container = getContentPane();
  displayArea = new JTextArea(4, 60);
  displayArea.setEditable(false);
  container.add(new JScrollPane(displayArea), BorderLayout.CENTER);
  inputField = new JTextField();
  //发送
  inputField.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent event) {
    message = inputField.getText().trim();// 发送的原文
    md5 = new MD5Algorithmic(message);
    Msg_Digest = md5.getDigest();
    displayMessage(message);
    inputField.setText("");
    inputField.setEditable(true);
    // 发送方用自己的私钥加密Msa_Digest,生成数字签名,signatrue
    byte[] signatrue = new byte[1024];
    signatrue = RSAUtil.encrypt(bPriKey, Msg_Digest.getBytes());
    // 发送方把原文message和数字签名signatrue用bPubKey加密
    byte[] encrypt1 = new byte[1024];
    encrypt1 = RSAUtil.encrypt(APubKey, message.getBytes());
    byte[] encrypt2=new byte[1024];
    encrypt2 = RSAUtil.encrypt(APubKey,signatrue);
    try {
     output.write(encrypt2);
     output.write(encrypt1);
     output.flush();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
    
   }
  });
  container.add(inputField, BorderLayout.SOUTH);

 }

 public void run() {
  try {
   while(true){
   step1();
   //step2();
   }

  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

 }
 private String byteToString( byte[] buf ){
  String res = "";
  for( int i = 0 ; i < buf.length ; i ++ )
   res += (char) buf[i];
  return res;
 }
 private byte[] getByte()
 {
  
  try {
   byte[] buf = new byte[1024];
   int cnt = input.read( buf );
   byte[] tmp = new byte[1024];
   for( int i = 0 ; i < cnt ; i ++ )  tmp[i] = buf[i];
   return tmp;
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return null;
  
 }
 /*
  * 接收,比较判断
  */
  private void step1() throws IOException {
   String msg1;
   String msg2;
   byte[] temp=RSAUtil.decrypt(bPriKey, getByte());//私钥解密数字签名
   msg1 = byteToString(RSAUtil.decrypt(bPriKey,getByte()));// 私钥解密明文信息
   msg2 = byteToString(RSAUtil.decrypt(APubKey,temp));// 公钥jie密数字签名
   // 由明文信息得到信息摘要
   MD5Algorithmic md5 = new MD5Algorithmic(msg1);
   displayMessage("接收到的明文信息:"+msg1);
   msg1 = md5.getDigest();
   System.out.println(msg1);
   System.out.println(msg2);
   displayMessage("计算接收明文信息得到的信息摘要:"+msg1);
   displayMessage("发送方给我的信息摘要:"+msg2); 
   if (msg1.equals(msg2)) {
    displayMessage("数字签名确实是发送方的。");
   } else
    displayMessage("收到的信息是伪造的或中途被篡改的。");

  }

}

 

 

转载于:https://www.cnblogs.com/guoyilin/archive/2009/04/09/1432763.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值