RSA加解密VS加簽與驗籤

原則:java

   1) 公鑰加密數據算法

    2)私鑰進行簽名shell

    3)公私鑰互加解密密鑰。
數組


JAVA安全

package com.zlbank.rsa;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
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 java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

import com.zlbank.tool.Base64Utils;

/**
 * <p>
 * RSA公鑰/私鑰/簽名工具包
 * </p>
 * <p>
 * 羅納德·李維斯特(Ron [R]ivest)、阿迪·薩莫爾(Adi [S]hamir)和倫納德·阿德曼(Leonard [A]dleman)
 * </p>
 * <p>
 * 字符串格式的密鑰在未在特殊說明狀況下都爲BASE64編碼格式<br/>
 * 因爲非對稱加密速度極其緩慢,通常文件不使用它來加密而是使用對稱加密,<br/>
 * 非對稱加密算法能夠用來對對稱加密的密鑰加密,這樣保證密鑰的安全也就保證了數據的安全
 * </p>
 * 
 * @author IceWee
 * @date 2012-4-26
 * @version 1.0
 */
public class RSAUtils {

	/**
	 * 加密算法RSA
	 */
	public static final String KEY_ALGORITHM = "RSA";

	/**
	 * 簽名算法
	 */
	// public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
	public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";

	/**
	 * 獲取公鑰的key
	 */
	private static final String PUBLIC_KEY = "RSAPublicKey";

	/**
	 * 獲取私鑰的key
	 */
	private static final String PRIVATE_KEY = "RSAPrivateKey";

	/**
	 * RSA最大加密明文大小
	 */
	private static final int MAX_ENCRYPT_BLOCK = 117;

	/**
	 * RSA最大解密密文大小
	 */
	private static final int MAX_DECRYPT_BLOCK = 128;

	/**
	 * <p>
	 * 生成密鑰對(公鑰和私鑰)
	 * </p>
	 * 
	 * @return
	 * @throws Exception
	 */
	public static Map<String, Object> genKeyPair() throws Exception {
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		keyPairGen.initialize(1024);
		KeyPair keyPair = keyPairGen.generateKeyPair();
		RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
		Map<String, Object> keyMap = new HashMap<String, Object>(2);
		keyMap.put(PUBLIC_KEY, publicKey);
		keyMap.put(PRIVATE_KEY, privateKey);
		return keyMap;
	}

	/**
	 * 從文件中輸入流中加載公鑰
	 * 
	 * @param in
	 *            公鑰輸入流
	 * @throws Exception
	 *             加載公鑰時產生的異常
	 */
	public static  RSAPublicKey loadPublicKey(InputStream in) throws Exception {
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String readLine = null;
			StringBuilder sb = new StringBuilder();
			while ((readLine = br.readLine()) != null) {
				if (readLine.charAt(0) == '-') {
					continue;
				} else {
					sb.append(readLine);
					sb.append('\r');
				}
			}
			return loadPublicKey(sb.toString());
		} catch (IOException e) {
			throw new Exception("公鑰數據流讀取錯誤");
		} catch (NullPointerException e) {
			throw new Exception("公鑰輸入流爲空");
		}
	}

	/**
	 * 從字符串中加載公鑰
	 * 
	 * @param publicKeyStr
	 *            公鑰數據字符串
	 * @throws Exception
	 *             加載公鑰時產生的異常
	 */
	public  static  RSAPublicKey  loadPublicKey(String publicKeyStr) throws Exception {
		try {

			byte[] buffer = Base64Utils.decode(publicKeyStr);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);

			return (RSAPublicKey) keyFactory.generatePublic(keySpec);

		} catch (NoSuchAlgorithmException e) {
			throw new Exception("無此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("公鑰非法");
		} catch (IOException e) {
			throw new Exception("公鑰數據內容讀取錯誤");
		} catch (NullPointerException e) {
			throw new Exception("公鑰數據爲空");
		}
	}

	/**
	 * 從文件中加載私鑰
	 * 
	 * @param keyFileName
	 *            私鑰文件名
	 * @return 是否成功
	 * @throws Exception
	 */
	public static RSAPrivateKey  loadPrivateKey(InputStream in) throws Exception {
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String readLine = null;
			StringBuilder sb = new StringBuilder();
			while ((readLine = br.readLine()) != null) {
				if (readLine.charAt(0) == '-') {
					continue;
				} else {
					sb.append(readLine);
					sb.append('\r');
				}
			}
			return loadPrivateKey(sb.toString());
		} catch (IOException e) {
			throw new Exception("私鑰數據讀取錯誤");
		} catch (NullPointerException e) {
			throw new Exception("私鑰輸入流爲空");
		}
	}

	public static  RSAPrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
		try {

			byte[] buffer = Base64Utils.decode(privateKeyStr);
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("無此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("私鑰非法");
		} catch (IOException e) {
			throw new Exception("私鑰數據內容讀取錯誤");
		} catch (NullPointerException e) {
			throw new Exception("私鑰數據爲空");
		}
	}

	/**
	 * <p>
	 * 用私鑰對信息生成數字簽名
	 * </p>
	 * 
	 * @param data
	 *            已加密數據
	 * @param privateKey
	 *            私鑰(BASE64編碼)
	 * 
	 * @return
	 * @throws Exception
	 */
	public static String sign(byte[] data, String privateKey) throws Exception {
		byte[] keyBytes = Base64Utils.decode(privateKey);
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initSign(privateK);
		signature.update(data);
		return Base64Utils.encode(signature.sign());
	}

	/**
	 * <p>
	 * 校驗數字簽名
	 * </p>
	 * 
	 * @param data
	 *            已加密數據
	 * @param publicKey
	 *            公鑰(BASE64編碼)
	 * @param sign
	 *            數字簽名
	 * 
	 * @return
	 * @throws Exception
	 * 
	 */
	public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
		byte[] keyBytes = Base64Utils.decode(publicKey);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PublicKey publicK = keyFactory.generatePublic(keySpec);
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initVerify(publicK);
		signature.update(data);
		return signature.verify(Base64Utils.decode(sign));
	}

	/**
	 * <P>
	 * 私鑰解密
	 * </p>
	 * 
	 * @param encryptedData
	 *            已加密數據
	 * @param privateKey
	 *            私鑰(BASE64編碼)
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey) throws Exception {
		byte[] keyBytes = Base64Utils.decode(privateKey);
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.DECRYPT_MODE, privateK);
		int inputLen = encryptedData.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 對數據分段解密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_DECRYPT_BLOCK;
		}
		byte[] decryptedData = out.toByteArray();
		out.close();
		return decryptedData;
	}

	/**
	 * <p>
	 * 公鑰解密
	 * </p>
	 * 
	 * @param encryptedData
	 *            已加密數據
	 * @param publicKey
	 *            公鑰(BASE64編碼)
	 * @return
	 * @throws Exception
	 */
	public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey) throws Exception {
		byte[] keyBytes = Base64Utils.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.DECRYPT_MODE, publicK);
		int inputLen = encryptedData.length;
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		int offSet = 0;
		byte[] cache;
		int i = 0;
		// 對數據分段解密
		while (inputLen - offSet > 0) {
			if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
				cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
			} else {
				cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
			}
			out.write(cache, 0, cache.length);
			i++;
			offSet = i * MAX_DECRYPT_BLOCK;
		}
		byte[] decryptedData = out.toByteArray();
		out.close();
		return decryptedData;
	}

	/**
	 * <p>
	 * 公鑰加密
	 * </p>
	 * 
	 * @param data
	 *            源數據
	 * @param publicKey
	 *            公鑰(BASE64編碼)
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPublicKey(byte[] data, String publicKey) throws Exception {
		byte[] keyBytes = Base64Utils.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;
	}

	/**
	 * <p>
	 * 私鑰加密
	 * </p>
	 * 
	 * @param data
	 *            源數據
	 * @param privateKey
	 *            私鑰(BASE64編碼)
	 * @return
	 * @throws Exception
	 */
	public static byte[] encryptByPrivateKey(byte[] data, String privateKey) throws Exception {
		byte[] keyBytes = Base64Utils.decode(privateKey);
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
		Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
		cipher.init(Cipher.ENCRYPT_MODE, privateK);
		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;
	}

	/**
	 * <p>
	 * 獲取私鑰
	 * </p>
	 * 
	 * @param keyMap
	 *            密鑰對
	 * @return
	 * @throws Exception
	 */
	public static String getPrivateKey(Map<String, Object> keyMap) throws Exception {
		Key key = (Key) keyMap.get(PRIVATE_KEY);
		return Base64Utils.encode(key.getEncoded());
	}

	/**
	 * <p>
	 * 獲取公鑰
	 * </p>
	 * 
	 * @param keyMap
	 *            密鑰對
	 * @return
	 * @throws Exception
	 */
	public static String getPublicKey(Map<String, Object> keyMap) throws Exception {
		Key key = (Key) keyMap.get(PUBLIC_KEY);
		return Base64Utils.encode(key.getEncoded());
	}

}
package com.zlbank.tool;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import it.sauronsoftware.base64.Base64;


 
/**
 * <p>
 * BASE64編碼解碼工具包
 * </p>
 * <p>
 * 依賴javabase64-1.3.1.jar
 * </p>
 * 
 * @author IceWee
 * @date 2012-5-19
 * @version 1.0
 */
public class Base64Utils {
 
    /**
     * 文件讀取緩衝區大小
     */
    private static final int CACHE_SIZE = 1024;
     
    /**
     * <p>
     * BASE64字符串解碼爲二進制數據
     * </p>
     * 
     * @param base64
     * @return
     * @throws Exception
     */
    public static byte[] decode(String base64) throws Exception {
        return Base64.decode(base64.getBytes());
    }
     
    /**
     * <p>
     * 二進制數據編碼爲BASE64字符串
     * </p>
     * 
     * @param bytes
     * @return
     * @throws Exception
     */
    public static String encode(byte[] bytes) throws Exception {
        return new String(Base64.encode(bytes));
    }
     
    /**
     * <p>
     * 將文件編碼爲BASE64字符串
     * </p>
     * <p>
     * 大文件慎用,可能會致使內存溢出
     * </p>
     * 
     * @param filePath 文件絕對路徑
     * @return
     * @throws Exception
     */
    public static String encodeFile(String filePath) throws Exception {
        byte[] bytes = fileToByte(filePath);
        return encode(bytes);
    }
     
    /**
     * <p>
     * BASE64字符串轉回文件
     * </p>
     * 
     * @param filePath 文件絕對路徑
     * @param base64 編碼字符串
     * @throws Exception
     */
    public static void decodeToFile(String filePath, String base64) throws Exception {
        byte[] bytes = decode(base64);
        byteArrayToFile(bytes, filePath);
    }
     
    /**
     * <p>
     * 文件轉換爲二進制數組
     * </p>
     * 
     * @param filePath 文件路徑
     * @return
     * @throws Exception
     */
    public static byte[] fileToByte(String filePath) throws Exception {
        byte[] data = new byte[0];
        File file = new File(filePath);
        if (file.exists()) {
            FileInputStream in = new FileInputStream(file);
            ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
            byte[] cache = new byte[CACHE_SIZE];
            int nRead = 0;
            while ((nRead = in.read(cache)) != -1) {
                out.write(cache, 0, nRead);
                out.flush();
            }
            out.close();
            in.close();
            data = out.toByteArray();
         }
        return data;
    }
     
    /**
     * <p>
     * 二進制數據寫文件
     * </p>
     * 
     * @param bytes 二進制數據
     * @param filePath 文件生成目錄
     */
    public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {
        InputStream in = new ByteArrayInputStream(bytes);   
        File destFile = new File(filePath);
        if (!destFile.getParentFile().exists()) {
            destFile.getParentFile().mkdirs();
        }
        destFile.createNewFile();
        OutputStream out = new FileOutputStream(destFile);
        byte[] cache = new byte[CACHE_SIZE];
        int nRead = 0;
        while ((nRead = in.read(cache)) != -1) {   
            out.write(cache, 0, nRead);
            out.flush();
        }
        out.close();
        in.close();
    }
     
     
}
package com.zlbank.rsa;

import java.util.Map;

import com.zlbank.tool.Base64Utils;

public class RSATester {

	static String publicKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5wonDXZhItfDmRUlWQCFwjYL/SSb5PYU7x4mtKPzopnUamlDXTVcSbUdFGRr4K6ANNPs3UsviraN/QWmI3vguzd/xWlpIbGnkyAOzS4hErf+cQDHSW2/TAf1MqI0I6p6tjfLpp4jXJj0OcEeeVR1oVXkY3I8vuOW1v0wwByAkpwIDAQAB";
	static String privateKey="MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALnCicNdmEi18OZFSVZAIXCNgv9JJvk9hTvHia0o/OimdRqaUNdNVxJtR0UZGvgroA00+zdSy+Kto39BaYje+C7N3/FaWkhsaeTIA7NLiESt/5xAMdJbb9MB/UyojQjqnq2N8umniNcmPQ5wR55VHWhVeRjcjy+45bW/TDAHICSnAgMBAAECgYBkO9+gRomcemhBqJNY8gPZOtK7s5pPFO4mgpX8lMhbNS6tKyWB956LN+IkG9bcoJWdasA/avLPHsjBKueqTj32AAu0lNCXnJBtFHXY2IAIpSNjOYP2HEsq6FWO9V4eznOcg588Hb4udi5F+Sq8E5werTx0q7PZKou8X31apXgiWQJBAN2y1FGjeGeskwPYpfqIv4xF+u4EPTkGWMNOD3uUqJNzPqg5ETYYXKlfQu5LnNMV0LHUbGl0f0hD70Hv+Xbz8RUCQQDWgDq7lEG7FmwPVVdbQceJJOfCWSLl3liFYRUXvLAVXL1aq3314OMp/m93HtbUj/oVJVJ8pEsAWkKEcS8jFFXLAkAEfS19ZbD3cHAdoNJji0dNoNEe5qkSsYU0ly0LFIyBR9EZ+OXXUZD2wP4K8y7+uy9ZmnKDhB9bqDx8+k3z0aatAkEAmIEUwPbYgO6hJ4mykTREbJJroHcFY89gunvapkTGIHoOOp/A74bTm7DFiTjI3tn6oPwnGG0q0fZaYpWiQNudXwJAfWhC3gaFpFYXZdg9+ysB3i7gIlpWd6CELkUV6YIEmW9V8B9URmDPBMLbjRYpt8Q4vGaPPunteeLfIl3Ld0rXUA==";

	static {
		try {
//			Map<String, Object> keyMap = RSAUtils.genKeyPair();
//			publicKey = RSAUtils.getPublicKey(keyMap);
//			privateKey = RSAUtils.getPrivateKey(keyMap);
//			System.out.println("公鑰: \n\r" + publicKey);
//			System.out.println("私鑰: \n\r" + privateKey);
//			
//			publicKey= RSAUtils.loadPublicKey("");
//			privateKey=RSAUtils.loadPrivateKey("");
//			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) throws Exception {
		//test();
		
		testSign();
	}

	static void test() throws Exception {
		System.out.println("公鑰加密——私鑰解密");
		String source = "123456";
		System.out.println("\r加密前文字:" + source);
		
		byte[] data = source.getBytes();
		byte[] encodedData = RSAUtils.encryptByPublicKey(data, publicKey);
		System.out.println("加密後文字:" + Base64Utils.encode(encodedData));
		
		
		byte[] decodedData = RSAUtils.decryptByPrivateKey(encodedData, privateKey);
		String target = new String(decodedData);
		System.out.println("解密後文字: " + target);

	}

	static void testSign() throws Exception {
		System.out.println("私鑰加密——公鑰解密");
		String source = "9876543";
		System.out.println("原文字:" + source);
		
		byte[] data = source.getBytes();
		byte[] encodedData = RSAUtils.encryptByPrivateKey(data, privateKey);
		System.out.println("加密後:" + Base64Utils.encode(encodedData));
		
		byte[] decodedData = RSAUtils.decryptByPublicKey(encodedData, publicKey);
		String target = new String(decodedData);
		System.out.println("解密後: " + target);

		System.out.println("私鑰簽名——公鑰驗證簽名");
		String sign = RSAUtils.sign(data, privateKey);
		System.out.println("簽名:" + sign);
		boolean status = RSAUtils.verify(data, publicKey, sign);
		System.out.println("驗證結果:" + status);
	}

}

     關鍵在測試數據:運行結果以下:簽名運用是JAVA經常使用的SHA1withRSA方式app

私鑰加密——公鑰解密
原文字:9876543
加密後:BuC21nX9C1QaW0M16b+Hxn54lnekLQHD1fNcaQgK7MvHNuQKNiwUQilYsi2vALm/yBEnIsR0SreXWYFFogq75SsbI/4fxF2tFz16JIR5+z5Wdm/uE0AFfQDqVMX2I0aJSKzTRhRmCJgE7+n0ALon/b2WLQfHguxGF8X9WjnqnXM=
解密後: 9876543
私鑰簽名——公鑰驗證簽名
簽名:aO9kIu3T4Q/irSxloqlSw+5Mm7TgNooqqkGFEuIyiFZ+KC2P8RFXnzhr2laggRpWVEEQ4cNysqoSE8uDnc3+Me/Ef4YHjK0F30sas1U8VsLuuBghptB406PZc0aStI7ZMp63AokNN+8FoVQ87ObYzRhkXOoKEy+W4gFjcT/usEg=
驗證結果:true


===== >對應的C 運用openssl進行作一樣的工做:工具

先看運行結果:測試

===============RSA 加密與解密 VS 加簽與驗籤功能 演示=================
RSA加解密------>加密前數據:[9876543]
RSA加解密------>加密後數據:06e0b6d675fd0b541a5b4335e9bf87c67e789677a42d01c3d5f35c69080aeccbc736e40a362c14422958b22daf00b9bfc8112722c4744ab797598145a20abbe52b1b23fe1fc45dad173d7a248479fb3e56766fee1340057d00ea54c5f623468948acd3461466089804efe9f400ba27fdbd962d07c782ec4617c5fd5a39ea9d73
RSA加解密------>解密後數據: 9876543
======================================================
RSA加驗籤---RSA_sign---> RSA_sign( NID_sha1, src, sizeof(src)-1, sign, &sign_len, key)加簽成功 [1]
RSA加驗籤---RSA_verify--->RSA_verify( NID_sha1, src, sizeof(src)-1, sign, sign_len, key)驗籤成功 [1]
RSA加驗籤----->待加簽數據: [9876543]
RSA加驗籤----->手工計算sha1(9876543)=3c776dacfd82b327a679bdf2339cc9477299ebb6
======================================================
簽名數據(十六進表現形式): 68ef6422edd3e10fe2ad2c65a2a952c3ee4c9bb4e0368a2aaa418512e23288567e282d8ff111579f386bda56a0811a56544110e1c372b2aa1213cb839dcdfe31efc47f86078cad05df4b1ab3553c56c2eeb81821a6d078d3a3d9734692b48ed9329eb702890d37ef05a1543cece6d8cd18645cea0a132f96e20163713feeb048
RSA加驗籤--->RSA_verify( NID_sha1, sha1, sha1_len, sign, sign_len, key) is ok
RSA加驗籤--->RSA_verify( NID_sha1, src, strlen(src), sign, sign_len, key) is error
======================================================
RSA加驗籤--->簽名解密獲得的數據:3021300906052b0e03021a050004143c776dacfd82b327a679bdf2339cc9477299ebb6
RSA加驗籤---> RSA_sign( NID_sha1, sha1, 20, sign, &sign_len, key): 68ef6422edd3e10fe2ad2c65a2a952c3ee4c9bb4e0368a2aaa418512e23288567e282d8ff111579f386bda56a0811a56544110e1c372b2aa1213cb839dcdfe31efc47f86078cad05df4b1ab3553c56c2eeb81821a6d078d3a3d9734692b48ed9329eb702890d37ef05a1543cece6d8cd18645cea0a132f96e20163713feeb048
RSA加驗籤---> RSA_sign( NID_sha1, sha1, 20, sign, &sign_len, key) 對應BASE64數據[aO9kIu3T4Q/irSxloqlSw+5Mm7TgNooqqkGFEuIyiFZ+KC2P8RFXnzhr2laggRpWVEEQ4cNysqoSE8uDnc3+Me/Ef4YHjK0F30sas1U8VsLuuBghptB406PZc0aStI7ZMp63AokNN+8FoVQ87ObYzRhkXOoKEy+W4gFjcT/usEg=]
RSA加驗籤--->直接解密加簽數據:3021300906052b0e03021a050004143c776dacfd82b327a679bdf2339cc9477299ebb6
======================================================
RSA加驗籤---> RSA_sign( NID_sha1, src, strlen(src), sign, &sign_len, key): 56eec6b2d018056d33c6dd5ddd4277ab6828972154e77a6b08f88fbc4cdd69e0d4657ca01983193e1b8115ad2bbc6aa353da41510aaa74a42947c1903d9c0d61626348592ae9f4dabd6bbb71020c78f6afbef7cd70a6b1367d9dccd75f68516ebc2e0ea7a8e090eb424abbd6cdcdbeace86288a0cfd09568f78dabd15472767f
RSA加驗籤---> RSA_sign( NID_sha1, src, strlen(src), sign, &sign_len, key) 對應BASE64數據[Vu7GstAYBW0zxt1d3UJ3q2golyFU53prCPiPvEzdaeDUZXygGYMZPhuBFa0rvGqjU9pBUQqqdKQpR8GQPZwNYWJjSFkq6fTavWu7cQIMePavvvfNcKaxNn2dzNdfaFFuvC4Op6jgkOtCSrvWzc2+rOhiiKDP0JVo942r0VRydn8=]
RSA加驗籤--->直接解密加簽數據:3014300906052b0e03021a0500040739383736353433


代碼以下:ui

/*
 * rsa_sign_test.c
 *
 *  Created on: 2015年11月27日
 *      Author: mengfh
 *      1)驗證RSA加密+解密
 *      2)驗證RSA所對應java中SHA1WITHRSA功能加簽與驗籤
 */

#include <stdio.h>
#include <string.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <assert.h>
#include<stdlib.h>

#define SetKey \
    key->n = BN_bin2bn(n, sizeof(n)-1, key->n); \
key->e = BN_bin2bn(e, sizeof(e)-1, key->e); \
key->d = BN_bin2bn(d, sizeof(d)-1, key->d); \
key->p = BN_bin2bn(p, sizeof(p)-1, key->p); \
key->q = BN_bin2bn(q, sizeof(q)-1, key->q); \
key->dmp1 = BN_bin2bn(dmp1, sizeof(dmp1)-1, key->dmp1); \
key->dmq1 = BN_bin2bn(dmq1, sizeof(dmq1)-1, key->dmq1); \
key->iqmp = BN_bin2bn(iqmp, sizeof(iqmp)-1, key->iqmp); \
return 0;

/*功能:解密成功返回0,不然返回-1
 * 參數:
 * pData:待解碼數據
 * nLeng:待解碼數據長度
 * linebreaks:待解碼數據是否以64字節換行 (0不換行; 1換行)
 * pOutBufffer:解碼後數據
 * pBufferLenth:解碼後數據長度,傳入時爲pOutBufffer大小,傳出爲解碼後數據長度
 */
int Base64Encode(unsigned char *pData, int nLeng, int linebreaks, char * pOutBufffer, int *pBufferLenth)
{
	int res = -1;
	BIO *bmem, *b64;
	BUF_MEM *bptr;

	b64 = BIO_new(BIO_f_base64());
	if (!b64)
		return res;
	if (!linebreaks)
	{
		BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
	}
	bmem = BIO_new(BIO_s_mem());
	if (bmem)
	{
		b64 = BIO_push(b64, bmem);
		if (BIO_write(b64, pData, nLeng) == nLeng)
		{
			(void) BIO_flush(b64);
			BIO_get_mem_ptr(b64, &bptr);
			if (*pBufferLenth > bptr->length)
			{
				memcpy(pOutBufffer, bptr->data, bptr->length);
				pOutBufffer[bptr->length] = 0;
				res = 0;
			}
			*pBufferLenth = bptr->length + 1;
		}
	}

	BIO_free_all(b64);
	return res;
}

/**
 *功能:編碼成功返0 , 不然返-1
 * pData:待編碼數據
 * nLeng:待編碼數據長度
 * linebreaks:待編碼數據是否以64字節換行 (0不換行; 1換行)
 * pOutBufffer:編碼後數據
 * pBufferLenth:編碼後數據長度,傳入時爲pOutBufffer大小,傳出爲編碼後數據長度
 */
int Base64Decode(char *pData, int nLeng, int linebreaks, unsigned char * pOutBufffer, int *pBufferLenth)
{
	int res = -1;
	BIO *bmem;
	BIO *b64;
	if (nLeng == 0)
		nLeng = strlen(pData);
	int nMaxLen = (nLeng * 6 + 7) / 8;
	int nMiniLen;
	unsigned char *buf = malloc(nMaxLen * sizeof(unsigned char));
	if (buf)
	{
		b64 = BIO_new(BIO_f_base64());
		if (b64)
		{
			if (!linebreaks)
			{
				BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
			}
			bmem = BIO_new_mem_buf((char*) pData, nLeng);
			b64 = BIO_push(b64, bmem);
			nMiniLen = BIO_read(b64, buf, nMaxLen);
			if (*pBufferLenth >= nMiniLen)
			{
				memcpy(pOutBufffer, buf, nMiniLen);
				res = 0;
			}
			*pBufferLenth = nMiniLen;
			BIO_free_all(b64);
		}
		free(buf);
	}
	return res;
}

//構建RSA公、私鑰信息
static int key5(RSA *key)
{
	//密鑰中變量
	static unsigned char n[] =
			"\x9c\xb5\xd4\x87\x70\xb6\x43\x03\x49\x5e\xe8\x40\xbc\xbf\x15\x79\x9e\xb2\x18\x0d\xfa\xde\xf7\xb2\x37\xd0\x22\xdb\xd4\xef\x2d\x79\x63\xdb\x38\x2b\xed\x05\xe5\x14\x0b\x9a\x80\x5c\x75\x11\xef\x1b\x89\x5b\x40\xb7\x1c\x22\x7d\x84\x59\xbc\xcc\xb5\xca\x63\xbd\x7b\xdf\x1e\x3a\x72\x13\x86\x93\xa9\x9c\xc7\xcb\x48\x3d\x8b\x8c\xa9\x4c\xce\xd7\xca\xc0\xb0\x62\x7a\x95\x7a\xd7\xbd\x27\x82\x91\x40\x90\x35\xb1\xe4\xab\x5f\xbb\x06\x29\x01\xf4\x91\xe5\x15\x5f\xd3\xc2\x13\x38\xaf\x1f\x75\x88\x47\xd1\x04\xd2\xb3\x71\xa0\x9e\xc7";

	static unsigned char e[] = "\x00\x01\x00\x01";

	static unsigned char d[] =
			"\x09\x33\x83\xef\x0f\xe7\x23\xb8\x25\xae\xb4\xe4\x58\x30\xc0\x0a\x0c\x0f\x58\xea\x39\x38\xae\x42\x80\x94\x6f\xf7\x88\x61\x22\xc2\x65\xe2\x91\x41\xc3\x00\xfd\x9a\x57\xb4\x12\xa5\x5b\x1a\x5a\x77\xbb\x70\xe8\x33\xd8\x2b\x0e\x43\x9f\x21\x3e\xc3\xcd\xc6\x5d\x71\xb8\xec\x6e\xea\x5f\x17\xa5\xe1\x43\xeb\xdd\x71\xa4\x6f\xed\x09\xf0\x8b\xbe\xd9\x26\xb5\x70\x9b\xab\x42\x70\x70\x71\xd4\x14\x8f\xa8\x2c\xc4\x23\x21\x70\x1f\xd7\xef\xfd\x6b\x02\x40\x8b\xf4\x77\x5c\x78\x08\x80\x8b\x7d\x7e\x7a\xb2\x14\xe0\xf6\x94\xf2\x56\x81";

	static unsigned char p[] =
			"\xd6\x8c\xf3\x60\x76\x5b\x6e\x55\xde\x5a\xf7\x43\x95\x6b\x5e\xc0\xd9\x5a\xcd\xd8\x03\xd3\x65\xcb\x1d\xf6\xfe\x57\x39\x6c\xfd\x72\x06\x8b\xe8\x2e\x05\xfd\xe4\x7c\x39\x94\xa2\xea\xb8\x4c\xf5\xd6\xdc\xd7\x9a\xb8\xef\x05\xd9\xef\x96\xfa\x91\xa3\xb6\x9a\xd4\x19";

	static unsigned char q[] =
			"\xba\xfc\x43\xf4\x79\x60\x09\x97\x37\x6e\x55\x83\xbb\xb6\xb3\x5f\x4c\x39\x00\x93\x19\x90\x64\x65\x3a\xf7\xa0\xca\x5e\x9d\x66\xd9\xee\x7d\xdb\xd0\xe2\xe7\x57\x55\x41\x90\xc7\x4b\xed\x91\x42\xea\x34\x93\x1a\x76\xb8\xd0\xf2\x74\xed\xf5\xd3\xb9\xa6\x34\x65\xdf";

	static unsigned char dmp1[] =
			"\x4f\xfd\x89\x17\xa3\xc8\xfe\xe0\x00\xe0\xc5\x63\x6b\x27\xf6\xd1\xcb\xb7\xb1\x1b\x22\x82\x04\x67\xb0\x2a\x50\x35\x50\xf1\xb3\xa4\x79\x90\x5b\xe6\x1c\xd1\xc6\x08\x12\xa7\xb9\xfd\xec\xec\xb4\x93\x81\x0e\xd9\x5e\xad\xae\xee\xcc\x06\xec\x30\xb4\x6a\xf6\x5a\xb1";

	static unsigned char dmq1[] =
			"\x60\x9b\x5d\x70\xbe\x15\x04\x5f\x80\x60\x1d\x06\x86\xc1\x8a\x43\x3e\x5a\x65\x15\x9b\x2b\xa2\xf3\x3a\x58\x1e\x56\xf0\x33\x5a\xa4\x56\x37\xe8\x8e\x2f\xed\x5e\x8d\xc9\xe6\x47\x51\xcf\x58\x31\xbe\x57\x93\x79\x24\xc5\xb0\x0e\xd4\xa2\xed\x53\x8a\xa3\x78\x86\xf9";

	static unsigned char iqmp[] =
			"\x28\xc6\xca\x44\x40\x7a\xad\x4c\x74\x4d\xeb\x2d\xaa\xd7\xc8\x43\xef\x4a\x12\x44\x0a\x89\xb8\x12\x11\x7f\x40\x91\x9a\xe1\x4a\xfe\xe2\xe5\x3e\x6c\x7f\x07\x49\x04\xc9\x95\x8a\x4e\xa5\x7f\x3c\x8f\xea\xbd\x71\x2e\xca\x7a\x37\xdf\x99\x05\x2f\x0c\x03\x11\x6d\x5d";

	SetKey
	;
}

//驗名數據(測試用 JAVA測試代碼生成)
char *signData =
		"aO9kIu3T4Q/irSxloqlSw+5Mm7TgNooqqkGFEuIyiFZ+KC2P8RFXnzhr2laggRpWVEEQ4cNysqoSE8uDnc3+Me/Ef4YHjK0F30sas1U8VsLuuBghptB406PZc0aStI7ZMp63AokNN+8FoVQ87ObYzRhkXOoKEy+W4gFjcT/usEg=";

/**
 * 加解密
 * 加簽與驗籤
 */
int main(int argc, char *argv[])
{
	int err = 0;
	int v;
	RSA *key;
	unsigned char rsaDecodeData[256];
	unsigned char des[256];
	unsigned char sign[1024], sha1[256];
	unsigned char src[] = "9876543";
	unsigned char ctext_ex[256];
	unsigned char tmpBuf[2560];
	int plen;
	int clen = 0;
	int ret;
	int n;
	int i;
	int sign_len, r, len,sha1_len;
	FILE *fprivate, *fpbulic;
	EVP_PKEY *pkey;

	fprintf(stderr, "===============RSA 加密與解密 VS 加簽與驗籤功能 演示=================\n");

	//1:生成RSA密鑰
	key = RSA_new();
	{
//        key5(key);
	}

	//從文件中直接取公、私鑰信息
	{
		if ((fprivate = fopen("./private.pem", "r")) == NULL)
		{
			fprintf(stderr, " open fprivate file error \n");
			return -1;
		}
		if ((fpbulic = fopen("./public.pem", "r")) == NULL)
		{
			fprintf(stderr, " open fpbulic file error \n");
			return -1;
		}

		if ((PEM_read_RSAPrivateKey(fprivate, &key, NULL, NULL)) == NULL)
		{
			fprintf(stderr, " PEM_read_RSAPrivateKeyerror error\n");
			return -1;
		}

		PEM_read_RSAPublicKey(fpbulic, &key, NULL, NULL);
//		if ((PEM_read_RSAPublicKey(fpbulic, &key, NULL, NULL)) == NULL)
//		{
//			fprintf(stderr, " PEM_read_RSAPublicKey error \n");
//			return -1;
//		}
	}

	//----------------------加解密

	//加密數據======================================================
	fprintf(stderr, "RSA加解密------>加密前數據:[%s]\n", src);
	memset(des, 0 ,sizeof(des));
	ret = RSA_private_encrypt(sizeof(src) - 1, src, des, key,RSA_PKCS1_PADDING);
	if (ret != 128)   //模數長度
	{
		fprintf(stderr,"PKCS#1 v1.5 encryption failed!\n");
		err = 1;
		goto next;
	}
	//加密後的數據
	fprintf(stderr, "RSA加解密------>加密後數據:");
	for (i = 0; i < ret; i++)
	{
		fprintf(stderr,"%02x", des[i]);
	}
	fprintf(stderr,"\n");

	memset(tmpBuf, 0 ,sizeof(tmpBuf));
	ret = RSA_public_decrypt(ret, des, tmpBuf, key,RSA_PKCS1_PADDING);
	if (ret <=0)
	{
		printf("PKCS#1 v1.5 decryption failed!\n");
		err = 1;
	}
	tmpBuf[ret] = '\0';    //字符串結尾
	printf("RSA加解密------>解密後數據: %s\n", tmpBuf);

	fprintf(stderr, "======================================================\n");

	//======================================================

	//自帶RSA_sign vs  RSA_verify

	memset(sign, 0 ,sizeof(sign));
	r = RSA_sign( NID_sha1, src, sizeof(src)-1, sign, &sign_len, key);
	assert(0 != r);
	printf("RSA加驗籤---RSA_sign---> RSA_sign( NID_sha1, src, sizeof(src)-1, sign, &sign_len, key)加簽成功 [%d]\n", r);

	r = RSA_verify( NID_sha1, src, sizeof(src)-1, sign, sign_len, key);
	assert(0 != r);
	printf("RSA加驗籤---RSA_verify--->RSA_verify( NID_sha1, src, sizeof(src)-1, sign, sign_len, key)驗籤成功 [%d]\n", r);


	// 測試JAVA 簽名數據================================================

	fprintf(stderr, "RSA加驗籤----->待加簽數據: [%s]\n", src);
	//SHA1
	memset(sha1, 0, sizeof(sha1));
	SHA1(src, strlen(src), sha1);
	sha1_len =20;
	fprintf(stderr, "RSA加驗籤----->手工計算sha1(%s)=", src);
	for (i = 0; i < sha1[i] != '\0'; i++)
		fprintf(stderr,"%02x", sha1[i]);
	fprintf(stderr,"\n");

	fprintf(stderr, "======================================================\n");


	//解析加簽數據
	memset(sign, 0 ,sizeof(sign));
	sign_len = sizeof(sign);
	if( Base64Decode(signData, strlen(signData), 0, sign, &sign_len)<0)
	{
		fprintf(stderr, " Base64Decode error \n");
		return -1;
	}
	fprintf(stderr, "簽名數據(十六進表現形式): ");
	for (i = 0; i < sign_len; i++)
		fprintf(stderr,"%02x", sign[i]);
	fprintf(stderr,"\n");


	//對比二種驗籤數據源
	if( RSA_verify( NID_sha1, sha1, sha1_len, sign, sign_len, key) ==1)
	{
		fprintf(stderr,"RSA加驗籤--->RSA_verify( NID_sha1, sha1, sha1_len, sign, sign_len, key) is ok\n");
	}
	else
	{
		fprintf(stderr,"RSA加驗籤--->RSA_verify( NID_sha1, sha1, sha1_len, sign, sign_len, key) is error\n");
	}

	if( RSA_verify( NID_sha1, src, strlen(src), sign, sign_len, key) ==1)
	{
		fprintf(stderr,"RSA加驗籤--->RSA_verify( NID_sha1, src, strlen(src), sign, sign_len, key) is ok\n");
	}
	else
	{
		fprintf(stderr,"RSA加驗籤--->RSA_verify( NID_sha1, src, strlen(src), sign, sign_len, key) is error\n");
	}



	fprintf(stderr, "======================================================\n");
	//將簽名數據RSA解密
	memset(tmpBuf, 0, sizeof(tmpBuf));
	if((ret = RSA_public_decrypt(sign_len, sign, tmpBuf, key, RSA_PKCS1_PADDING))<=0)
	{
		fprintf(stderr, " RSA_public_decrypt error \n");
		return -1;
	}

	fprintf(stderr, "RSA加驗籤--->簽名解密獲得的數據:");
	for (i = 0; i < ret; i++)
	{
		fprintf(stderr,"%02x", tmpBuf[i]);
	}
	fprintf(stderr,"\n");


	//進行數據加簽操做
	memset(sign, 0, sizeof(sign));
	sign_len = -1;
	if(1!= RSA_sign( NID_sha1, sha1, sha1_len, sign, &sign_len, key))
	{
		fprintf(stderr, " RSA_sign error \n");
		return -1;
	}
	fprintf(stderr,"RSA加驗籤---> RSA_sign( NID_sha1, sha1, 20, sign, &sign_len, key): ");
	for (i = 0; i < sign_len; i++)
	{
		fprintf(stderr,"%02x", sign[i]);
	}
	fprintf(stderr,"\n");

	memset(tmpBuf, 0, sizeof(tmpBuf));
	len = sizeof(tmpBuf);
	if(Base64Encode(sign, sign_len, 0, tmpBuf, &len)<0)
	{
		fprintf(stderr, " Base64Encode error \n");
		return -1;
	}
	fprintf(stderr, "RSA加驗籤---> RSA_sign( NID_sha1, sha1, 20, sign, &sign_len, key) 對應BASE64數據[%s]\n", tmpBuf);

	memset(tmpBuf, 0 ,sizeof(tmpBuf));
	ret = RSA_public_decrypt(sign_len, sign, tmpBuf, key, RSA_PKCS1_PADDING);
	fprintf(stderr, "RSA加驗籤--->直接解密加簽數據:");
	for (i = 0; i < ret; i++)
	{
		fprintf(stderr,"%02x", tmpBuf[i]);
	}
	fprintf(stderr,"\n");


	fprintf(stderr, "======================================================\n");

	//進行數據加簽操做
	memset(sign, 0, sizeof(sign));
	sign_len = -1;
	if(1!= RSA_sign( NID_sha1, src, strlen(src), sign, &sign_len, key))
	{
		fprintf(stderr, " RSA_sign error \n");
		return -1;
	}
	fprintf(stderr,"RSA加驗籤---> RSA_sign( NID_sha1, src, strlen(src), sign, &sign_len, key): ");
	for (i = 0; i < sign_len; i++)
	{
		fprintf(stderr,"%02x", sign[i]);
	}
	fprintf(stderr,"\n");

	memset(tmpBuf, 0, sizeof(tmpBuf));
	len = sizeof(tmpBuf);
	if(Base64Encode(sign, sign_len, 0, tmpBuf, &len)<0)
	{
		fprintf(stderr, " Base64Encode error \n");
		return -1;
	}
	fprintf(stderr, "RSA加驗籤---> RSA_sign( NID_sha1, src, strlen(src), sign, &sign_len, key) 對應BASE64數據[%s]\n", tmpBuf);


	//將簽名數據RSA解密
	memset(tmpBuf, 0 ,sizeof(tmpBuf));
	ret = RSA_public_decrypt(sign_len, sign, tmpBuf, key, RSA_PKCS1_PADDING);
	fprintf(stderr, "RSA加驗籤--->直接解密加簽數據:");
	for (i = 0; i < ret; i++)
	{
		fprintf(stderr,"%02x", tmpBuf[i]);
	}
	fprintf(stderr,"\n");


	fprintf(stderr, "======================================================\n");

	next:
	//公鑰和私鑰輸出爲 PEM 格式:
	PEM_write_RSAPrivateKey(stdout, key, NULL, NULL, 0, NULL, NULL);
	PEM_write_RSAPublicKey(stdout, key);

	//釋放申請的內存
	RSA_free(key);

	if (err)
		fprintf(stderr,"ERROR: %d\n", err);
	return err;
}
相關文章
相關標籤/搜索