原則: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; }