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 block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				in.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.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

时间: 2024-08-09 02:19:03

Android应用开发中如何使用RSA加密算法对数据进行校验的相关文章

Android实际开发中的bug总结与解决方法(一)

                                                                             Android实际开发中的bug总结与解决方法(一) Android开发中有很多bug,我们是完全可以在线下避免的,不要等到线上报的BUG的再去修复.下面是我在实际开发中遇到过的bug和解决方法. BUG 1: java.lang.RuntimeException: Unable to start activity ComponentInfo

Android应用开发中的风格和主题(style,themes)(转)

Android应用开发中的风格和主题(style,themes) 越来越多互联网企业都在Android平台上部署其客户端,为了提升用户体验,这些客户端都做得布局合理而且美观.......Android的Style设计就是提升用户体验的关键之一.Android上的Style分为了两个方面: Theme是针对窗体级别的,改变窗体样式: Style是针对窗体元素级别的,改变指定控件或者Layout的样式.      Android系统的themes.xml和style.xml(位于\base\core

Android应用开发中三种常见的图片压缩方法

Android应用开发中三种常见的图片压缩方法,分别是:质量压缩法.比例压缩法(根据路径获取图片并压缩)和比例压缩法(根据Bitmap图片压缩). 一.质量压缩法 private Bitmap compressImage(Bitmap image) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里

android游戏开发中图形绘制:Canvas和Paint的使用

android游戏开发中,使用android.graphics中的类来绘制2D向量图和文字. 一 画布Canvas 在Android中的绘图应该继承View组件,并重写它的onDraw(Canvas canvas)方法. Canvas代表指定View上的画布,常用方法如图: 二 画刷Paint Paint代表Canvas上的画刷,主要用于绘制风格,包括画刷颜色.画刷笔触粗细.填充风格等. 大体上可以分为两类,一类与图形绘制相关,一类与文本绘制相关. 常用方法如图: 三 路径Path Path表示

Android应用开发中对Bitmap的内存优化

在Android应用里,最耗费内存的就是图片资源.而且在Android系统中,读取位图Bitmap时,分给虚拟机中的图片的堆栈大小只有8M,如果超出了,就会出现OutOfMemory异常.所以,对于图片的内存优化,是Android应用开发中比较重要的内容. 1) 要及时回收Bitmap的内存 Bitmap类有一个方法recycle(),从方法名可以看出意思是回收.这里就有疑问了,Android系统有自己的垃圾回收机制,可以不定期的回收掉不使用的内存空间,当然也包括Bitmap的空间.那为什么还需

Android 应用开发中如何自定义 Drawable 背景?

2020-02-06 关键字:EditText自定义背景.shape.corners 通过 xml 定义 View 的背景 Drawable 资源还是挺常用的. 本篇博文记录几种常用的自定义 Drawable 方式. 1.圆角矩形 A.普通圆角矩形 <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/

iOS开发中视图控制器ViewControllers之间的数据传递

iOS开发中视图控制器ViewControllers之间的数据传递 这里我们用一个demo来说明ios是如何在视图控制器之间传递重要的参数的.本文先从手写UI来讨论,在下一篇文章中讨论在storyboard中传递数据. 首先新建一个空工程,并添加一个根视图控制器类,如下图所示: # 在函数didFinishLunchingWithOption中添加几行代码,完成后如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 - (BOOL)application:(UIApplication

Android实际开发中的首页框架搭建(二、首页框架实现)

本来这一篇是前两天就要写的,奈何事多缠身,推到今日,为自己的拖延感到愧疚... 上一篇大概把项目的结构完成了,下一步就是实现首页切换功能了 首先在activity目录下新建一个HomeActivity,作为承载多个fragment的容器 代码如下 1 /* 2 * * 3 * * ******************************************************* 4 * * 5 * * @文件名称:HomeActivity.java 6 * * @文件作者:ouyan

Android应用开发中的夜间模式实现(一)

前言 在应用开发中会经常遇到要求实现夜间模式或者主题切换具体例子如下,我会先讲解第一种方法. 夜间模式 知乎 网易新闻 沪江开心词场 Pocket 主题切换 腾讯QQ 新浪微博 我今天主要是详述第一种的实现方式: 首先,应用的Application要继承自定义的Theme 1 2 3 4 5 6 <application android:allowBackup="true" android:icon="@drawable/ic_launcher" androi