加密解密与数字签名

            在工作中,我们用到了加密与解密,以及数字签名,所以对它的原理以及实现进行讲解:

            实际上数字签名又称作基于PKI的电子签名, PKI的核心机构是电子认证服务提供者,即通称的认证机构CA,PKI签名的核心元素是由CA签发的数字证书,数字证书就如同日常生活中的身份证一样,用来标识网上实体的身份,CA就是对网上实体进行认证的第三方机构.数字证书就是CA机构对网上实体进行认证而产生的电子证书,它是数据签名的基础技术保障.CA机构对电子证书的有效性,有效期等提供查询服务.数字证书所包含公钥用来对使用对应的私钥加密的数据信息进行验证.

           数字签名实现的具体原理是:

1、 将报文按双方约定的HASH算法计算得到一个固定位数的报文摘要。在数学上保证,只要改动报文中任何一位,重新计算出的报文摘要值就会与原先的值不相符。这样就保证了报文的不可更改性。

2、 将该报文摘要值用发送者的私人密钥加密,然后连同原报文和数字证书(包含公钥)一起发送给接收者而产生的报文即称数字签名。

3、接收方收到数字签名后,用同样的HASH算法对报文计算摘要值,然后与用发送者的公开密钥进行解密解开的报文摘要值相比较,如相等则说明报文确实来自所称的发送者。

4、同时通过证书颁发机构CA确认证书的有效性即可确认发送的真实身份。

              数字证书的技术实现:

             数字证书是公钥的载体,是PKI的核心元素.数字证书符合X.509标准,现行的PIK机制一般为又证书,即一个实体一般有两个证书,两个密码对,一个用于电子签名,一个用于加密通信.按照X.509标准,一个标准和数字证书的格式为:

             CA《A》=CA{V,SN,AI,CA,UCA,A,UA,Ap,Ta}

             它将包含证书颁发机构和标识及用户的标识,证书ID,有效期等信息(详见参考资料),另外还包含CA对此证书内容的进行了数字签名,以验证此证书的有效性.在验证一个数字证书的过程中,对数字证书的数字签名的验证将递归进行,只到找到双方共同可信任的CA根证书为止.

             对于RSA产生的公钥、私钥,我们可以有两种方式可以对信息进行加密解密。私钥加密-公钥解密 和 公钥加密-私钥解密。

          下面用个例子说明一下:          

package edu.bjtu;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

class RSADemo {
	/**
	 * 公钥
	 */
	private RSAPublicKey publicKey;
	/**
	 * 私钥
	 */
	private RSAPrivateKey privateKey;
	/**
	 * 用于加解密
	 */
	private Cipher cipher;
	/**
	 * 明文块的长度 它必须小于密文块的长度 - 11
	 */
	private int originLength = 128;
	/**
	 * 密文块的长度
	 */
	private int encrytLength = 256;

	/**
	 * 得到初始化的公钥和私钥
	 *
	 * @throws NoSuchAlgorithmException
	 * @throws NoSuchPaddingException
	 */
	public void initKey() throws NoSuchAlgorithmException,
			NoSuchPaddingException {
		// RSA加密算法:创建密钥对,长度采用2048
		KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA");
		kg.initialize(encrytLength * 8);
		KeyPair keypair = kg.generateKeyPair();
		// 分别得到公钥和私钥
		publicKey = (RSAPublicKey) keypair.getPublic();
		privateKey = (RSAPrivateKey) keypair.getPrivate();
		System.out.println("public key: " + publicKey);
		System.out.println("private key: " + privateKey);
	}

	/**
	 * 将公钥保存至文件
	 *
	 * @param file
	 *            待写入的文件
	 * @return true 写入成功;false 写入失败
	 */
	public boolean savePublicKey(File file) {
		return this.saveKey(publicKey, file);
	}

	/**
	 * 将私钥保持至文件
	 *
	 * @param file
	 *            待写入的文件
	 * @return true 写入成功;false 写入失败
	 */
	public boolean savePrivateKey(File file) {
		return this.saveKey(privateKey, file);
	}

	// 将Key文件保持到文件中
	private boolean saveKey(Key key, File file) {
		boolean write;
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(file);
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			// System.out.println(key.getFormat());
			// 公钥默认使用的是X.509编码,私钥默认采用的是PKCS #8编码
			byte[] encode = key.getEncoded();
			// 注意,此处采用writeObject方法,读取时也要采用readObject方法
			oos.writeObject(encode);
			write = true;
		} catch (IOException e) {
			write = false;
		} finally {
			try {
				if (fos != null)
					fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return write;
	}

	/**
	 * 从文件中得到公钥
	 *
	 * @param file
	 *            保存公钥的文件
	 */
	public void getPublicKey(File file) {
		getKey(file, 0);
	}

	/**
	 * 从文件中得到私钥
	 *
	 * @param file
	 *            保存私钥的文件
	 */
	public void getPrivateKey(File file) {
		getKey(file, 1);
	}

	private void getKey(File file, int mode) {
		FileInputStream fis;
		try {
			// 读取数据
			fis = new FileInputStream(file);
			ObjectInputStream ois = new ObjectInputStream(fis);
			byte[] keybyte = (byte[]) ois.readObject();
			// 关闭资源
			ois.close();
			// 默认编码
			KeyFactory keyfactory = KeyFactory.getInstance("RSA");
			// 得到公钥或是私钥
			if (mode == 0) {
				X509EncodedKeySpec x509eks = new X509EncodedKeySpec(keybyte);
				publicKey = (RSAPublicKey) keyfactory.generatePublic(x509eks);
				// System.out.println(pk.getAlgorithm());
			} else {
				PKCS8EncodedKeySpec pkcs8eks = new PKCS8EncodedKeySpec(keybyte);
				privateKey = (RSAPrivateKey) keyfactory
						.generatePrivate(pkcs8eks);
				// System.out.println(pk.getAlgorithm());
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 数据RSA加密 (用私匙加密)
	 *
	 * @param origin
	 *            明文
	 * @return 密文
	 */
	protected byte[] encrypt(byte[] origin) {
		// byte [] enc = new byte [encrytLength];
		byte[] enc = null;
		try {

			cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, privateKey);
			enc = cipher.doFinal(origin);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return enc;
	}

	/**
	 * 数据RSA解密 (用公匙解密)
	 *
	 * @param enc
	 *            密文
	 * @return 明文
	 */
	protected byte[] decrypt(byte[] enc) {
		// byte [] origin = new byte [originLength];
		byte[] origin = null;
		try {
			cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.DECRYPT_MODE, publicKey);
			origin = cipher.doFinal(enc);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return origin;
	}

	/**
	 * 加密文件
	 *
	 * @param origin
	 *            明文件
	 * @throws IOException
	 */
	public void encryptFile(File origin) throws IOException {
		FileInputStream fis = null;
		FileOutputStream fos = null;

		// 读入
		fis = new FileInputStream(origin);
		BufferedInputStream bis = new BufferedInputStream(fis);
		byte[] originbyte = new byte[originLength];
		// 写出
		fos = new FileOutputStream(new File(origin + ".encrypt"));
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		byte[] encryptbyte;
		// int k;
		while (bis.read(originbyte) > 0) {
			encryptbyte = this.encrypt(originbyte);
			bos.write(encryptbyte);
			originbyte = new byte[originLength];
		}
		// 压入
		bos.flush();
		// 关闭资源
		if (fis != null)
			fis.close();
		if (fos != null)
			fos.close();
	}

	/**
	 * 解密文件
	 *
	 * @param encrypt
	 *            密文件
	 * @throws IOException
	 */
	public void decryptFile(File encrypt) throws IOException {

		FileInputStream fis = null;
		FileOutputStream fos = null;
		// 读入
		fis = new FileInputStream(encrypt);
		BufferedInputStream bis = new BufferedInputStream(fis);
		byte[] encryptbyte = new byte[encrytLength];
		// 写出
		fos = new FileOutputStream(new File(encrypt + ".decrypt"));
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		byte[] originbyte;

		// int k;
		while (bis.read(encryptbyte) > 0) {
			originbyte = this.decrypt(encryptbyte);
			bos.write(originbyte);
			encryptbyte = new byte[encrytLength];
		}
		// 压入
		bos.flush();
		// 关闭资源
		if (fis != null)
			fis.close();
		if (fos != null)
			fos.close();
	}
}
package edu.bjtu;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;

/**
*
*/

   /**********************************
    * MD5 part
    **********************************/
}

/**
* MD5的算法在RFC1321 中定义
* 在RFC 1321中,给出了Test suite用来检验你的实现是否正确:
* MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
* MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
* MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
* MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
* MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
*
* @author yilee
*
* 传入:一个字节数组
* 传出:字节数组的 MD5 结果字符串
*/
class MD5Demo {

   public byte[] getFileBytes(String fileName) throws Exception {
           FileInputStream fis = new FileInputStream(fileName);
           BufferedInputStream bis = new BufferedInputStream(fis);

           ByteArrayOutputStream outStream = new ByteArrayOutputStream();
           byte[] data = new byte[4096];
           int count = -1;
           while ((count = bis.read(data, 0, 4096)) != -1) {
               outStream.write(data, 0, count);
           }

           data = null;
           if(fis != null) fis.close();

           return outStream.toByteArray();
   }

   public void saveString2File(String content, String fileName) throws Exception {
       BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName)));
       bw.write(content);
       bw.close();
   }

   public String getMD5(byte[] source) {
       String s = null;
       char hexDigits[] = { // 用来将字节转换成 16 进制表示的字符
           '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
       try {
           java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
           md.update(source);
           byte tmp[] = md.digest();          // MD5 的计算结果是一个 128 位的长整数,
           // 用字节表示就是 16 个字节
           char str[] = new char[16 * 2];   // 每个字节用 16 进制表示的话,使用两个字符,
           // 所以表示成 16 进制需要 32 个字符
           int k = 0;                                // 表示转换结果中对应的字符位置
           for (int i = 0; i < 16; i++) {    // 从第一个字节开始,对 MD5 的每一个字节
               // 转换成 16 进制字符的转换
               byte byte0 = tmp[i];  // 取第 i 个字节
               str[k++] = hexDigits[byte0 >>> 4 & 0xf];  // 取字节中高 4 位的数字转换,
               // >>> 为逻辑右移,将符号位一起右移
               str[k++] = hexDigits[byte0 & 0xf];   // 取字节中低 4 位的数字转换
           }
           s = new String(str);  // 换后的结果转换为字符串

       } catch (Exception e) {
           e.printStackTrace();
       }
       return s;
   }
}

package edu.bjtu;

/**
 * RSA加密算法的演示验证
 * RSA是一种分组加密算法
 * 注意:密钥对采用的长度决定了加密块的长度,我这里取的是2048,即256byte
 * 由于加密块的长度固定为256,因此明文的长度至多为256 - 11 = 245byte
 * 我这里明文长度取的是128byte,密文长度为256byte,它适合于小文件加密
 */

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
//import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

/**
 * 签名过程
 */
public class Cipher {
    public static void main(String[] args) throws Exception {

        // 1. 第一步: 对原始内容进行散列(MD5算法)
        MD5Demo md5 = new MD5Demo();
        byte[] srcContentBytes = md5.getFileBytes("d:\\test.txt");  // 获取原始内容字节流。test.txt是要签名的内容文件
        String md5Str = md5.getMD5(srcContentBytes);                // MD5散列
        md5.saveString2File(md5Str, "d:\\test.md5.txt");            // 保存散列内容到文件

        // 2. 第二步:得到私匙和公匙对
        RSADemo rsa = new RSADemo();
        rsa.initKey();
        rsa.savePublicKey(new File("D:\\public.key"));
        rsa.savePrivateKey(new File("D:\\private.key"));

        // 3. 第三步:使用私匙对散列内容加密。并把加密后的内容保存到文件 “散列文件.encrypt”
        // 3.1 然后,加密者把 原始内容文件+加密后的散列内容文件+公匙 发给解密者
        rsa.encryptFile(new File("D:\\test.md5.txt"));

        // 4. 解密者用公匙对“散列文件.encrypt”进行解密,得到解密后的散列内容,并保存到“散列文件.encrypt.decrypt”
        // 4.1 机密者对元素内容文件进行同样的散列,把得到的散列值和机密得到的散列值进行比对,如果一样,这任务元素内容是经过签名的,是可信的。
        rsa.decryptFile(new File("D:\\test.md5.txt.encrypt"));

    }
}
时间: 2024-09-20 05:21:30

加密解密与数字签名的相关文章

openssl如何利用导入的证书实现对文档加密解密、数字签名

问题描述 具体代码是什么?????? 解决方案 解决方案二:1.生成证书2.利用证书里的公钥加密3.用私钥解密代码参考cisoCA吧

详解.NET下的加密解密算法(3) 非对称加密

本博文列出了.NET下常用的非对称加密算法,并将它们制作成小DEMO,希望能对大家有所帮助. RSA static string EnRSA(string data,string publickey) { RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); byte[] cipherbytes; rsa.FromXmlString(publickey); cipherbytes = rsa.Encrypt(Encoding

RSA加密解密及RSA签名和验证

加密|解密 此Demo包含两个文件,建立一个解决方案,然后建立两个文件,一个为Form,一个为Class,把代码分别复制进去即可 RSA正确的执行过程:加密解密:1.获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥2.加密3.解密签名和验证:签名:1.获取密钥,这里是产生密钥,实际应用中可以从各种存储介质上读取密钥2.获取待签名的Hash码3.签名其中,1和2的步骤无所谓,在本例中,我们将对txtSource里的内容进行签名,也可以对文件进行签名验证签名:1.获取密钥,这里是产生

刚开始学OPENSSL , 请问rsa加密解密和验证签名有关系吗? 为什么需要验证签名。

问题描述 刚开始学OPENSSL , 请问rsa加密解密和验证签名有关系吗? 为什么需要验证签名. 我只想知道具体的工作过程,不必知道里面的算法是怎么实现的. 知道怎么去用就可以了,感觉自己越看与糊涂了. 求助 谢谢 解决方案 因为RSA算法是用的公钥,私钥机制来进行加解密,而私钥另一个用途就是验证身份,所以RSA加密本身也能用在身份验证,数字签名等场合. 这相当于RSA的多个用途 解决方案二: 公钥和私钥是一对的,这对密钥由个人向认证机构申请,最后由认证机构颁发私钥给你并在其网站上公布你的公钥

Swift 使用RSA算法进行数据加密,解密以及数字签名

RSA算法是一种非对称加密算法,要了解RSA算法,首先要知道什么是对称加密算法,什么是非对称加密算法. 1,对称加密算法 密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密. 特点:算法公开.计算量小.加密速度快.加密效率高特点.但交易双方都使用同样钥匙,安全性得不到保证. 具体算法有:DES算法,3DES算法,TDEA算法,Blowfish算法,RC5算法,IDEA算法. 2,非对称加密算法 非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey).

一步一步教你加密解密技术——软件保护技术(3)(1)

第三节 加密算法1.RSA算法它是第一个既能用于数据加密也能用于数字签名的算法.它易于理解和操作,也很流行.算法的名字以发明者的名字命名:Ron Rivest, Adi Shamir 和Leonard Adleman.但RSA的安全性一直未能得到理论上的证明.它经历了各种攻击,至今未被完 全攻破.一.RSA算法 : 首先,找出三个数,p,q,r,其中p,q是两个相异的质数,r是与(p-1)(q-1)互质的数......p,q,r这三个数便是privatekey接著,找出m,使得rm==1mod(

RSA加密解密(附源码工程)

版权声明:本文为博主原创文章,转载注明出处http://blog.csdn.net/u013142781 目录(?)[+] 一.RSA加密介绍 RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.1987年首次公布,当时他们三人都在麻省理工学院工作.RSA就是他们三人姓氏开头字母拼在一起组成的. RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,

详解.Net下的加密解密算法(6) 玩转非对称加密

本博文来聊聊怎么玩转非对称加密吧,这里主要介绍.NET算法下的3种非对称加密算法:DSA,RSA,ECDsa.上两篇博文分 别为Hash家族和非对称加密家族找到了lead,现在我们就为非对称加密技术找个合适的lead吧. 首先创建一个接口 :"IEncryptAndDecrypt",然后为上面的3中算法分别创建3个实现类并让这些类实现接口"IEncryptAndDecrypt".它们 的情况如下图: 这下我们把这些哥们都召集起来了,现在我们就给他们找一个lead:&

php中AES加密解密的例子小结

 话不多说,先放上代码,一共有两个文件:AES.php(aes算法类文件)和aesDemo.php(应用实例文件) aesDemo.php:   例子,    代码如下: <?php require_once('./AES.php'); //$aes = new AES(); $aes = new AES(true);// 把加密后的字符串按十六进制进行存储 //$aes = new AES(true,true);// 带有调试信息且加密字符串按十六进制存储 $key = "this is