1、简单的加密(凯撒密码)
基本思想是:通过把字母移动一定的位数来实现加密和解密。明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是 3 的时候,所有的字母 A 将被替换成 D,B 变成 E,由此可见,位数就是凯撒密码加密和解密的密钥。
static int key = 6;
/**
* 加密
*/
private static String encrypt(String originalText, int key) {
// 把所有的字符向右移
char[] cs = originalText.toCharArray();
for (int i = 0; i < cs.length; i++) {
// 转化成asci码
int asci = cs[i];
char newChar = (char) (asci + key);
cs[i] = newChar;
}
return new String(cs);
}
/**
* 解密
*/
private static String decrypt(String originalText, int key) {
// 把所有的字符向左移
char[] cs = originalText.toCharArray();
for (int i = 0; i < cs.length; i++) {
// 转化成asci码
int asci = cs[i];
char newChar = (char) (asci - key);
cs[i] = newChar;
}
return new String(cs);
}
String originalText = "Hello World";
String encrypt = encrypt(originalText,key);
System.out.println("加密后:"+encrypt);
String decrypt = decrypt(encrypt, key);
System.out.println("解密后:"+decrypt);
结果:
2、对称加密
加密和解密都使用同一把秘钥,这种加密方法称为对称加密,也称为单密钥加密。
对称加密常用算法:AES、DES、3DES、TDEA、Blowfish、RC2、RC4、RC5、IDEA、SKIPJACK 等。
DES加密:
String originalText = "Hello World";
// 创建一个加密器
Cipher cipher = null;
try {
cipher = Cipher.getInstance("DES");
Key key = KeyGenerator.getInstance("DES").generateKey();
// 设置加密器是解密还是加密
cipher.init(Cipher.ENCRYPT_MODE, key);
// 加密方法
byte[] encrypt = cipher.doFinal(originalText.getBytes());
System.out.println("加密后:" + new String(encrypt));
// 解密
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypt = cipher.doFinal(encrypt);
System.out.println("解密后:" + new String(decrypt));
} catch (Exception e) {
e.printStackTrace();
}
结果:
但是此时key值一直在变化,相同内容,每次加密的结果不一样,处理办法是可以保存唯一使用同一个key值。
DES自定义key
private static String ALGORITHM = "DES";
static String textKey = "123456787777";// des密钥的长度是64位,其中56位参数加密,8位做校验,如果密钥长度大于64,64位后的字符都不无效的
String originalText = "Hello World";
// 生成加密器
Cipher cipher = Cipher.getInstance(ALGORITHM);
DESKeySpec keySpec = new DESKeySpec(textKey.getBytes());
// 密钥工厂
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
Key key = keyFactory.generateSecret(keySpec);
// 设置操作模式
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypt = cipher.doFinal(originalText.getBytes());
// 解密
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypt = cipher.doFinal(encrypt);
System.out.println(new String(decrypt));
AES自定义key
private static String KEY_ALGORITHM = "AES";
private static String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";//算法/工作模式/填充模式
static String textKey = "1234567812345678";// aes密钥的长度是128位
String originalText = "Hello World";
//加密
String encrypt = encrypt(originalText, textKey);
System.out.println("加密后:"+encrypt);
String decrypt = decrypt(encrypt, textKey);
System.out.println("解密后:"+decrypt);
private static String encrypt(String text,String key){
String encryptStr = null;
try {
//获取加密器
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//获取自定义的key
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), KEY_ALGORITHM);
//初始化操作模式
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
//加密后字节数组
byte[] encrypt = cipher.doFinal(text.getBytes());
//这个地方不能直接创建字符串返回
//encryptStr = new String(encrypt);
//用Base64编码一下
encryptStr = Base64.encode(encrypt);
} catch (Exception e) {
e.printStackTrace();
}
return encryptStr;
}
private static String decrypt(String text,String key){
String encryptStr = null;
try {
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), KEY_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
//Base64解码一下
byte[] decode = Base64.decode(text);
//解密
byte[] encrypt = cipher.doFinal(decode);
encryptStr = new String(encrypt);
} catch (Exception e) {
e.printStackTrace();
}
return encryptStr;
}
3、非对称加密
非对称加密算法需要两个密钥:公钥(publickey)和私钥(privatekey)。公钥与私钥是一对,如果用公钥对数据进行加密,只有用对应的私钥才能解密;如果用私钥对数据进行加密,那么只有用对应的公钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
简单理解为:加密和解密是不同的钥匙
常见算法:RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)等。
RSA加密解密:
private static String algorithm = "RSA";// 公钥加密私钥解密,私钥加密公钥解密
private static int ENCRYPT_LENTH = 117;// 加密时数据长度不能超过117
private static int DECRYPT_LENTH = 128;// 解密时数据长度不能超过128
String originalText = "Hello World Hello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello WorldHello World";
// 生成公钥和私钥,密钥不能够自定义
// 密钥对生成器
KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance(algorithm);
// 生成密钥对
KeyPair keyPair = pairGenerator.genKeyPair();
// 获取公钥
PublicKey publicKey = keyPair.getPublic();
// 获取私钥
PrivateKey privateKey = keyPair.getPrivate();
// 公钥加密
// 生成加密器
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] bytes = originalText.getBytes();
//分块加解密
byte[] encrypt = doCrypt(cipher, bytes,ENCRYPT_LENTH);
// 私钥解密
cipher.init(Cipher.DECRYPT_MODE, privateKey);
//byte[] decrypt = cipher.doFinal(encrypt);
byte[] decrypt = doCrypt(cipher, encrypt,DECRYPT_LENTH);
System.out.println(new String(decrypt));
private static byte[] doCrypt(Cipher cipher, byte[] bytes,int cryptLength)throws IllegalBlockSizeException, BadPaddingException, IOException {
int length = bytes.length;// 200
int offSet = 0;
byte[] tmp = null;
//字节数组的拼接
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((length - offSet) > 0) {
//分块加密
if (length - offSet >= cryptLength) {
tmp = cipher.doFinal(bytes, offSet, cryptLength);
}else{
tmp = cipher.doFinal(bytes, offSet, length - offSet);
}
offSet += cryptLength;
bos.write(tmp);
}
//加密后的字节数组
byte[] encrypt = bos.toByteArray();
return encrypt;
}
4、消息摘要
常见算法MD5、SHA、CRC 等。
String text = "Hello World";
//MD5,SHA
MessageDigest digest = MessageDigest.getInstance("MD5");
//消息摘要的字节数组
byte[] msg = digest.digest(text.getBytes());
//将数组转化字符
String msgText = Hex.encode(msg);
System.out.println(msgText);
//b10a8db164e0754105b7a99be72e3fe5 MD5
//0a4d55a8d778e5022fab701977c5d840bbc486d0 SHA
MD5一种数据摘要算法, 可以将任何文件或者字符串,加密成为一个32位长度的特征码, 数字指纹, 数字摘要(秒传),不可逆, 无法通过md5还原文件或字符串
MD5破解: 通过海量数据库进行暴力破解
数字签名是非对称加密与数字摘要的组合应用。
//私钥加密(签名),用我的公钥能解开,说明这确实是我签名
//MD2withRSA MD5withRSA SHA1withRSA
String text = "我借了你100W";//先对原文进行MD5,再对MD5后的结果进行RSA加密
Signature signature = Signature.getInstance("MD5withRSA");
// 密钥对生成器
KeyPairGenerator pairGenerator = KeyPairGenerator.getInstance("RSA");
// 生成密钥对
KeyPair keyPair = pairGenerator.genKeyPair();
// 获取公钥
PublicKey publicKey = keyPair.getPublic();
// 获取私钥
PrivateKey privateKey = keyPair.getPrivate();
//签名
signature.initSign(privateKey);
//输入原文
signature.update(text.getBytes());
//进行签名
byte[] sign = signature.sign();
//验证签名
signature.initVerify(publicKey);
//输入原文
signature.update(text.getBytes());
//验签
boolean verify = signature.verify(sign);
System.out.println(verify);
6、Https
SSLContext context = SSLContext.getInstance("SSL");//SSL TLS
//信任管理器数组
TrustManager[] tm = new TrustManager[]{
new EmptyTrustManager()
};
//初始化SSL上下文
context.init(null, tm, null);
String urlStr = "https://kyfw.12306.cn/otn/";
//设置信任管理器,需要在连接前就设置好
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
URL url = new URL(urlStr);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
//获取流对象
InputStream is = connection.getInputStream();
String str = Util.inputStream2String(is);
System.out.println(str);
static class EmptyTrustManager implements X509TrustManager{
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
}
SSLContext context = SSLContext.getInstance("SSL");//SSL TLS
//导入证书
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(new File("srca.cer")));
//创建密钥库
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
//初始化密钥库
keyStore.load(null);
//将证书放入密钥库
keyStore.setCertificateEntry("srca", certificate);
//信任管理器的工厂
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
//将密钥库放入密钥工厂中
trustManagerFactory.init(keyStore);
//获取信任管理器数组
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
//初始化SSL上下文
context.init(null, trustManagers, null);
String urlStr = "https://kyfw.12306.cn/otn/";
//设置信任管理器,需要在连接前就设置好
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
URL url = new URL(urlStr);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
//获取流对象
InputStream is = connection.getInputStream();
String str = Util.inputStream2String(is);
System.out.println(str);
Util
public class Util {
//https://kyfw.12306.cn/otn/
// 英文里出现次数最多的字符
private static final char MAGIC_CHAR = 'e';
// 破解生成的最大文件数
private static final int DE_MAX_FILE = 4;
public static String file2String(String path) throws IOException {
FileReader reader = new FileReader(new File(path));
char[] buffer = new char[1024];
int len = -1;
StringBuffer sb = new StringBuffer();
while ((len = reader.read(buffer)) != -1) {
sb.append(buffer, 0, len);
}
return sb.toString();
}
public static void string2File(String data, String path) {
FileWriter writer = null;
try {
writer = new FileWriter(new File(path));
writer.write(data);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static String inputStream2String(InputStream in) throws IOException {
int len = -1;
byte[] buffer = new byte[1024];
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len = in.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
baos.close();
return baos.toString("UTF-8");
}
public static void printCharCount(String path) throws IOException {
String data = Util.file2String(path);
List<Entry<Character, Integer>> mapList = getMaxCountChar(data);
for (Entry<Character, Integer> entry : mapList) {
// 输出前几位的统计信息
System.out.println("字符'" + entry.getKey() + "'出现"
+ entry.getValue() + "次");
}
}
public static void encryptFile(String srcFile, String destFile, int key)
throws IOException {
String artile = Util.file2String(srcFile);
// 加密文件
String encryptData = encrypt(artile, key);
// 保存加密后的文件
Util.string2File(encryptData, destFile);
}
public static void decryptCaesarCode(String input, String destPath) {
int deCount = 0;// 当前解密生成的备选文件数
// 获取出现频率最高的字符信息(出现次数越多越靠前)
List<Entry<Character, Integer>> mapList = getMaxCountChar(input);
for (Entry<Character, Integer> entry : mapList) {
// 限制解密文件备选数
if (deCount >= DE_MAX_FILE) {
break;
}
// 输出前几位的统计信息
System.out.println("字符'" + entry.getKey() + "'出现"
+ entry.getValue() + "次");
++deCount;
// 出现次数最高的字符跟MAGIC_CHAR的偏移量即为秘钥
int key = entry.getKey() - MAGIC_CHAR;
System.out.println("猜测key = " + key + ", 解密生成第" + deCount + "个备选文件"
+ "\n");
String decrypt = decrypt(input, key);
String fileName = "de_" + deCount + destPath;
Util.string2File(decrypt, fileName);
}
}
// 统计String里出现最多的字符
public static List<Entry<Character, Integer>> getMaxCountChar(String data) {
Map<Character, Integer> map = new HashMap<Character, Integer>();
char[] array = data.toCharArray();
for (char c : array) {
if (!map.containsKey(c)) {
map.put(c, 1);
} else {
Integer count = map.get(c);
map.put(c, count + 1);
}
}
// 获取获取最大值
int maxCount = 0;
for (Entry<Character, Integer> entry : map.entrySet()) {
// 不统计空格
if (/* entry.getKey() != ' ' && */entry.getValue() > maxCount) {
maxCount = entry.getValue();
}
}
// map转换成list便于排序
List<Entry<Character, Integer>> mapList = new ArrayList<Map.Entry<Character, Integer>>(
map.entrySet());
// 根据字符出现次数排序
Collections.sort(mapList, new Comparator<Entry<Character, Integer>>() {
@Override
public int compare(Entry<Character, Integer> o1,
Entry<Character, Integer> o2) {
return o2.getValue().compareTo(o1.getValue());
}
});
return mapList;
}
public static String encrypt(String input, int key) {
char[] array = input.toCharArray();
for (int i = 0; i < array.length; i++) {
// 字符转为acsii码值
int ascii = array[i];
// 字符偏移
ascii = ascii + key;
// ascii码值转换为对应字符
char newChar = (char) ascii;
// 替换原有字符
array[i] = newChar;
// 以上4行代码可以简写为一行
// array[i] = (char) (array[i] + 1);
}
return new String(array);
}
public static String decrypt(String input, int key) {
char[] array = input.toCharArray();
for (int i = 0; i < array.length; i++) {
// 字符转为acsii码值
int ascii = array[i];
// 字符偏移
ascii = ascii - key;
// ascii码值转换为对应字符
char newChar = (char) ascii;
// 替换原有字符
array[i] = newChar;
// 以上4行代码可以简写为一行
// array[i] = (char) (array[i] + 1);
}
return new String(array);
}
}
Android里的https请求:
把scra.cer文件考到assets或raw目录下,或者直接使用证书的RFC格式,接下来的做法和java工程代码一样。
Base64
import java.io.*;
public class Base64 {
private static char[] base64EncodeChars = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/' };
private static byte[] base64DecodeChars = new byte[] {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 };
public static String encode(byte[] data) {
StringBuffer sb = new StringBuffer();
int len = data.length;
int i = 0;
int b1, b2, b3;
while (i < len) {
b1 = data[i++] & 0xff;
if (i == len)
{
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
sb.append("==");
break;
}
b2 = data[i++] & 0xff;
if (i == len)
{
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
sb.append("=");
break;
}
b3 = data[i++] & 0xff;
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
sb.append(base64EncodeChars[b3 & 0x3f]);
}
return sb.toString();
}
public static byte[] decode(String str) throws UnsupportedEncodingException {
StringBuffer sb = new StringBuffer();
byte[] data = str.getBytes("US-ASCII");
int len = data.length;
int i = 0;
int b1, b2, b3, b4;
while (i < len) {
/* b1 */
do {
b1 = base64DecodeChars[data[i++]];
} while (i < len && b1 == -1);
if (b1 == -1) break;
/* b2 */
do {
b2 = base64DecodeChars[data[i++]];
} while (i < len && b2 == -1);
if (b2 == -1) break;
sb.append((char)((b1 << 2) | ((b2 & 0x30) >>> 4)));
/* b3 */
do {
b3 = data[i++];
if (b3 == 61) return sb.toString().getBytes("ISO-8859-1");
b3 = base64DecodeChars[b3];
} while (i < len && b3 == -1);
if (b3 == -1) break;
sb.append((char)(((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));
/* b4 */
do {
b4 = data[i++];
if (b4 == 61) return sb.toString().getBytes("ISO-8859-1");
b4 = base64DecodeChars[b4];
} while (i < len && b4 == -1);
if (b4 == -1) break;
sb.append((char)(((b3 & 0x03) << 6) | b4));
}
return sb.toString().getBytes("ISO-8859-1");
}
}
Hex/**
* 字节数组与16进制字符串转换工具
*/
public class Hex {
private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
/**
* 字节数组转换成16进制字符串
*
* @param bytes
* @return
*/
public static String encode(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return null;
}
StringBuffer sb = new StringBuffer(bytes.length * 2);
// 27对应的十六进制为1b,对应的二进制是00011011
// 取高位和低位:00011011-》0001,1011-》1,b
for (int i = 0; i < bytes.length; ++i) {
// 取高位:跟0xf0做与运算后再右移4位
int high = (bytes[i] & 0xf0) >> 4;// 0xf0: 11110000
// 取低位:跟0x0f做与运算
int low = bytes[i] & 0x0f;// 0x0f: 00001111
// 字符映射
sb.append(HEX_CHAR[high]).append(HEX_CHAR[low]);
}
return sb.toString();
}
/**
* 16进制字符串转换为字节数组
*
* @param hex
* 16进制字符
* @return
*/
public static byte[] decode(String hex) {
if (hex == null || hex.length() == 0) {
return null;
}
// 16进制转byte,长度减半,"1b"-->27
int len = hex.length() / 2;
byte[] result = new byte[len];
String highStr = null;
String lowStr = null;
int high = 0;
int low = 0;
for (int i = 0; i < len; i++) {
// 高位值
highStr = hex.substring(i * 2, i * 2 + 1);// "1b"的高位为"1"
high = Integer.parseInt(highStr, 16);// 高位转为10进制
// 低位值
lowStr = hex.substring(i * 2 + 1, i * 2 + 2);// "1b"的低位为"b"
low = Integer.parseInt(lowStr, 16);// 低位转为10进制
// 合计值
result[i] = (byte) ((high << 4) + low);// 相当于:(高位*16) + 低位
}
return result;
}
}