標籤:android rsa 加密 校正
這個世界很精彩,這個世界很無奈。是的,在互連網時代,如何保護自己的資料,如何對資料進行加密和效驗就變得非常的重要。這裡總結一下Android平台使用Java語言,利用RSA演算法對資料進行校正的經驗。
先來看下如何RSA密碼編譯演算法對資料進行校正的流程:
1、首先要用openssh之類的程式產生一個私密金鑰
2、再根據私密金鑰產生一個公開金鑰
3、使用私密金鑰和公開金鑰,對資料進行簽名,得到簽名檔案。
4、使用公開金鑰和簽名檔案就可以對資料進行校正了。
再來看下如何?:
1、產生2048位的私密金鑰:
openssl genrsa -out private.pem 2048
2、產生公開金鑰
使用openssh也可以產生公開金鑰,但是在使用的過程中,發現由於格式的問題,使用openssh產生的公開金鑰在Java中使用時總是提示異常,所以最後還是根據網上的相關資料,使用Java語言來寫了程式,使用的公開金鑰可以在Java中使用,代碼如下:
GenPublic.java
import java.io.BufferedReader;import java.io.ByteArrayOutputStream;import java.io.DataOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.FileReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.PrintStream;import java.math.BigInteger;import java.security.KeyFactory;import java.security.KeyPair;import java.security.PublicKey;import java.security.Security;import java.security.Signature;import java.security.interfaces.DSAParams;import java.security.interfaces.DSAPublicKey;import java.security.interfaces.RSAPublicKey;import java.security.spec.X509EncodedKeySpec;import java.security.spec.RSAPublicKeySpec;import javax.xml.bind.DatatypeConverter;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.openssl.PEMReader;import org.bouncycastle.util.encoders.Base64;public class GenPublic { public static PrintStream out = System.out; public static PrintStream err = System.err; private static void genPublicKey(String privateFile,String pubFile) { try { PEMReader pemReader = new PEMReader(new FileReader(privateFile)); KeyPair pair = (KeyPair)pemReader.readObject(); PublicKey pubKey = pair.getPublic(); FileOutputStream outPub = new FileOutputStream(pubFile); byte[] bytes = pair.getPublic().getEncoded(); outPub.write(bytes); outPub.close(); } catch (Exception e) { e.printStackTrace(); }} public static void main(String[] args) throws Exception { if (args.length != 2) { err.println("Usage: java GenPublic <pem file> <public file>"); System.exit(1); } File pemFile = new File(args[0]); if(!pemFile.exists()) { err.println("PEM File Does Not Exist"); System.exit(1); } Security.addProvider(new BouncyCastleProvider()); genPublicKey(args[0],args[1]); }}
使用方法:
先編譯:
export CLASSPATH=".:bcprov-jdk15-140.jar"javac GenPublic.java
再使用編譯的程式產生公開金鑰:
java GenPublic private.pem public.bin
用到的庫可以在本文最後的連結中下載。
再來看看產生簽名檔案的Java代碼:
Sign.java
import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;import java.io.PrintStream;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.PublicKey;import java.security.SecureRandom;import java.security.Security;import java.security.Signature;import java.security.spec.X509EncodedKeySpec;import javax.xml.bind.DatatypeConverter;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.jce.provider.JDKKeyPairGenerator;import org.bouncycastle.openssl.PEMReader;import org.bouncycastle.openssl.PEMWriter;class Sign { public static PrintStream out = System.out; public static PrintStream err = System.err; private static byte[] pubKeyData = null; public static void main(String[] args) throws Exception { if(args.length < 4) { err.println("Usage: java JavaSign <pem file> <public file> <data file to sign> <signed file>"); System.exit(1); } File pemFile = new File(args[0]); File pubFile = new File(args[1]); File dataFile = new File(args[2]); if(!dataFile.exists()) { err.println("Data File Does Not Exist"); System.exit(1); } Security.addProvider(new BouncyCastleProvider()); KeyPair keys = null; if(!pemFile.exists()) { err.println("PEM File Does Not Exist. Generating."); KeyPairGenerator r = KeyPairGenerator.getInstance("RSA"); //keysize in bits is 2048 r.initialize(2048,new SecureRandom()); keys = r.generateKeyPair(); PEMWriter pemWriter = new PEMWriter(new FileWriter(pemFile)); pemWriter.writeObject(keys); pemWriter.close(); //You must flush or close the file or else it will not save } else { keys = (KeyPair) new PEMReader(new FileReader(pemFile)).readObject(); } //read data file into signature instance FileInputStream fin = new FileInputStream(dataFile); byte[] data = new byte[(int) dataFile.length()]; fin.read(data); fin.close(); //Sign the data Signature sg = Signature.getInstance("SHA1withRSA"); sg.initSign(keys.getPrivate()); sg.update(data); //output base64 encoded binary signature byte signBytes[] = sg.sign(); fin = new FileInputStream(pubFile); pubKeyData = new byte[(int) pubFile.length()]; fin.read(pubKeyData); fin.close(); int len = pubKeyData.length; for (int i=0;i<data.length;i++) { data[i] = (byte)(data[i] ^ pubKeyData[i%len]); } if (args.length == 4) { FileOutputStream out = new FileOutputStream(args[3]); out.write(signBytes); out.close(); } }}
同樣先編譯:
export CLASSPATH=".:bcprov-jdk15-140.jar"javac Sign.java
再看看看如何產生簽名檔案:
java JavaSign private.pem public.bin test.dat sign.bin
這裡的test.dat即是要校正的資料,sign.bin為產生的簽名檔案:
最後,就是如何使用公開金鑰和簽名檔案進行校正資料了:
來看下面的代碼:
import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;import java.io.PrintStream;import java.security.KeyFactory;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.PublicKey;import java.security.SecureRandom;import java.security.Security;import java.security.Signature;import java.security.spec.X509EncodedKeySpec;import javax.xml.bind.DatatypeConverter;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.jce.provider.JDKKeyPairGenerator;import org.bouncycastle.openssl.PEMReader;import org.bouncycastle.openssl.PEMWriter;class Verify { public static PrintStream out = System.out; public static PrintStream err = System.err; private static byte[] pubKeyData = null; public static void main(String[] args) throws Exception { if(args.length < 3) { err.println("Usage: java Verify <public file> <sign file> <data file to verify> "); System.exit(1); } File pubFile = new File(args[0]); FileInputStream fin = new FileInputStream(pubFile); pubKeyData = new byte[(int) pubFile.length()]; fin.read(pubKeyData); fin.close(); out.println("verifytData:"+verifyData(new File(args[1]),new File(args[2]))); } public static boolean verifyData(File signFile,File dataFile) {if(!signFile.exists()) {return false;}FileInputStream in = null;try {in = new FileInputStream(signFile);byte[] signatureBytes = new byte[(int)signFile.length()];in.read(signatureBytes);in.close();in = new FileInputStream(dataFile);byte[] data = new byte[(int)dataFile.length()];in.read(data);in.close();if (!verify(pubKeyData,signatureBytes,data)) { return false;}return true;} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {try {in.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return false;} public static boolean verify(byte[] pubKeyBytes,byte[] signatureBytes,byte[] dataBytes) throws Exception {X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(pubKeyBytes);KeyFactory keyFactory = KeyFactory.getInstance("RSA");PublicKey pubKey = keyFactory.generatePublic(pubKeySpec);//load public key Signature sg = Signature.getInstance("SHA1withRSA"); sg.initVerify(pubKey); sg.update(dataBytes); //validate signature if(sg.verify(signatureBytes)){ return true; } return false; } }
使用方法:
java Verify public.bin sign.bin test.dat
在使用的過程中,簽名檔案一般是和資料打包在一起的,並且在校正的時候要保證公開金鑰不會被篡改,要不然校正就沒有意義了。
當然,這裡對RSA的加密原理並沒有討論,這方面網上有很多相關的資料。
本文中用到的庫可以從下面的連結中找到:
http://penguindreams.org/blog/signature-verification-between-java-and-python/comment-page-1/#comment-3664169
Android應用開發中如何使用RSA密碼編譯演算法對資料進行校正