欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

详解Android端与JavaWeb传输加密(DES+RSA)

程序员文章站 2023-12-04 17:53:58
一、加密介绍 本文采用对称式加密算法des和非对称式加密算法rsa结合做数据传输加密的方式。 先说一下对称式加密 des:对称式加密即使用单钥密码加密的方法,信息的...

一、加密介绍

本文采用对称式加密算法des和非对称式加密算法rsa结合做数据传输加密的方式。

先说一下对称式加密 des:对称式加密即使用单钥密码加密的方法,信息的加密和解密使用同一个秘钥,这种方式也称为单秘钥加密。所谓对称就是指加密和解密使用的是同一个秘钥!

常用的对称加密有:des、idea、rc2、rc4、skipjack、rc5、aes算法等。

与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥 (privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。

rsa 公钥加密算法是1977年由ron rivest、adi shamirh和lenadleman在(美国麻省理工学院)开发的。rsa取名来自开发他们三者的名字。rsa是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的所有密码攻击,已被iso推荐为公钥数据加密标准。 rsa算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。

二、rsa密钥生成

rsa密钥采用openssl协议进行生成,本文仅简单生成公钥和私钥,如有其它需要可以通过ca证书进行密钥的生成

1、openssl安装

http://slproweb.com/products/win32openssl.html

请自行选择32位64位进行下载安装

2、打开工作空间

打开openssl安装目录下的bin,运行openssl.exe进入openssl工作空间

3、密钥生成

①、私钥生成(生成位置位于bin目录下)

genrsa -out rsa_private_key.pem 1024

openssl随机生成了一份私钥,加密长度是1024位。加密长度是指理论上最大允许”被加密的信息“长度的限制,也就是明文的长度限制。随着这个参数的增大(比方说2048),允许的明文长度也会增加,但同时也会造成计算复杂度的极速增长。一般推荐的长度就是1024位(128字节)

java需要使用的私钥需要经过pkcs#8编码,php程序不需要

当前私钥格式需要转换为pkcs#8的格式,命令为:

pkcs8 -topk8 -inform pem -in pkcs8_rsa_private_key.pem -outform pem -nocrypt

②、公钥生成

rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout

至此,rsa+des相关前期准备工作完成

三、android端配置

本文主要针对数据传输过程进行加密,采取加密json字符串完成整个加密过程,由此,需要统一传输参数为"data=********&sign="*******************"的格式,如有其它需求请自行更改。

由于本项目网络框架采用retrofit+okhttp的实现方式,所以对参数进行加密的过程由okhttp拦截器来实现

public class encryptioninterceptor implements interceptor {

private context mcontext;

public encryptioninterceptor(context context) {
 this.mcontext = context;
}

@override
public response intercept(@nonnull chain chain) throws ioexception {
 request request = chain.request();
 requestbody oldbody = request.body();
 buffer buffer = new buffer();
 if (oldbody != null) {
  oldbody.writeto(buffer);
 }
 string stroldbody = buffer.readutf8();
 map<string, string> map = new hashmap<>();
 string databyte = urldecoder.decode(stroldbody.substring(5), "utf-8");
 try {
  //获取des的key
  byte[] deskey = descoder.initkey();
  //des加密数据
  byte[] encrypt = descoder.encrypt(databyte.getbytes(), deskey);
  map.put("data", parsebyte2hexstr(encrypt));
  //rsa加密
  rsaencrypt rsaencrypt = new rsaencrypt();
  inputstream inputstream =  mcontext.getresources().getassets().open("rsa_public_key.pem");
  //rsa设置公钥
  rsaencrypt.loadpublickey(inputstream);
  //rsa加密des的key
  byte[] rsadata = rsaencrypt.encrypt(rsaencrypt.getpublickey(), deskey);
  map.put("sign", parsebyte2hexstr(rsadata));
 } catch (exception e) {
  e.printstacktrace();
 }

 formbody body = new formbody.builder().add("data", map.get("data")).add("sign", map.get("sign")).build();
 request = request.newbuilder().header("content-type", body.contenttype().type()).header("content-length", string.valueof(body.contentlength())).method(request.method(), body).build();
 return chain.proceed(request);
}

/**
 * 将二进制转换成16进制
 *
 * @since v1.0
 */
private static string parsebyte2hexstr(byte buf[]) {
 stringbuilder sb = new stringbuilder();
 for (byte abuf : buf) {
  string hex = integer.tohexstring(abuf & 0xff);
  if (hex.length() == 1) {
   hex = '0' + hex;
  }
  sb.append(hex.touppercase());
 }
 return sb.tostring();
}

/**
 * 按照key排序得到参数列表字符串
 *
 * @param paramvalues 参数map对象
 * @return 参数列表字符串
 */
public static string getparamsorderbykey(map<string, string> paramvalues) {
 string params = "";
 list<string> paramnames = new arraylist<>(paramvalues.size());
 paramnames.addall(paramvalues.keyset());
 collections.sort(paramnames);
 for (string paramname : paramnames) {

  if (params.equals("")) {
   params += paramname + "=" + paramvalues.get(paramname);
  } else {
   params += "&" + paramname + "=" + paramvalues.get(paramname);
  }
 }

 return params;
}

/**
 * 将16进制转换为二进制
 *
 * @since v1.0
 */
public byte[] parsehexstr2byte(string hexstr) {
 if (hexstr.length() < 1)
  return null;
 byte[] result = new byte[hexstr.length() / 2];
 for (int i = 0; i < hexstr.length() / 2; i++) {
  int high = integer.parseint(hexstr.substring(i * 2, i * 2 + 1), 16);
  int low = integer.parseint(hexstr.substring(i * 2 + 1, i * 2 + 2), 16);
  result[i] = (byte) (high * 16 + low);
 }
 return result;
}

}

添加okhttp拦截器

new okhttpclient.builder()
    .addinterceptor(new encryptioninterceptor(this))
    .build();

rsa工具类实现

public class rsaencrypt {
public static final string default_public_key =
  "migfma0gcsqgsib3dqebaquaa4gnadcbiqkbgqc1qcf1zvouhsefxvo6+fnvveps" + "\r" + "uvczg6ox+hjmnksiidwcnkbphfznapdtgoby2xf0r8hghbrt53lnvkj7umci48tq" + "\r" + "k+b4ydjhe9sgjvdccicellgtf/ev206qj/xgkgrlfd+vmmjib8gqckzvy/dxhef1" + "\r" + "aamoz5tdjhovdxt7qwidaqab" + "\r";

public static final string default_private_key =
  "miicdgibadanbgkqhkig9w0baqefaascamawggjcageaaogbalvbx/xnu66gx4xg" + "\r" +
    "+jr4wdw8q+xs9zodqhf4emw2sykinzw2rs8d/odo8o2cgfjbexrhwcydutpncs2+" + "\r" +
    "sptqxwjjy2or4hhh0kd71kalumikjx4ssa1/96/btqon9eaqcssup68yamghybak" + "\r" +
    "rm/l93ger/vocajpm10me5v3fptdagmbaaecgyaf1heahhnhss0muzmqv+q3ftzt" + "\r" +
    "snm+6hzbjxpalamgapo3+nsrfmxqxp9mseqw0lgniflocdrb03o3pv98nocizch7" + "\r" +
    "phsu2ghxj04qro+wkhk358326knxcjjqvibg0xmbjxvhjm2/jjfocxfpe5id7h53" + "\r" +
    "c+gvdguvduayo4i1gqjbao21n2aizqv3mscs1o8brv+9cmhadbvhqbetrob3kj2u" + "\r" +
    "piflktnofwwmta5a8skt8wcoz7lsb2swcp9jnvatxa8cqqddncmfo6eix9e5f11k" + "\r" +
    "rf8srin7xgdzlkkzlmqan0utxdtp4an9cuzrwnntwkysxr/zlntylgyn9rdrohbd" + "\r" +
    "9rgnakboesog7iuqcscfqcmoin29psss0oartnbtvniadyrlzuhp0cebgaaord9t" + "\r" +
    "cyfwoxrxg3jarkwdvxqcmqstbq0nakb8flcrhilsqsundype5vfxpixy9jirako8" + "\r" +
    "our6lexfqjoihcevr+l+1oa4hda8fa2thxak7h4wfmxmmmr8fn69akeaur0yu9my" + "\r" +
    "snzwldwyr5snp90phydsl/htzhbnebd+jlaywoyrfyt+txw0/pemv2b3thygpeiz" + "\r" +
    "khkd/telivbxgg==" + "\r";

/**
 * 私钥
 */
private rsaprivatekey privatekey;

/**
 * 公钥
 */
private rsapublickey publickey;

/**
 * 字节数据转字符串专用集合
 */
private static final char[] hex_char = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};


/**
 * 获取私钥
 *
 * @return 当前的私钥对象
 */
public rsaprivatekey getprivatekey() {
 return privatekey;
}

/**
 * 获取公钥
 *
 * @return 当前的公钥对象
 */
public rsapublickey getpublickey() {
 return publickey;
}

/**
 * 随机生成密钥对
 */
public void genkeypair() {
 keypairgenerator keypairgen = null;
 try {
  keypairgen = keypairgenerator.getinstance("rsa");
 } catch (nosuchalgorithmexception e) {
  e.printstacktrace();
 }
 keypairgen.initialize(1024, new securerandom());
 keypair keypair = keypairgen.generatekeypair();
 this.privatekey = (rsaprivatekey) keypair.getprivate();
 this.publickey = (rsapublickey) keypair.getpublic();
}

/**
 * 从文件中输入流中加载公钥
 *
 * @param in 公钥输入流
 * @throws exception 加载公钥时产生的异常
 */
public void 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');
   }
  }
  loadpublickey(sb.tostring());
 } catch (ioexception e) {
  throw new exception("公钥数据流读取错误");
 } catch (nullpointerexception e) {
  throw new exception("公钥输入流为空");
 }
}


/**
 * 从字符串中加载公钥
 *
 * @param publickeystr 公钥数据字符串
 * @throws exception 加载公钥时产生的异常
 */
public void loadpublickey(string publickeystr) throws exception {
 try {
 // byte[] buffer = base64.decode(publickeystr.getbytes(), base64.default);
  base64decoder base64decoder= new base64decoder();
  byte[] buffer= base64decoder.decodebuffer(publickeystr);
  keyfactory keyfactory = keyfactory.getinstance("rsa");
  x509encodedkeyspec keyspec = new x509encodedkeyspec(buffer);
  this.publickey = (rsapublickey) keyfactory.generatepublic(keyspec);
 } catch (nosuchalgorithmexception e) {
  throw new exception("无此算法");
 } catch (invalidkeyspecexception e) {
  throw new exception("公钥非法");
 } catch (nullpointerexception e) {
  throw new exception("公钥数据为空");
 }
}

/**
 * 从文件中加载私钥
 *
 * @return 是否成功
 * @throws exception
 */
public void 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');
   }
  }
  loadprivatekey(sb.tostring());
 } catch (ioexception e) {
  throw new exception("私钥数据读取错误");
 } catch (nullpointerexception e) {
  throw new exception("私钥输入流为空");
 }
}

public void loadprivatekey(string privatekeystr) throws exception {
 try {
  //byte[] buffer = base64.encode(privatekeystr.getbytes(), base64.default);
  base64decoder base64decoder= new base64decoder();
  byte[] buffer= base64decoder.decodebuffer(privatekeystr);
  pkcs8encodedkeyspec keyspec = new pkcs8encodedkeyspec(buffer);
  keyfactory keyfactory = keyfactory.getinstance("rsa");
  this.privatekey = (rsaprivatekey) keyfactory.generateprivate(keyspec);
 } catch (nosuchalgorithmexception e) {
  throw new exception("无此算法");
 } catch (invalidkeyspecexception e) {
  throw new exception("私钥非法");
 } catch (nullpointerexception e) {
  throw new exception("私钥数据为空");
 }
}

/**
 * 加密过程
 *
 * @param publickey  公钥
 * @param plaintextdata 明文数据
 * @return
 * @throws exception 加密过程中的异常信息
 */
public byte[] encrypt(rsapublickey publickey, byte[] plaintextdata) throws exception {
 if (publickey == null) {
  throw new exception("加密公钥为空, 请设置");
 }
 cipher cipher = null;
 try {
  
  cipher = cipher.getinstance("rsa");
  //android端无需添加此加密提供者,已默认实现
  //cipher = cipher.getinstance("rsa", new bouncycastleprovider());
  cipher.init(cipher.encrypt_mode, publickey);
  return cipher.dofinal(plaintextdata);
 } catch (nosuchalgorithmexception e) {
  throw new exception("无此加密算法");
 } catch (nosuchpaddingexception e) {
  e.printstacktrace();
  return null;
 } catch (invalidkeyexception e) {
  throw new exception("加密公钥非法,请检查");
 } catch (illegalblocksizeexception e) {
  throw new exception("明文长度非法");
 } catch (badpaddingexception e) {
  throw new exception("明文数据已损坏");
 }
}

/**
 * 解密过程
 *
 * @param privatekey 私钥
 * @param cipherdata 密文数据
 * @return 明文
 * @throws exception 解密过程中的异常信息
 */
public byte[] decrypt(rsaprivatekey privatekey, byte[] cipherdata) throws exception {
 if (privatekey == null) {
  throw new exception("解密私钥为空, 请设置");
 }
 cipher cipher = null;
 try {
  cipher = cipher.getinstance("rsa");
  //android端无需添加此加密提供者,已默认实现
  //cipher = cipher.getinstance("rsa", new bouncycastleprovider());
  cipher.init(cipher.decrypt_mode, privatekey);
  byte[] output = cipher.dofinal(cipherdata);
  return output;
 } catch (nosuchalgorithmexception e) {
  throw new exception("无此解密算法");
 } catch (nosuchpaddingexception e) {
  e.printstacktrace();
  return null;
 } catch (invalidkeyexception e) {
  throw new exception("解密私钥非法,请检查");
 } catch (illegalblocksizeexception e) {
  throw new exception("密文长度非法");
 } catch (badpaddingexception e) {
  throw new exception("密文数据已损坏");
 }
}


/**
 * 字节数据转十六进制字符串
 *
 * @param data 输入数据
 * @return 十六进制内容
 */
public static string bytearraytostring(byte[] data) {
 stringbuilder stringbuilder = new stringbuilder();
 for (int i = 0; i < data.length; i++) {
  //取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移 
  stringbuilder.append(hex_char[(data[i] & 0xf0) >>> 4]);
  //取出字节的低四位 作为索引得到相应的十六进制标识符 
  stringbuilder.append(hex_char[(data[i] & 0x0f)]);
  if (i < data.length - 1) {
   stringbuilder.append(' ');
  }
 }
 return stringbuilder.tostring();
}


public static void main(string[] args) {
 rsaencrypt rsaencrypt = new rsaencrypt();

 //加载公钥
 try {
  rsaencrypt.loadpublickey(rsaencrypt.default_public_key);
  system.out.println("加载公钥成功");
 } catch (exception e) {
  system.err.println(e.getmessage());
  system.err.println("加载公钥失败");
 }
 /*try {
  rsaencrypt.loadpublickey(rsaencrypt.default_public_key);
  system.out.println("加载公钥成功");
 } catch (exception e) {
  system.err.println(e.getmessage());
  system.err.println("加载公钥失败");
 }
 //加载私钥
 try {
  rsaencrypt.loadprivatekey(rsaencrypt.default_private_key);
  system.out.println("加载私钥成功");
 } catch (exception e) {
  system.err.println(e.getmessage());
  system.err.println("加载私钥失败");
 }
 try {
  securerandom sr = new securerandom();
  keygenerator kg = keygenerator.getinstance("des");
  kg.init(56, sr);
  secretkey generatekey = kg.generatekey();
  string encodehexstring = hex.tohexstring(generatekey.getencoded());
  system.out.println(encodehexstring);
 } catch (nosuchalgorithmexception e) {
  e.printstacktrace();
 }
 //测试字符串
 string encryptstr= "test string chaijunkun";

 try {
  //加密
  long encryptstart = system.currenttimemillis();
  byte[] cipher = rsaencrypt.encrypt(rsaencrypt.getpublickey(), encryptstr.getbytes());
  long encryptend = system.currenttimemillis();
  system.out.println("密文长度:"+ cipher.length);
  system.out.println(rsaencrypt.bytearraytostring(cipher));
  system.out.println("加密时间"+ (encryptend-encryptstart));

  //解密
  long decryptstart = system.currenttimemillis();
  byte[] plaintext = rsaencrypt.decrypt(rsaencrypt.getprivatekey(), cipher);
  long decryptend = system.currenttimemillis();
  system.out.println("明文长度:"+ plaintext.length);
  system.out.println(rsaencrypt.bytearraytostring(plaintext));
  system.out.println("解密时间"+ (decryptend-decryptstart));

  system.out.println(new string(plaintext));
 } catch (exception e) {
  system.err.println(e.getmessage());
 }*/ 
  }
} 

des工具类实现

public class descoder {
/**
 * 密钥算法
 * java 7只支持56位密钥
 * bouncy castle 支持64位密钥
 */
public static final string key_algorithm = "des";
/**
 * 加密/解密算法 /工作模式/填充方式
 */
public static final string cipher_algorithm = "des/ecb/pkcs5padding";
/**
 * 转换密钥
 * @param key 二进制密钥
 * @return key 密钥
 * @throws exception
 */
private static key tokey(byte[] key) throws exception{
 //实例化des密钥材料
 deskeyspec dks = new deskeyspec(key);
 //实例化密钥工厂
 secretkeyfactory keyfactory = secretkeyfactory.getinstance(key_algorithm);
 //生产密钥
 secretkey secretkey = keyfactory.generatesecret(dks);
 return secretkey;
}
/**
 * 解密
 * @param data 待解密数据
 * @param key 密钥
 * @return byte[] 解密数据
 * @throws exception
 */
public static byte[] decrypt(byte[] data,byte[] key) throws exception{
 //还原密钥
 key k = tokey(key);
 //实例化 
 cipher cipher = cipher.getinstance(cipher_algorithm);
 //初始化,设置为解密模式
 cipher.init(cipher.decrypt_mode, k);
 //执行操作
 return cipher.dofinal(data);
}
/**
 * 加密
 * @param data 待加密数据
 * @param key 密钥
 * @return byte[] 加密数据
 * @throws exception
 */
public static byte[] encrypt(byte[] data,byte[] key) throws exception{
 //还原密钥
 key k = tokey(key);
 //实例化
 cipher cipher = cipher.getinstance(cipher_algorithm,new bouncycastleprovider());
 //初始化,设置为加密模式
 cipher.init(cipher.encrypt_mode,k);
 //执行操作
 return cipher.dofinal(data);
}
/**
 * 生产密钥
 * java 7只支持56位 密钥
 * bouncy castle 支持64位密钥
 * @return byte[] 二进制密钥
 * @throws exception
 */
public static byte[] initkey() throws exception{
 /*
  * 实例化密钥生成器
  * 若要使用64位密钥注意替换
  * 讲下述代码中的
  * keygenerator.getinstance(key_algorithm);
  * 替换为
  * keygenerator.getinstance(key_algorithm,"bc");
  */
 keygenerator kg = keygenerator.getinstance(key_algorithm,new bouncycastleprovider());

 kg.init(64);
 //生成密钥
 secretkey secretkey = kg.generatekey();
 //获得密钥的二进制编码形式
 return secretkey.getencoded();
}
}

四、javaweb端配置

web后端只需要在controller中添加以下代码,接受服务端传递的data和sign,并完成接收的json字符串转换为实体类即可

/**
 * 解密所需数据
 *
 * @param data 接受客户端上传的json格式的数据
 * @param sign 接受客户端上传的解密数据的key值
 */
public <t> t convertjson(string data, string sign,class<t> clazz) {
 system.out.println(data);
 system.out.println(sign);
 t tclass = null;
 try {
  //rsa加密
  rsaencrypt rsaencrypt = new rsaencrypt();
  //加载rsa私钥
  inputstream in = new fileinputstream(new file("c:\\openssl-win64\\bin\\pkcs8_rsa_private_key.pem"));
  rsaencrypt.loadprivatekey(in);
  //获取rsa加密的key的数据,并把该16进制的sign转成byte[],(客户端采用将byte[]转成16进制进行数据上传)
  byte[] keybytes = parsehexstr2byte(sign);
  //通过rsa解密des的key值
  byte[] rsakey = rsaencrypt.decrypt(rsaencrypt.getprivatekey(), keybytes);

  //通过des的key值解密需要的json数据
  byte[] desdata = descoder.decrypt(parsehexstr2byte(data), rsakey);
  system.out.println(arrays.tostring(desdata));
  system.out.println(new string(desdata));
  tclass = json.parseobject(new string(desdata), clazz);
 } catch (exception e) {
  e.printstacktrace();
 }
 return tclass;
}


五、备注

后续会上传相关demo到github

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。