RSA加密算法和签名算法

RSA加密算法和签名算法

一、理论_来源于网上。

RSA加密算法

RSA公钥加密体制包含如下3个算法:KeyGen(密钥生成算法),Encrypt(加密算法)以及Decrypt(解密算法)。

  • 。密钥生成算法以安全常数作为输入,输出一个公钥PK,和一个私钥SK。安全常数用于确定这个加密算法的安全性有多高,一般以加密算法使用的质数p的大小有关。越大,质数p一般越大,保证体制有更高的安全性。在RSA中,密钥生成算法如下:算法首先随机产生两个不同大质数p和q,计算N=pq。随后,算法计算欧拉函数。接下来,算法随机选择一个小于的整数e,并计算e关于的模反元素d。最后,公钥为PK=(N, e),私钥为SK=(N, d)。
  • 。加密算法以公钥PK和待加密的消息M作为输入,输出密文CT。在RSA中,加密算法如下:算法直接输出密文为
  • 。解密算法以私钥SK和密文CT作为输入,输出消息M。在RSA中,解密算法如下:算法直接输出明文为。由于e和d在下互逆,因此我们有:

所以,从算法描述中我们也可以看出:公钥用于对数据进行加密,私钥用于对数据进行解密。当然了,这个也可以很直观的理解:公钥就是公开的密钥,其公开了大家才能用它来加密数据。私钥是私有的密钥,谁有这个密钥才能够解密密文。否则大家都能看到私钥,就都能解密,那不就乱套了。

RSA签名算法

签名算法同样包含3个算法:KeyGen(密钥生成算法),Sign(签名算法),Verify(验证算法)。

  • 。密钥生成算法同样以安全常数作为输入,输出一个公钥PK和一个私钥SK。在RSA签名中,密钥生成算法与加密算法完全相同。
  • 。签名算法以私钥SK和待签名的消息M作为输入,输出签名。在RSA签名中,签名算法直接输出签名为。注意,签名算法和RSA加密体制中的解密算法非常像。
  • 。验证算法以公钥PK,签名以及消息M作为输入,输出一个比特值b。b=1意味着验证通过。b=0意味着验证不通过。在RSA签名中,验证算法首先计算,随后对比M'与M,如果相等,则输出b=1,否则输出b=0。注意:验证算法和RSA加密体制中的加密算法非常像。

所以,在签名算法中,私钥用于对数据进行签名,公钥用于对签名进行验证。这也可以直观地进行理解:对一个文件签名,当然要用私钥,因为我们希望只有自己才能完成签字。验证过程当然希望所有人都能够执行,大家看到签名都能通过验证证明确实是我自己签的。

 

二、工具类

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;

public class RSAUtil{
	
	public static final String  SIGN_ALGORITHMS = "SHA1WithRSA";
	
    /**加密算法RSA*/
    public static final String KEY_ALGORITHM = "RSA";
    
	/**RSA最大加密明文大小*/
    private static final int MAX_ENCRYPT_BLOCK = 117;
    
    /**RSA最大解密密文大小*/
    private static final int MAX_DECRYPT_BLOCK = 128;
	
	/**
	* RSA签名
	* @param content 待签名数据
	* @param privateKey 商户私钥
	* @param input_charset 编码格式
	*/
	public static String sign(String content, String privateKey, String input_charset){
        try {
        	PKCS8EncodedKeySpec priPKCS8 	= new PKCS8EncodedKeySpec(Base64_.decode(privateKey) ); 
        	KeyFactory keyf 				= KeyFactory.getInstance(KEY_ALGORITHM);
        	PrivateKey priKey 				= keyf.generatePrivate(priPKCS8);
            java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
            signature.initSign(priKey);
            signature.update(content.getBytes(input_charset));
            byte[] signed = signature.sign();
            return Base64_.encode(signed);
        }catch (Exception e) {
        	e.printStackTrace();
        }
        return null;
    }
	
	/**
	* RSA验签名检查
	* @param content 待签名数据
	* @param sign 签名值
	* @param ali_public_key 支付宝公钥
	* @param input_charset 编码格式
	*/
	public static boolean verify(String content, String sign, String ali_public_key, String input_charset){
		try {
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
	        byte[] encodedKey = Base64_.decode(ali_public_key);
	        PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
			java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);
			signature.initVerify(pubKey);
			signature.update(content.getBytes(input_charset) );
			boolean bverify = signature.verify( Base64_.decode(sign) );
			return bverify;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
	
	/**
	* 私钥解密
	* @param content 密文
	* @param private_key 商户私钥
	* @param input_charset 编码格式
	*/
	public static String decrypt(String content, String private_key, String input_charset) throws Exception {
        PrivateKey prikey = getPrivateKey(private_key);
        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, prikey);
        InputStream ins = new ByteArrayInputStream(Base64_.decode(content));
        ByteArrayOutputStream writer = new ByteArrayOutputStream();
        //rsa解密的字节大小最多是128,将需要解密的内容,按128位拆开解密
        byte[] buf = new byte[128];
        int bufl;
        while ((bufl = ins.read(buf)) != -1) {
            byte[] block = null;
            if (buf.length == bufl) {
                block = buf;
            } else {
                block = new byte[bufl];
                for (int i = 0; i < bufl; i++) {
                    block[i] = buf[i];
                }
            }
            writer.write(cipher.doFinal(block));
        }
        return new String(writer.toByteArray(), input_charset);
    }
	
	/**
     * 公钥加密
     * @param data 源数据
     * @param publicKey 公钥(BASE64编码)
     */
    public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
        byte[] keyBytes = Base64_.decode(publicKey);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // 对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // 对数据分段加密
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }
    
    public static String encryptByPublicKeyToStr(byte[] data, String publicKey) throws Exception {
    	byte[] bytes = encryptByPublicKey(data, publicKey);
    	String result = Base64_.encode(bytes);
    	return result;
    }
	
	/**
	* 得到私钥
	* @param key 密钥字符串(经过base64编码)
	* @throws Exception
	*/
	public static PrivateKey getPrivateKey(String key) throws Exception {
		byte[] keyBytes;
		keyBytes = Base64_.decode(key);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
		return privateKey;
	}
	
	public static class Base64_ {
		private static final Base64.Decoder decoder = Base64.getDecoder();
		private static final Base64.Encoder encoder = Base64.getEncoder();
		public static byte[] decode(String key) {
			if (key == null) { return null;}
			byte[] decode = decoder.decode(key);
			return decode;
		}
		public static String encode(byte[] content) {
			if (content == null) {return null;}
			String encode = encoder.encodeToString(content);
			return encode;
		}
	}
	
	/**
	 * 测试
	 */
	public static void main(String args[]) throws Exception{
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        keyPairGen.initialize(1024);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        String pubKey = Base64_.encode(publicKey.getEncoded()); //公钥
        String priKey = Base64_.encode(privateKey.getEncoded()); //私钥
//        System.out.println(pubKey);
//        System.out.println(priKey);
        
//......................................公钥加密,私钥解密!
        
        String sourceStr = "我是中国人啊!!!!!!!!!!!!!!!!!!!!!!!!!";
        //公钥加密
        byte[] ens = RSAUtil.encryptByPublicKey(sourceStr.getBytes(),pubKey);
        String encodes = Base64_.encode(ens);
        System.out.println(encodes);
        //私钥解密
        String res2 = RSAUtil.decrypt(encodes, priKey, "UTF-8");
        System.out.println(res2);
        
//.......................................签名验证,私钥签名,公钥验证是否正确!
        
        String source = "id=shoig&name=shoer&age=23dnjlegj;reg"; //模拟请求参数,然后对此请求参数进行签名。
        
        String sign = RSAUtil.sign(source, priKey, "UTF-8");
        
        System.out.println("签名是:"+sign);
        
        // 公钥验证签名是否正确.
        // 具体流程是,请求参数+sign发送给公钥方,然后公钥方过滤掉sign,用公钥验证其他参数是否通过。
        
        boolean result = RSAUtil.verify(source, sign, pubKey, "UTF-8");
        
        System.out.println(result);
        
	}
}

 

 

你可能感兴趣的:(java)