一.概念

1.1目的

由于工作中用到了趟过了许多的坑所以深有体会,所以想写个笔记怕以后忘记了,好到时候回来看看。

首先是一定要知道最基础的概念,一定要知道最基础的概念,一定要知道最基础的概念,以免被误导。

1.2具体概念(就俩RSA加密和校验)

在这里摘抄百度百科中的要点,具体的请自行百度或google。

1.2.1 RSA:RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密(这俩不同哦)。这里分为公钥(pk)和秘钥(sk),这里使用pk加密,sk解密(其实也可以sk加密,pk解密,但是前者更加的安全所以使用前者)。

可以理解为:实际使用时候公钥加密,私钥解密

1.2.2 RSA既能用于数据加密也能用于数字签名的算法。

1.2.3 数字签名:数字签名(又称公钥数字签名、电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。

可以理解为:私钥进行签名,公钥负责校验,验证信息提供者有效身份。

1.2如何使用(理论):

1.2.1先来说一下限制条件:

a.生成密文的长度和明文长度无关,但明文长度不能超过密钥长度(不管明文长度是多少,RSA 生成的密文长度总是固定的。但是明文长度不能超过密钥长度。比如 Java 默认的 RSA 加密实现不允许明文长度超过密钥长度减去 11(单位是字节,也就是 byte)。也就是说,如果我们定义的密钥(我们可以通过 java.security.KeyPairGenerator.initialize(int keysize) 来定义密钥长度)长度为 1024(单位是位,也就是 bit),生成的密钥长度就是 1024位 / 8位/字节 = 128字节,那么我们需要加密的明文长度不能超过 128字节 -11 字节 = 117字节。也就是说,我们最大能将 117 字节长度的明文进行加密,否则会出问题(抛诸如 javax.crypto.IllegalBlockSizeException: Data must not be longer than 53 bytes 的异常)。);

b.生成密文的长度等于密钥长度

使用RSA加密时候的各种坑连接

1.2.2加密没有唯一方案可言选择适合的方案就好。通常我们选用对称加密和非对称加密结合的方案(对称选AES,DES,3DES;非对称用RSA);

分情况讨论

第一种情况:被加密的数据量很小直接用RSA

第二种情况:加密的数据量较大但是对称加密不放心,使用AES,DES,3DES中一种和RSA结合方式,具体数据用对称加密一种加密,而对称加密的秘钥用RSA加密传给服务端,服务端则先RSA解密出对称加密的秘钥,再用它解密已经加密的数据;

第三种情况:要校验信息来源的真实性(是不是服务端传来的“原始数据”),使用RSA的私钥签名,公钥校验;

二实现代码(用Android端和java后台)

点击完整代码下载

2.1各种工具类,下面代码齐全,copy就能用(不懂仔细看代码中注释很详细)

加密解密工具类

/*** Created by gxo on 2017/11/29.* 加密解密工具类*/
public class RSAEncrypt {/*** 公钥加密过程* @param plainTextData*            明文数据* @return  密文数据* @throws Exception*             加密过程中的异常信息*/public static byte[] encryptByPublicKey(byte[] plainTextData) throws Exception {RSAPublicKey publicKey = RsaKeyUtil.loadPublicKey();if (publicKey == null) {throw new Exception("加密公钥为空, 请设置");}Cipher cipher = null;try {// 使用默认RSAcipher = Cipher.getInstance("RSA");// cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());cipher.init(Cipher.ENCRYPT_MODE, publicKey);byte[] output = cipher.doFinal(plainTextData);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 plainTextData*            明文数据* @return 密文数据* @throws Exception*             加密过程中的异常信息*/public static byte[] encryptByPrivateKey(byte[] plainTextData) throws Exception {RSAPrivateKey privateKey = RsaKeyUtil.loadPrivateKey();if (privateKey == null) {throw new Exception("加密私钥为空, 请设置");}Cipher cipher = null;try {// 使用默认RSAcipher = Cipher.getInstance("RSA");cipher.init(Cipher.ENCRYPT_MODE, privateKey);byte[] output = cipher.doFinal(plainTextData);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 cipherData 密文数据* @return 明文* @throws Exception*             解密过程中的异常信息*/public static byte[] decryptByPrivateKey(byte[] cipherData) throws Exception {RSAPrivateKey privateKey = RsaKeyUtil.loadPrivateKey();if (privateKey == null) {throw new Exception("解密私钥为空, 请设置");}Cipher cipher = null;try {// 使用默认RSAcipher = Cipher.getInstance("RSA");// 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 cipherData*            密文数据* @return 明文* @throws Exception*             解密过程中的异常信息*/public static byte[] decryptByPublicKey( byte[] cipherData) throws Exception {RSAPublicKey publicKey = RsaKeyUtil.loadPublicKey();if (publicKey == null) {throw new Exception("解密公钥为空, 请设置");}Cipher cipher = null;try {// 使用默认RSAcipher = Cipher.getInstance("RSA");// cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());cipher.init(Cipher.DECRYPT_MODE, publicKey);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("密文数据已损坏");}}
}

秘钥管理类

/*** Created by gxo on 2017/11/30.* 秘钥管理类*/public class RsaKeyUtil {/*** 随机生成密钥对*/public static void genKeyPair(Handler handler) {// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象KeyPairGenerator keyPairGen = null;try {keyPairGen = KeyPairGenerator.getInstance("RSA");} catch (NoSuchAlgorithmException e) {// TODO Auto-generated catch blocke.printStackTrace();}// 初始化密钥对生成器,密钥大小为96-1024位(这里是常用值)keyPairGen.initialize(1024,new SecureRandom());// 生成一个密钥对,保存在keyPair中KeyPair keyPair = keyPairGen.generateKeyPair();// 得到私钥RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();// 得到公钥RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();try {// 得到公钥字符串String publicKeyString = Base64.encode(publicKey.getEncoded());// 得到私钥字符串String privateKeyString = Base64.encode(privateKey.getEncoded());Log.e("publicKeyString",publicKeyString);Log.e("privateKeyString",privateKeyString);// 将密钥对写入到文件(文件后缀不重要只要系统能识别的文件都行,只是为了存储用)String publicKeyPath = FIleUtils.getPublicKeyPath();String privateKeyPath = FIleUtils.getPrivateKeyPath();FileWriter pubfw = new FileWriter(publicKeyPath);FileWriter prifw = new FileWriter(privateKeyPath);BufferedWriter pubbw = new BufferedWriter(pubfw);BufferedWriter pribw = new BufferedWriter(prifw);pubbw.write(publicKeyString);pribw.write(privateKeyString);pubbw.flush();pubbw.close();pubfw.close();pribw.flush();pribw.close();prifw.close();handler.sendEmptyMessage(1);} catch (Exception e) {e.printStackTrace();}}/*** 加载公钥*/public static RSAPublicKey loadPublicKey() throws Exception {String publicKeyStr = loadPublicKeyByFile();try {byte[] buffer = Base64.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 (NullPointerException e) {throw new Exception("公钥数据为空");}}/*** 从文件中加载公钥* @throws Exception 加载公钥时产生的异常*/public static String loadPublicKeyByFile() throws Exception {try {BufferedReader br = new BufferedReader(new FileReader(FIleUtils.getPublicKeyPath()));String readLine = null;StringBuilder sb = new StringBuilder();while ((readLine = br.readLine()) != null) {sb.append(readLine);}br.close();Log.e("publicKeyStr",sb.toString());return sb.toString();} catch (IOException e) {throw new Exception("公钥数据流读取错误");} catch (NullPointerException e) {throw new Exception("公钥输入流为空");}}public static RSAPrivateKey loadPrivateKey() throws Exception {String privateKeyStr = loadPrivateKeyByFile();try {byte[] buffer = Base64.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 (NullPointerException e) {throw new Exception("私钥数据为空");}}/*** 从文件中加载私钥* @throws Exception*/public static String loadPrivateKeyByFile() throws Exception {try {BufferedReader br = new BufferedReader(new FileReader(FIleUtils.getPrivateKeyPath()));String readLine = null;StringBuilder sb = new StringBuilder();while ((readLine = br.readLine()) != null) {sb.append(readLine);}br.close();Log.e("privateKeyStr",sb.toString());return sb.toString();} catch (IOException e) {throw new Exception("私钥数据读取错误");} catch (NullPointerException e) {throw new Exception("私钥输入流为空");}}
}

文件处理类

/*** Created by gxo on 2017/11/29.* 文件处理类*/public class FIleUtils {public static String getPrivateKeyPath(){String rootPath = getRootPath();String filePath = rootPath + "/privateKey.keystore";File file = new File(filePath);if (!file.exists()){try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}return filePath;}public static String getPublicKeyPath(){String rootPath = getRootPath();String filePath = rootPath + "/publicKey.keystore";File file = new File(filePath);if (!file.exists()){try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}return filePath;}private static String getRootPath() {String filepath= Environment.getExternalStorageDirectory().getPath() + File.separator + "mykey"+ File.separator + "pripub";File file = new File(filepath);if (!file.exists()) {file.mkdirs();}return filepath;}
}

签名和校验类

/*** Created by gxo on 2017/11/29.* 签名和校验类*/public class RSASignature {/*** 签名算法*/public static final String SIGN_ALGORITHMS = "SHA1WithRSA";/*** RSA签名* @param content 待签名数据* @param privateKey 商户私钥* @param encode 字符集编码* @return 签名值*/public static String sign(String content, String privateKey, String encode){try{PKCS8EncodedKeySpec priPKCS8    = new PKCS8EncodedKeySpec( Base64.decode(privateKey) );KeyFactory keyf                 = KeyFactory.getInstance("RSA");PrivateKey priKey               = keyf.generatePrivate(priPKCS8);java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);signature.initSign(priKey);signature.update( content.getBytes(encode));byte[] signed = signature.sign();return Base64.encode(signed);}catch (Exception e){e.printStackTrace();}return null;}public static String sign(String content) {try {String privateKey = RsaKeyUtil.loadPrivateKeyByFile();PKCS8EncodedKeySpec priPKCS8    = new PKCS8EncodedKeySpec( Base64.decode(privateKey) );KeyFactory keyf = KeyFactory.getInstance("RSA");PrivateKey priKey = keyf.generatePrivate(priPKCS8);java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);signature.initSign(priKey);signature.update( content.getBytes());byte[] signed = signature.sign();return Base64.encode(signed);}catch (Exception e){e.printStackTrace();}return null;}public static boolean doCheck(String content, String sign) {try {String publicKey = RsaKeyUtil.loadPublicKeyByFile();KeyFactory keyFactory = KeyFactory.getInstance("RSA");byte[] encodedKey = Base64.decode(publicKey);PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));java.security.Signature signature = java.security.Signature.getInstance(SIGN_ALGORITHMS);signature.initVerify(pubKey);signature.update( content.getBytes() );boolean bverify = signature.verify( Base64.decode(sign) );return bverify;}catch (Exception e){e.printStackTrace();}return false;}
}

测试入口

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);testRsa();}Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {if (msg != null){int what = msg.what;switch (what){case 1:publicEncryptPrivateDecrypt();//验证公钥加密私钥解密//privateEncryptPublicDecrypt();//验证私钥加密公钥解密//signAndCheck();//验证签名和校验break;}}}};private void signAndCheck() {System.out.println("---------------私钥签名过程------------------");String content="ihep_这是用于签名的原始数据";String signstr= null;try {signstr = RSASignature.sign(content);} catch (Exception e) {e.printStackTrace();}System.out.println("签名原串:"+content);System.out.println("签名串:"+signstr);System.out.println();System.out.println("---------------公钥校验签名------------------");System.out.println("签名原串:"+content);System.out.println("签名串:"+signstr);try {System.out.println("验签结果:"+RSASignature.doCheck(content, signstr));} catch (Exception e) {e.printStackTrace();}System.out.println();}private void privateEncryptPublicDecrypt() {System.out.println("--------------私钥加密公钥解密过程-------------------");String plainText="ihep_私钥加密公钥解密";//私钥加密过程byte[] cipherData= new byte[0];try {cipherData=RSAEncrypt.encryptByPrivateKey(plainText.getBytes());} catch (Exception e) {e.printStackTrace();}String cipher=Base64.encode(cipherData);//公钥解密过程byte[] res= new byte[0];try {res=RSAEncrypt.decryptByPublicKey(Base64.decode(cipher));} catch (Exception e) {e.printStackTrace();}String restr=new String(res);System.out.println("原文:"+plainText);System.out.println("加密:"+cipher);System.out.println("解密:"+restr);System.out.println();}private void publicEncryptPrivateDecrypt() {System.out.println("--------------公钥加密私钥解密过程-------------------");String plainText="公钥加密私钥解密过程";//公钥加密过程byte[] cipherData= new byte[0];try {cipherData = RSAEncrypt.encryptByPublicKey(plainText.getBytes());} catch (Exception e) {e.printStackTrace();}//生成可以传送的字符串String cipher=Base64.encode(cipherData);//私钥解密过程byte[] res= new byte[0];try {res = RSAEncrypt.decryptByPrivateKey(Base64.decode(cipher));} catch (Exception e) {e.printStackTrace();}String restr=new String(res);System.out.println("原文:"+plainText);System.out.println("加密:"+cipher);System.out.println("解密:"+restr);System.out.println();}private void testRsa() {new Thread(new Runnable() {@Overridepublic void run() {//生成公钥和私钥文件并保存RsaKeyUtil.genKeyPair(handler);}}).start();}
}

Base64管理类

/*** Created by gxo on 2017/11/29.* Base64管理类*/public class Base64 {static private final int     BASELENGTH           = 128;static private final int     LOOKUPLENGTH         = 64;static private final int     TWENTYFOURBITGROUP   = 24;static private final int     EIGHTBIT             = 8;static private final int     SIXTEENBIT           = 16;static private final int     FOURBYTE             = 4;static private final int     SIGN                 = -128;static private final char    PAD                  = '=';static private final boolean fDebug               = false;static final private byte[]  base64Alphabet       = new byte[BASELENGTH];static final private char[]  lookUpBase64Alphabet = new char[LOOKUPLENGTH];static {for (int i = 0; i < BASELENGTH; ++i) {base64Alphabet[i] = -1;}for (int i = 'Z'; i >= 'A'; i--) {base64Alphabet[i] = (byte) (i - 'A');}for (int i = 'z'; i >= 'a'; i--) {base64Alphabet[i] = (byte) (i - 'a' + 26);}for (int i = '9'; i >= '0'; i--) {base64Alphabet[i] = (byte) (i - '0' + 52);}base64Alphabet['+'] = 62;base64Alphabet['/'] = 63;for (int i = 0; i <= 25; i++) {lookUpBase64Alphabet[i] = (char) ('A' + i);}for (int i = 26, j = 0; i <= 51; i++, j++) {lookUpBase64Alphabet[i] = (char) ('a' + j);}for (int i = 52, j = 0; i <= 61; i++, j++) {lookUpBase64Alphabet[i] = (char) ('0' + j);}lookUpBase64Alphabet[62] = (char) '+';lookUpBase64Alphabet[63] = (char) '/';}private static boolean isWhiteSpace(char octect) {return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);}private static boolean isPad(char octect) {return (octect == PAD);}private static boolean isData(char octect) {return (octect < BASELENGTH && base64Alphabet[octect] != -1);}/*** Encodes hex octects into Base64** @param binaryData Array containing binaryData* @return Encoded Base64 array*/public static String encode(byte[] binaryData) {if (binaryData == null) {return null;}int lengthDataBits = binaryData.length * EIGHTBIT;if (lengthDataBits == 0) {return "";}int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;char encodedData[] = null;encodedData = new char[numberQuartet * 4];byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;int encodedIndex = 0;int dataIndex = 0;if (fDebug) {System.out.println("number of triplets = " + numberTriplets);}for (int i = 0; i < numberTriplets; i++) {b1 = binaryData[dataIndex++];b2 = binaryData[dataIndex++];b3 = binaryData[dataIndex++];if (fDebug) {System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);}l = (byte) (b2 & 0x0f);k = (byte) (b1 & 0x03);byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);if (fDebug) {System.out.println("val2 = " + val2);System.out.println("k4   = " + (k << 4));System.out.println("vak  = " + (val2 | (k << 4)));}encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];}// form integral number of 6-bit groupsif (fewerThan24bits == EIGHTBIT) {b1 = binaryData[dataIndex];k = (byte) (b1 & 0x03);if (fDebug) {System.out.println("b1=" + b1);System.out.println("b1<<2 = " + (b1 >> 2));}byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];encodedData[encodedIndex++] = PAD;encodedData[encodedIndex++] = PAD;} else if (fewerThan24bits == SIXTEENBIT) {b1 = binaryData[dataIndex];b2 = binaryData[dataIndex + 1];l = (byte) (b2 & 0x0f);k = (byte) (b1 & 0x03);byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];encodedData[encodedIndex++] = PAD;}return new String(encodedData);}/*** Decodes Base64 data into octects** @param encoded string containing Base64 data* @return Array containind decoded data.*/public static byte[] decode(String encoded) {if (encoded == null) {return null;}char[] base64Data = encoded.toCharArray();// remove white spacesint len = removeWhiteSpace(base64Data);if (len % FOURBYTE != 0) {return null;//should be divisible by four}int numberQuadruple = (len / FOURBYTE);if (numberQuadruple == 0) {return new byte[0];}byte decodedData[] = null;byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;char d1 = 0, d2 = 0, d3 = 0, d4 = 0;int i = 0;int encodedIndex = 0;int dataIndex = 0;decodedData = new byte[(numberQuadruple) * 3];for (; i < numberQuadruple - 1; i++) {if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))|| !isData((d3 = base64Data[dataIndex++]))|| !isData((d4 = base64Data[dataIndex++]))) {return null;}//if found "no data" just return nullb1 = base64Alphabet[d1];b2 = base64Alphabet[d2];b3 = base64Alphabet[d3];b4 = base64Alphabet[d4];decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);}if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))) {return null;//if found "no data" just return null}b1 = base64Alphabet[d1];b2 = base64Alphabet[d2];d3 = base64Data[dataIndex++];d4 = base64Data[dataIndex++];if (!isData((d3)) || !isData((d4))) {//Check if they are PAD charactersif (isPad(d3) && isPad(d4)) {if ((b2 & 0xf) != 0)//last 4 bits should be zero{return null;}byte[] tmp = new byte[i * 3 + 1];System.arraycopy(decodedData, 0, tmp, 0, i * 3);tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);return tmp;} else if (!isPad(d3) && isPad(d4)) {b3 = base64Alphabet[d3];if ((b3 & 0x3) != 0)//last 2 bits should be zero{return null;}byte[] tmp = new byte[i * 3 + 2];System.arraycopy(decodedData, 0, tmp, 0, i * 3);tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));return tmp;} else {return null;}} else { //No PAD e.g 3cQlb3 = base64Alphabet[d3];b4 = base64Alphabet[d4];decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);}return decodedData;}/*** remove WhiteSpace from MIME containing encoded Base64 data.** @param data  the byte array of base64 data (with WS)* @return      the new length*/private static int removeWhiteSpace(char[] data) {if (data == null) {return 0;}// count characters that's not whitespaceint newSize = 0;int len = data.length;for (int i = 0; i < len; i++) {if (!isWhiteSpace(data[i])) {data[newSize++] = data[i];}}return newSize;}
}

2.2工具类的说明

2.2.1私钥加密和公钥解密只是为了说明可以实现,但是实际不能这么写

2.2.2产生秘钥对的方式有很多种,这里为了方便在Android代码中生成放在文件中;实际生产中可以使用线上的工具产生,也可以下载工具在本地产生,也可以在java后台产生;使用的时候可以把秘钥字符串放在java代码中也可以放在文件中。(不知道怎么找可以百度)

2.2.3代码中io操作的有的地方应放在子线程中,这里为了偷懒

2.3下面依次是上面三种测试的log(知道可以用了吧!哈哈)

2.3.1公钥加密私钥解密

12-01 08:46:11.333 14150-14189/com.rsa.test E/publicKeyString: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC80bTu4sQOt35PRCTlmXhAciTINBxe+bM9Qx7wz11k5xTzZbjbpEZaAlfurKohM8hWCblEJ7qE02N3NaY3enbNec1IAW67YchE41Us81nMUIvGg91eFpGj9Sf8WkVRvvNjmGaJMjQ2ufEzM5DUDysR44RxTu1aCrdCZs9ZqRESeQIDAQAB
12-01 08:46:11.333 14150-14189/com.rsa.test E/privateKeyString: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALzRtO7ixA63fk9EJOWZeEByJMg0HF75sz1DHvDPXWTnFPNluNukRloCV+6sqiEzyFYJuUQnuoTTY3c1pjd6ds15zUgBbrthyETjVSzzWcxQi8aD3V4WkaP1J/xaRVG+82OYZokyNDa58TMzkNQPKxHjhHFO7VoKt0Jmz1mpERJ5AgMBAAECgYEAjfycNG8tw2tUfkLeBBGuDbhH1IzrMLhQgqbwo2Er9+6VIJrDsdcMWC8e9Im+vYz0/038lTXS2oMjbsdXIKzknD5k7BAFVimXNNzCJryhS7MmzO+VSeEDE2LdWxMdpXDKNb4iKInuxRfXAeIsor0LIL7Da8HvU0DgfF6V1Q9XnUkCQQD1m+77rhJSpL7aOjCEQMPCuz+TjH23Y+5Y0fSbnHxMCqb/nPd4jXvg6FJCe6d+eBr/61DAlmlr1+Wjcuvi7VwTAkEAxM613aH1mhOgMhs09R4/QC8Wy7wDNy+D22+meo38OBO0ILr9XfsNuBxex6M12C1pmL5BY6JpROnz7j8fbEpQwwJBALt/iibKkaRTrntMduNPyeJsLjHGy+ZnvHpD9hehk+Y9L5Xtz6JRaGOfF8U3Pvu2Vu5ORzxu1xYEIIPx5JA9oc8CQBAT+xOSKahethWh11+3Ct/JeQlH4NNfVFxW8LjOZK6IHY0W+Z/15JcH6k5Q7RMuEpRh5qGnIQZ6Pm1WRtDn+VUCQFHQpCYW6kVYh7eAm1kPZ0e1CBBJEHRaqmuLaNy79hQWWLYO1R9eMfbMYVjXlxSS/7RWrZ8zthiZ/D7PL3NXVwM=12-01 08:46:11.337 14150-14150/com.rsa.test I/System.out: --------------公钥加密私钥解密过程-------------------
12-01 08:46:11.338 14150-14150/com.rsa.test E/publicKeyStr: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC80bTu4sQOt35PRCTlmXhAciTINBxe+bM9Qx7wz11k5xTzZbjbpEZaAlfurKohM8hWCblEJ7qE02N3NaY3enbNec1IAW67YchE41Us81nMUIvGg91eFpGj9Sf8WkVRvvNjmGaJMjQ2ufEzM5DUDysR44RxTu1aCrdCZs9ZqRESeQIDAQAB
12-01 08:46:11.342 14150-14150/com.rsa.test E/privateKeyStr: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALzRtO7ixA63fk9EJOWZeEByJMg0HF75sz1DHvDPXWTnFPNluNukRloCV+6sqiEzyFYJuUQnuoTTY3c1pjd6ds15zUgBbrthyETjVSzzWcxQi8aD3V4WkaP1J/xaRVG+82OYZokyNDa58TMzkNQPKxHjhHFO7VoKt0Jmz1mpERJ5AgMBAAECgYEAjfycNG8tw2tUfkLeBBGuDbhH1IzrMLhQgqbwo2Er9+6VIJrDsdcMWC8e9Im+vYz0/038lTXS2oMjbsdXIKzknD5k7BAFVimXNNzCJryhS7MmzO+VSeEDE2LdWxMdpXDKNb4iKInuxRfXAeIsor0LIL7Da8HvU0DgfF6V1Q9XnUkCQQD1m+77rhJSpL7aOjCEQMPCuz+TjH23Y+5Y0fSbnHxMCqb/nPd4jXvg6FJCe6d+eBr/61DAlmlr1+Wjcuvi7VwTAkEAxM613aH1mhOgMhs09R4/QC8Wy7wDNy+D22+meo38OBO0ILr9XfsNuBxex6M12C1pmL5BY6JpROnz7j8fbEpQwwJBALt/iibKkaRTrntMduNPyeJsLjHGy+ZnvHpD9hehk+Y9L5Xtz6JRaGOfF8U3Pvu2Vu5ORzxu1xYEIIPx5JA9oc8CQBAT+xOSKahethWh11+3Ct/JeQlH4NNfVFxW8LjOZK6IHY0W+Z/15JcH6k5Q7RMuEpRh5qGnIQZ6Pm1WRtDn+VUCQFHQpCYW6kVYh7eAm1kPZ0e1CBBJEHRaqmuLaNy79hQWWLYO1R9eMfbMYVjXlxSS/7RWrZ8zthiZ/D7PL3NXVwM=
12-01 08:46:11.351 14150-14150/com.rsa.test I/System.out: 原文:公钥加密私钥解密过程
12-01 08:46:11.351 14150-14150/com.rsa.test I/System.out: 加密:uQ0UIGF2TunqQHnW7E8li8wSvhK8IS+mKufpZ1qtove3W5yCv406T7tLyu1BXpaf17+uj2kefYGwqiAxIHnRjcqaTs13Wl6yh5K0W3t2VCvd697EYo2kXjXfpCICkVlOYXUYyHItre7FB48KNXsw2DV94ttytuO1igyixYzFl8A=
12-01 08:46:11.351 14150-14150/com.rsa.test I/System.out: 解密:公钥加密私钥解密过程

2.3.2私钥加密公钥解密

12-01 08:49:09.557 16713-16743/com.rsa.test E/publicKeyString: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDB2ZDYqyQ/3Wdsa+E+QvQkB1kunl7zxXezDwaHJTQoOGNCSJFGG8rMHTblrvOIlmyHgXGNbFA4UWZrbzWUHEhzzHO3L088tF+Z4h8TECL1DDHLALgm8p20tUzR/qMaIfeOsh6N9D1IsQ9P10SJlHV8w+SCrB0J2vh/m73QZWKTdQIDAQAB
12-01 08:49:09.557 16713-16743/com.rsa.test E/privateKeyString: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMHZkNirJD/dZ2xr4T5C9CQHWS6eXvPFd7MPBoclNCg4Y0JIkUYbyswdNuWu84iWbIeBcY1sUDhRZmtvNZQcSHPMc7cvTzy0X5niHxMQIvUMMcsAuCbynbS1TNH+oxoh946yHo30PUixD0/XRImUdXzD5IKsHQna+H+bvdBlYpN1AgMBAAECgYEAo6QiXoW6yB8DW8eGEaU7q954Lp6K0YZ1Ebcxb4y8hudzA1V3LZPwknZnDWWvODKj05A2Z4hz/9bXewIaXLmzfnKfpGaSuGFPg4ldaxJMIZpuGGP8XQonkhGxwwf5EZyIB3b9JVu4bEDydJWYQDUT/iTzgQpSZQg5aGQ6jFJMpgECQQD8bwMDGFUXYp5fD9dAsAf0XkJ5DsKnGoSSIAcs7Ys6m9Dpo33Q4tfKC8OLfx67OPZisZd5MgyapEK484Y3z+TVAkEAxJar4403vTtMgQAli4+iYNiltY+V1RHRiAN5+1E7N2vc4g66NvI8EiomqXqmjY01uyCRJLlZyO8LpN0ONFfEIQJBALWuMDzKBnQORm2kuQeVqiP2s2DtfqtGKqQA6SkszkggXPvK74KnwSdp0BNWKogVNz9REfPoUan7DwqOOstwlQECQExmujrfYTA74YmpAu5wTg0RZaVgPjzmheY0Y63Wbgsl8lwwmRJNpibxFsF7F0uf+6fUClSZbFl4/a9+8cxJ58ECQGkdj1rBuLjqOG/1I/mgiKno4M7+SYDhkBX171kKWOrQwoSYSrMTOnhTC249VMIEsnjjY59Tfuj+ebpA2y4SlVA=
12-01 08:49:09.559 16713-16713/com.rsa.test I/System.out: --------------私钥加密公钥解密过程-------------------
12-01 08:49:09.561 16713-16713/com.rsa.test E/privateKeyStr: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMHZkNirJD/dZ2xr4T5C9CQHWS6eXvPFd7MPBoclNCg4Y0JIkUYbyswdNuWu84iWbIeBcY1sUDhRZmtvNZQcSHPMc7cvTzy0X5niHxMQIvUMMcsAuCbynbS1TNH+oxoh946yHo30PUixD0/XRImUdXzD5IKsHQna+H+bvdBlYpN1AgMBAAECgYEAo6QiXoW6yB8DW8eGEaU7q954Lp6K0YZ1Ebcxb4y8hudzA1V3LZPwknZnDWWvODKj05A2Z4hz/9bXewIaXLmzfnKfpGaSuGFPg4ldaxJMIZpuGGP8XQonkhGxwwf5EZyIB3b9JVu4bEDydJWYQDUT/iTzgQpSZQg5aGQ6jFJMpgECQQD8bwMDGFUXYp5fD9dAsAf0XkJ5DsKnGoSSIAcs7Ys6m9Dpo33Q4tfKC8OLfx67OPZisZd5MgyapEK484Y3z+TVAkEAxJar4403vTtMgQAli4+iYNiltY+V1RHRiAN5+1E7N2vc4g66NvI8EiomqXqmjY01uyCRJLlZyO8LpN0ONFfEIQJBALWuMDzKBnQORm2kuQeVqiP2s2DtfqtGKqQA6SkszkggXPvK74KnwSdp0BNWKogVNz9REfPoUan7DwqOOstwlQECQExmujrfYTA74YmpAu5wTg0RZaVgPjzmheY0Y63Wbgsl8lwwmRJNpibxFsF7F0uf+6fUClSZbFl4/a9+8cxJ58ECQGkdj1rBuLjqOG/1I/mgiKno4M7+SYDhkBX171kKWOrQwoSYSrMTOnhTC249VMIEsnjjY59Tfuj+ebpA2y4SlVA=
12-01 08:49:09.573 16713-16713/com.rsa.test E/publicKeyStr: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDB2ZDYqyQ/3Wdsa+E+QvQkB1kunl7zxXezDwaHJTQoOGNCSJFGG8rMHTblrvOIlmyHgXGNbFA4UWZrbzWUHEhzzHO3L088tF+Z4h8TECL1DDHLALgm8p20tUzR/qMaIfeOsh6N9D1IsQ9P10SJlHV8w+SCrB0J2vh/m73QZWKTdQIDAQAB
12-01 08:49:09.574 16713-16713/com.rsa.test I/System.out: 原文:ihep_私钥加密公钥解密
12-01 08:49:09.574 16713-16713/com.rsa.test I/System.out: 加密:k1u/ChmolNypfIlVRu+uuc8Qayf5I9cj9ufONBAxl4agonPfjtxxyYRvwNPPFQMPWMAd2rpVwzvSvzHWIJpOiqnppdj+xkJHyr8JQVLaYZDEGc8jck9YPMoJsdDvnOCwLN19b8XoP2nt1fCeNZPVJ2HDzlBWcO29kc2cE5HRlf4=
12-01 08:49:09.574 16713-16713/com.rsa.test I/System.out: 解密:ihep_私钥加密公钥解密

2.3.3签名和校验

12-01 08:52:45.241 18864-18884/com.rsa.test E/publicKeyString: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFxtoFjoWHyyf4QV6NiMxv3GPQALNVgn0NKO+7iREU6OBRTmmYlMainC6HJcIoh1B2AgVGZkuJg2RoFKsd2WzndHDVR/vOwPAIH4cOaYIsEE7WDxW90BlJ0GT9A2kgfZED7TvUQjmSeF4eGU1KiwEeMMGrYC6AnRTzXWUhHkrbbwIDAQAB
12-01 08:52:45.241 18864-18884/com.rsa.test E/privateKeyString: MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMXG2gWOhYfLJ/hBXo2IzG/cY9AAs1WCfQ0o77uJERTo4FFOaZiUxqKcLoclwiiHUHYCBUZmS4mDZGgUqx3ZbOd0cNVH+87A8Agfhw5pgiwQTtYPFb3QGUnQZP0DaSB9kQPtO9RCOZJ4Xh4ZTUqLAR4wwatgLoCdFPNdZSEeSttvAgMBAAECgYBe264sJhxjcgwcpPW9upQbPsBcvklFRQ3HZw/8iZQ4zCzyskIxXYIb8f7a8UA7ghMUVonDJ0MplGxvAyLDcUoqq6opde7wFkHyidoikJOFGt3DNk8OYM5sZPpoMgWhbiZ/rqijnrV6sepPEgnKdVW1HGQvLDJOEil5gjOSlFdGAQJBAP2Rjoa2Mo/PiUCDZFNySJ4BimFOvvtE6ou4V73arxcRBHPTIPgRz1JT482784pWO6AI8Y4J3RA4eWtV8jyLTQECQQDHrFdDQHZ3Q/MNI1/7xYRqYwH45fJEDML99YDOX8GRC+LL/27TZwH4duGLOYpJSfjng1fubKYODMhtPcU1zHhvAkB/ArjMe1jKNh8+xFGthrIfCxCAe0woWjXNtJGmlHJdcHW1eoyqFWmuiDy0Ia/0nAsTt0cfaYtkg5U2EX/bmb8BAkB3iDthHjkNItdguRmfvlmL2qN2nimPBVjB8XNfmEFnlIb7+nkdAyBR3tEcqKCZSThBWAaOy+oIpSxjAUSK9VHvAkAODwbyfKDYZlH6P4BNs6UUKr1kuZPewlTZuMv0eHNT4CAdazSUl/mFdfaGA4Dsjy/cHInicMEv8yKp/NPojWO/
12-01 08:52:45.244 18864-18864/com.rsa.test I/System.out: ---------------私钥签名过程------------------
12-01 08:52:45.245 18864-18864/com.rsa.test E/privateKeyStr: MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAMXG2gWOhYfLJ/hBXo2IzG/cY9AAs1WCfQ0o77uJERTo4FFOaZiUxqKcLoclwiiHUHYCBUZmS4mDZGgUqx3ZbOd0cNVH+87A8Agfhw5pgiwQTtYPFb3QGUnQZP0DaSB9kQPtO9RCOZJ4Xh4ZTUqLAR4wwatgLoCdFPNdZSEeSttvAgMBAAECgYBe264sJhxjcgwcpPW9upQbPsBcvklFRQ3HZw/8iZQ4zCzyskIxXYIb8f7a8UA7ghMUVonDJ0MplGxvAyLDcUoqq6opde7wFkHyidoikJOFGt3DNk8OYM5sZPpoMgWhbiZ/rqijnrV6sepPEgnKdVW1HGQvLDJOEil5gjOSlFdGAQJBAP2Rjoa2Mo/PiUCDZFNySJ4BimFOvvtE6ou4V73arxcRBHPTIPgRz1JT482784pWO6AI8Y4J3RA4eWtV8jyLTQECQQDHrFdDQHZ3Q/MNI1/7xYRqYwH45fJEDML99YDOX8GRC+LL/27TZwH4duGLOYpJSfjng1fubKYODMhtPcU1zHhvAkB/ArjMe1jKNh8+xFGthrIfCxCAe0woWjXNtJGmlHJdcHW1eoyqFWmuiDy0Ia/0nAsTt0cfaYtkg5U2EX/bmb8BAkB3iDthHjkNItdguRmfvlmL2qN2nimPBVjB8XNfmEFnlIb7+nkdAyBR3tEcqKCZSThBWAaOy+oIpSxjAUSK9VHvAkAODwbyfKDYZlH6P4BNs6UUKr1kuZPewlTZuMv0eHNT4CAdazSUl/mFdfaGA4Dsjy/cHInicMEv8yKp/NPojWO/
12-01 08:52:45.253 18864-18864/com.rsa.test I/System.out: 签名原串:ihep_这是用于签名的原始数据
12-01 08:52:45.253 18864-18864/com.rsa.test I/System.out: 签名串:ElHOMjGFvtc500wRpgtFR+i9F63A+G3vh10cwU4EEyNsy0S18O5qYpvv/mWJ+1KvQNd5dY9DNkiBnklhcbFIVbxE4goJfNEHLd1hhVGhytE0ze4QeRsVHnTDA0mXsHuArY8RLYWoDJ96RXoa6VEvpJr6+DUlJ2dPhOqkHehRCIg=
12-01 08:52:45.254 18864-18864/com.rsa.test I/System.out: ---------------公钥校验签名------------------
12-01 08:52:45.254 18864-18864/com.rsa.test I/System.out: 签名原串:ihep_这是用于签名的原始数据
12-01 08:52:45.254 18864-18864/com.rsa.test I/System.out: 签名串:ElHOMjGFvtc500wRpgtFR+i9F63A+G3vh10cwU4EEyNsy0S18O5qYpvv/mWJ+1KvQNd5dY9DNkiBnklhcbFIVbxE4goJfNEHLd1hhVGhytE0ze4QeRsVHnTDA0mXsHuArY8RLYWoDJ96RXoa6VEvpJr6+DUlJ2dPhOqkHehRCIg=
12-01 08:52:45.255 18864-18864/com.rsa.test E/publicKeyStr: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFxtoFjoWHyyf4QV6NiMxv3GPQALNVgn0NKO+7iREU6OBRTmmYlMainC6HJcIoh1B2AgVGZkuJg2RoFKsd2WzndHDVR/vOwPAIH4cOaYIsEE7WDxW90BlJ0GT9A2kgfZED7TvUQjmSeF4eGU1KiwEeMMGrYC6AnRTzXWUhHkrbbwIDAQAB
12-01 08:52:45.256 18864-18864/com.rsa.test I/System.out: 验签结果:true

RSA非对称加密(以Android和java为例)相关推荐

  1. java rsa 117_java实现RSA非对称加密解密

    之前写过一篇java实现AES对称加密解密 在对密码加密传输的场景下 RSA非对称加密解密可能会更加适合. 原理就是后台生成一对公钥和私钥,公钥给前端用来加密,后台用私钥去解密,保证了传输过程中就算被 ...

  2. java RSA非对称加密详解

    简介 RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.1987年首次公布,当 ...

  3. java集成RSA非对称加密数据传输

    使用场景: 前端请求后端接口时如:登录接口,这时候需要传账号密码到后端接口请求这样就会暴露请求的数据.RSA非对称加密分公钥和私钥,公钥将数据进行加密,私钥对加密的数据进行解密 (当然前端最好是封装一 ...

  4. 数据加密 RSA非对称加密篇

    先把代码贴上来,理论后续补充,暂时可先参考数据加密 总篇 package com.jlpay.partner.utils;import android.util.Base64;import java. ...

  5. JSON 接口如何实现 RSA 非对称加密与签名

    代码地址如下: http://www.demodashi.com/demo/14000.html 一.概述 1. 数字签名的作用:保证数据完整性,机密性和发送方角色的不可抵赖性,加密与签字结合时,两套 ...

  6. 前后端数据加密传输 RSA非对称加密

    任务需求:要求登陆时将密码加密之后再进行传输到后端. 经过半天查询摸索折腾,于是有了如下成果: 加密方式:RSA非对称加密. 实现方式:公钥加密,私钥解密. 研究进度:javascript与java端 ...

  7. Springboot+RSA非对称加密

    这是百度百科对(对称加密丶非对称加密)的解释: (1)对称加密算法在加密和解密时使用的是同一个秘钥. (2)非对称加密算法需要两个密钥来进行加密和解密,这两个秘钥是公开密钥(public key,简称 ...

  8. 微信小程序RSA非对称加密。

    因公司做的产品为金融项目,所以对数据安全性有很高要求,因为项目中的数据都会通过3DES 对称加密,和RSA非对称加密进行数据传输. 在这里先简单介绍一下什么是对称加密和非对称加密 对称加密:对称加密采 ...

  9. RSA非对称加密和解密(同时生成密钥)

    RSA非对称加密和解密(同时生成密钥) 准备jar包 bcprov-jdk16-1.46.jar commons-codec-1.15.jar 获取jar地址:https://mvnrepositor ...

  10. 加密算法---RSA 非对称加密原理及使用

    加密算法---RSA 非对称加密原理及使用 一 非对称加密原理介绍 二 加密解密测试 2.1 加密解密工具类 2.2 测试 一 非对称加密原理介绍 非对称加密算法中,有两个密钥:公钥和私钥.它们是一对 ...

最新文章

  1. hashmap 扩容是元素还是数组_HashMap的扩容机制---resize()
  2. (0024)iOS 开发之MJExtension可能遇到全部问题
  3. VS 2010 使用项目 无法链接 DLL文件的问题
  4. mysql数据库1067错误
  5. TI Davinci DM6446开发攻略——开发环境搭建
  6. 自适应登陆html5,html5验证自适应
  7. 前端学习(711):数组导读
  8. 解决pip下载速度太慢
  9. python批量创建txt文件
  10. C#读取xml节点数据方法小结
  11. initialize
  12. 超弦计算机,物理学四大神兽——拉普拉斯妖
  13. iOS-苹果应用商店审核指南中文翻译
  14. 2022内蒙古最新建筑施工塔式起重机(建筑特种作业)模拟考试题库及答案
  15. 小程序开发API之mDNS
  16. Valley Numer II(状压dp)
  17. [企业管理]宽容与尊严
  18. python乘法符号手写_利用Python自动生成小学生加减乘除口算考试题卷,不再为手写算术题烦恼!...
  19. 蔬菜类别二级计算机,国家标准:蔬菜分类.doc
  20. linux下c使用lzma_使用 LZMA SDK

热门文章

  1. 久等了,铁威马TOS 5内测招募来了
  2. 佟年计算机天才不会打游戏,亲爱的热爱的:Gun神带佟年开黑,网友:甜蜜游戏时间...
  3. Android 11获取应用列表 android.permission.QUERY_ALL_PACKAGES
  4. 国外博士后申请前有哪些准备工作
  5. 为Electron 打包后的桌面程序添加自定义向导
  6. win10 uwp 打开文件管理器选择文件
  7. WebRTC帧率调整策略
  8. 易语言群控雷电_奇易安卓模拟器/真机免ROOT群控自带V8脚本开发引擎
  9. 手机群控系统(补充篇)
  10. OPTEE学习笔记 - AArch64 RPC(一)