基本概念
密码学的三大作用:加密( Encryption)、认证(Authentication),鉴定(Identification)
加密:
防止坏人获取你的数据
鉴权:
防止坏人假冒你的身份。
认证:
防止坏人修改了你的数据而你却并没有发现。
Base64编码
Base64编码算法是一种用64个字符(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)来表示任意二进制数据的方法。在加解密算法中,原始的数据和加密后的数据一般也是二进制数据,为了不传输出错,方便保存或者调试代码,一般需要对加密后的数据进行base64编码。
常用加密算法
对称加密算法(加解密密钥相同)
加解密速度快,适合大数据量的加解密处理,但是密钥管理困难,不适合互联网,一般用于内部系统
常见的有DES,3DES,AES,DES默认的是56位的加密密钥,已经不安全,不建议使用,推荐使用AES,Android 提供的AES加密算法API默认使用的是ECB模式,所以要显式指定加密算法为:CBC或CFB模式,可带上PKCS5Padding填充。AES密钥长度最少是128位,推荐使用256位。
try {
String a="abc";
//生成key
KeyGenerator keyGenerator=KeyGenerator.getInstance("AES");
keyGenerator.init(256);
//产生秘钥
SecretKey secretKey=keyGenerator.generateKey();
//获取秘钥
byte[] bytes=secretKey.getEncoded();
//还原秘钥
SecretKey key=new SecretKeySpec(bytes,"AES");
Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE,secretKey);
byte[] result=cipher.doFinal(a.getBytes());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
非对称加密(加密密钥和解密密钥不同)
密钥容易管理,速度慢,适合小数据量加解密或数据签名,非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密(这个过程可以做数字签名)。
非对称加密主要使用的是RSA算法。
生成密钥对:
public static KeyPair generateRSAKeyPair(int keyLength) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
kpg.initialize(keyLength);//密钥长度不要低于512位,建议使用2048位的密钥长度
return kpg.genKeyPair();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
公钥加密:
public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
// 得到公钥
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PublicKey keyPublic = kf.generatePublic(keySpec);
// 加密数据
Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
cp.init(Cipher.ENCRYPT_MODE, keyPublic);
return cp.doFinal(data);
}
私钥加密:
public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
// 得到私钥
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PrivateKey keyPrivate = kf.generatePrivate(keySpec);
// 数据加密
Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, keyPrivate);
return cipher.doFinal(data);
}
公钥解密:
public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
// 得到公钥
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PublicKey keyPublic = kf.generatePublic(keySpec);
// 数据解密
Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
cipher.init(Cipher.DECRYPT_MODE, keyPublic);
return cipher.doFinal(data);
}
私钥解密:
public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) throws Exception {
// 得到私钥
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PrivateKey keyPrivate = kf.generatePrivate(keySpec);
// 解密数据
Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
cp.init(Cipher.DECRYPT_MODE, keyPrivate);
byte[] arr = cp.doFinal(encrypted);
return arr;
}
注意:android系统的RSA实现是"RSA/None/NoPadding",而标准JDK实现是"RSA/None/PKCS1Padding" ,这造成了在android机上加密后无法在服务器上解密的原因,1024位key的最多只能加密127位数据,否则就会报错(javax.crypto.IllegalBlockSizeException: Data must not be longer than 117 bytes)
消息摘要
MD5加密全程是Message-Digest Algoorithm 5(信息-摘要算法),它对信息进行摘要采集,再通过一定的位运算,最终获取加密后的MD5字符串。
例如我们要加密一篇文章,那么我们会随机从每段话或者每行中获取一个字,把这些字统计出来后,再通过一定的运算获得一个固定长度的MD5加密后信息。因此,其很难被逆向破解。
Android端 AES+RSA结合实践
Android端
服务器端(server)分别生成自己的RSA密钥对,并提供接口给Android客户端获取RSA公钥(rsaPublicKey)
client生成AES密钥(aesKey)
client使用自己的AES密钥(aesKey)对转换为json格式的请求明文数据(data)进行加密,得到加密后的请求数据encryptData
client提供server提供的接口获取RSA公钥(rsaPublicKey)
client使用获取RSA公钥(rsaPublicKey)对AES密钥(aesKey)进行加密,得到encryptAesKey
client将encryptAesKey作为http请求头参数,将加密后的请求数据encryptData作为请求体一起传输给服务器端
服务器端
server响应client的http请求,读取http请求头。获得client传过来的加密后的AES密钥(encryptAesKey),读取http请求体,获得client传过来的加密后的请求数据(encryptData)。
server使用自己的RSA私钥(rsaPrivateKey)对加密后的AES密钥(encryptAesKey)进行RSA解密,得到AES密钥(aesKey)
使用解密后的AES密钥(aesKey)对加密后的请求数据(encryptData),进行AES解密操作,得到解密后的请求数据(data),该数据为json格式
对解密后的请求数据(data)进行json解析,然后做相关的响应操作。