Enctypt()
这个函数很关键,一般来说加密方法里面都会有这个单词
加密是通过某种算法将原本的数据内容加密为特殊的参数
,网上也有很多自称是可以破解MD5
密码的网站,其原理也是一样,就是有一个巨大的资源库,存放了许多字符串及对应的MD5
加密后的字符串,通过你输入的MD5
加密串来进行比较,如果过你的密码复杂度比较低,还是有很大机率验证出来的
加密方式
Md5加密: 通过md5加密会生成一个16位或者32位的加密参数 特征: 16位或32位 不可逆
对称加密DES/AES两个: 就是加密和解密用的是同一把钥匙 特征: 秘加密解密钥匙唯一 可逆
非对称加密RSA: 有加密公匙和解密私匙 特征: 加密解密钥匙不唯一 可逆
Base64伪加密: 将数据以另外一种编码方式呈现 特征: 表示真正的加密算法 可逆
MD5 (不可逆向需要Key)
MD5.js
是通过前台js
加密的方式对用户信息,密码等私密信息进行加密处理的工具,也可称为插件
MD5共有6种加密方法:
hex_md5(value)
b64_md5(value)
str_md5(value)
HMAC
消息认证码,就是最后加密完成的数据
hex_hmac_md5(key, data)
b64_hmac_md5(key, data)
str_hmac_md5(key, data)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./md5.js"></script>>
</head>
<body>
<p>你好世界</p>
<script>
var code = "123456";
var username = "123456";
var password = "123456";
var str1 = hex_md5("123456");
var str2 = b64_md5("123456");
var str3 = str_md5("123456");
var str4 = hex_hmac_md5(code,code);
var str5 = b64_hmac_md5(username,username);
var str6 = str_hmac_md5(password,password);
console.log(str1); // e10adc3949ba59abbe56e057f20f883e
console.log(str2); // 4QrcOUm6Wau+VuBX8g+IPg
console.log(str3); // áÜ9IºY«¾VàWò��
console.log(str4); // 30ce71a73bdd908c3955a90e8f7429ef
console.log(str5); // MM5xpzvdkIw5VakOj3Qp7w
console.log(str6); // 0Îq§;Ý��9U©��t)ï
</script>
</body>
</html>
判断方式
- 密文一般为 16 位或者 32 位,其中 16 位是取的 32 位第 9~25 位的值;
- 组成方式为字母
(a-f)
和数字(0-9)混合,字母可以全部是大写或者小写。
除了通过密文特征来判断以外,我们还可以搜索源代码,标准 MD5
的源码里是包含了一些特定的值的,没有这些特定值,就无法实现 MD5:
0123456789ABCDEF
、0123456789abcdef
1732584193
、-271733879
、-1732584194
、271733878
PS:某些特殊情况下,密文的长度也有可能不止 16 位或者 32 位,有可能是在官方算法上有一些魔改,通常也是在 16 位的基础上,左右填充了一些随机字符串。
Base64编码转换 (可逆)
Base64 使用了 64 个可打印字符(A-Z、a-z、0-9、+、/)Base16 使用了 16 个可打印字符(A-F、0-9)
下列代码可以将普通的字符串通过方法转换为Base64编码的数字
<html>
<head>
<title>前端的base64使用方法</title>
</head>
<body>
</body>
<script>
var str = "hello";
var str64 = window.btoa("hello"); // 编码方法
console.log("字符串是:"+str);
console.log("经base64编码后:"+str64);
console.log("base64解码后:"+window.atob(str64)); // 解码方法
</script>
</html>
判断方式
Base编码系统特征如下
Base16:结尾没有等号,数字要多于字母;
Base32:字母要多于数字,明文数量超过 10 个,结尾可能会有很多等号;
Base58:结尾没有等号,字母要多于数字;
Base64:一般情况下结尾都会有 1 个或者 2 个等号,明文很少的时候可能没有;
Base85:等号一般出现在字符串中间,含有一些奇怪的字符;
Base100:密文由 Emoji 表情组成
sha1 (不可逆
哈希算法
SHA1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦数据处理标准(FIPS)。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。
SHA256是SHA2的一种,可产生256位的哈希值,较SHA1更加的安全
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>sha1</title>
<script src="https://cdn.bootcss.com/js-sha1/0.6.0/sha1.js"></script>
</head>
<body>
<p>sha1加解密</p>
<script type="text/javascript">
var sha1_1 = sha1("mosquito~");
console.log(sha1_1);
var sha1_2 = sha1("admin:1001");
console.log(sha1_2);
</script>
</body>
</html>
编码/解码字符串原生函数
使用JS函数的escape()
和unescape()
分别是编码和解码字符串
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>sha1</title>
</head>
<body>
<p>编码解码字符串</p>
<script type="text/javascript">
var escape1 =escape("我的名字是:mosquito~"); // 将里面的字符串编码
console.log(escape1);
var unescape1 = unescape(escape1); //解码 // 解码编码后的字符串
console.log(unescape1);
</script>
</script>
</body>
</html>
对称加密AES/DES 唯一 可逆需要key
对称加密算法只是为了区分非对称加密算法。其中鲜明的特点是对称加密是加密解密使用相同的密钥,而非对称加密加密和解密时使用的密钥不一样 对称就是相同的,不对称就是不唯一的 各有优点
使用场景
对于大部分情况我们都使用对称加密,而对称加密的密钥交换时使用非对称加密,这有效保护密钥的安全。非对称加密加密和解密密钥不同,那么它的安全性是无疑最高的,但是它加密解密的速度很慢,不适合对大数据加密。而对称加密加密速度快,因此混合使用最好
- AES:高级加密标准,新一代标准,加密速度更快,安全性更高(不用说优先选择)
- DES:比较老的算法,一共有三个参数入口(原文,密钥,加密模式)。而3DES只是DES的一种模式,是以DES为基础更安全的变形,对数据进行了三次加密,也是被指定为AES的过渡算法
AES的使用
AES密钥长度可以选择128位【16字节】,192位【24字节】和256位【32字节】密钥(其他不行,因此别乱设密码哦)
AES支持五种模式:CBC,CFB,ECB,OFB,PCBC,
ECB:是一种基础的加密方式,密文被分割成分组长度相等的块(不足补齐),然后单独一个个加密,一个个输出组成密文。
CBC:是一种循环模式,前一个分组的密文和当前分组的明文异或操作后再加密,这样做的目的是增强破解难度。
CFB/OFB实际上是一种反馈模式,目的也是增强破解的难度。
ECB和CBC的加密结果是不一样的,两者的模式不同,而且CBC会在第一个密码块运算时加入一个初始化向量
Java语言实现AES算法的加解密 :
键盘录入需要录入的规则是加密时使用的密钥,也就是加密规则。加密规则需要和解密时使用的密钥相同,否则无法正确解密。因此,加密规则和解密规则之间非常重要。在实际应用中,加密规则需要保密,只有知道加密规则的人才能正确解密**注意:**如果攻击者能够获取加密使用的密钥,就可以通过逆向分析得出加密的规则,从而破解加密。因此,在实际应用中,加密规则需要保密,只有知道加密规则的人才能正确解密。同时,还需要采取其他安全措施,如加密传输通道、使用安全的存储方式等,以保护加密数据的安全。
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Scanner;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class RSAUtil {
/*
* 加密 1.构造密钥生成器 2.根据ecnodeRules规则初始化密钥生成器 3.产生密钥 4.创建和初始化密码器 5.内容加密 6.返回字符串
*/
public static String AESEncode(String encodeRules, String content) {
try {
// 1.构造密钥生成器,指定为AES算法,不区分大小写
KeyGenerator keygen = KeyGenerator.getInstance("AES");
// 2.根据ecnodeRules规则初始化密钥生成器
// 生成一个128位的随机源,根据传入的字节数组
keygen.init(128, new SecureRandom(encodeRules.getBytes()));
// 3.产生原始对称密钥
SecretKey original_key = keygen.generateKey();
// 4.获得原始对称密钥的字节数组
byte[] raw = original_key.getEncoded();
// 5.根据字节数组生成AES密钥
SecretKey key = new SecretKeySpec(raw, "AES");
// 6.根据指定算法AES自成密码器
Cipher cipher = Cipher.getInstance("AES");
// 7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY
cipher.init(Cipher.ENCRYPT_MODE, key);
// 8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码
byte[] byte_encode = content.getBytes("utf-8");
// 9.根据密码器的初始化方式--加密:将数据加密
byte[] byte_AES = cipher.doFinal(byte_encode);
// 10.将加密后的数据转换为字符串
// 这里用Base64Encoder中会找不到包
// 解决办法:
// 在项目的Build path中先移除JRE System Library,再添加库JRE System
// Library,重新编译后就一切正常了。
String AES_encode = new String(new BASE64Encoder().encode(byte_AES));
// 11.将字符串返回
return AES_encode;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 如果有错就返加nulll
return null;
}
/*
* 解密 解密过程: 1.同加密1-4步 2.将加密后的字符串反纺成byte[]数组 3.将加密内容解密
*/
public static String AESDncode(String encodeRules, String content) {
try {
// 1.构造密钥生成器,指定为AES算法,不区分大小写
KeyGenerator keygen = KeyGenerator.getInstance("AES");
// 2.根据ecnodeRules规则初始化密钥生成器
// 生成一个128位的随机源,根据传入的字节数组
keygen.init(128, new SecureRandom(encodeRules.getBytes()));
// 3.产生原始对称密钥
SecretKey original_key = keygen.generateKey();
// 4.获得原始对称密钥的字节数组
byte[] raw = original_key.getEncoded();
// 5.根据字节数组生成AES密钥
SecretKey key = new SecretKeySpec(raw, "AES");
// 6.根据指定算法AES自成密码器
Cipher cipher = Cipher.getInstance("AES");
// 7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY
cipher.init(Cipher.DECRYPT_MODE, key);
// 8.将加密并编码后的内容解码成字节数组
byte[] byte_content = new BASE64Decoder().decodeBuffer(content);
/*
* 解密
*/
byte[] byte_decode = cipher.doFinal(byte_content);
String AES_decode = new String(byte_decode, "utf-8");
return AES_decode;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
// 如果有错就返加nulll
return null;
}
public static void main(String[] args) {
RSAUtil jm = new RSAUtil();
Scanner scanner = new Scanner(System.in);
/*
* 加密
*/
System.out.println("使用AES对称加密,请输入加密的规则");
String encodeRules = scanner.next();
System.out. println ("请输入要加密的内容:");
String content = scanner.next();
System.out.println("根据输入的规则" + encodeRules + "加密后的密文是:"
+ jm.AESEncode(encodeRules, content));
/*
* 解密
*/
System.out.println("使用AES对称解密,请输入加密的规则:(须与加密相同)");
encodeRules = scanner.next();
System.out.println("请输入要解密的内容(密文):");
content = scanner.next();
System.out.println("根据输入的规则" + encodeRules + "解密后的明文是:"
+ jm.AESDncode(encodeRules, content));
}
}
------------------------------------------------------
输出:
使用AES对称加密,请输入加密的规则
zhang
请输入要加密的内容:
123
根据输入的规则zhang加密后的密文是:JXHBwSB8AAspwb5k4YvExQ==
使用AES对称解密,请输入加密的规则:(须与加密相同)
zhang
请输入要解密的内容(密文):
JXHBwSB8AAspwb5k4YvExQ==
根据输入的规则zhang解密后的明文是:123
DES的使用
DES
是对称加密算法领域中的典型算法,其密钥默认长度为56
位
非对称RSA加密 不唯一 可逆
JS
中没有私钥是无法解密的,只能通过公钥去加密结果
非对称加密加密解密时使用的不同的密钥,分为公钥(public key)和私钥(private key).公钥可以公开,而私钥自己保存,通过公钥加密结果,必须私钥解密
由于非对称加密的密钥生成麻烦,所以无法做到一次一密,而且其加密速度很慢,无法对大量数据加密。因此最常用的使用场景就是数字签名和密码传输,用作数字签名时使用私钥加密,公钥解密;用作加密解密时,使用公钥加密,私钥解密
长度要求:
RSA加密是有长度限制的,1024位密钥可以加密128字节(1024位),不满128字节的使用随机数填充,但是RSA实现中必须要加随机数(11字节以上),所以明文长度最大为117字节,然后剩下的加入随机数。这也产生了每次加密结果每一次都不一样的特点
下方是 Java 实现该RSA算法,最底部字符串我们可以自行选择 ,先是生成密钥对,然后加密,再解密。需要注意的是这个方法是不能跨语言使用的,因为里面对公钥和私钥用到的序列化是java的序列化。 由于加密后的密文都是字节码形式的,我们要以字符串方式保存或传输的话,可以使用Base64编码
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import javax.crypto.Cipher;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
public class RSAUtil {
/** 指定加密算法为RSA */
private static String ALGORITHM = "RSA";
/*指定加密模式和填充方式*/
private static String ALGORITHM_MODEL = "RSA/ECB/PKCS1Padding";
/** 指定key的大小,一般为1024,越大安全性越高 */
private static int KEYSIZE = 1024;
/** 指定公钥存放文件 */
private static String PUBLIC_KEY_FILE = "PublicKey";
/** 指定私钥存放文件 */
private static String PRIVATE_KEY_FILE = "PrivateKey";
/**
* 生成密钥对
*/
private static void generateKeyPair() throws Exception {
/** RSA算法要求有一个可信任的随机数源 */
SecureRandom sr = new SecureRandom();
/** 为RSA算法创建一个KeyPairGenerator对象 */
KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM);
/** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
kpg.initialize(KEYSIZE, sr);
/** 生成密匙对 */
KeyPair kp = kpg.generateKeyPair();
/** 得到公钥 */
Key publicKey = kp.getPublic();
/** 得到私钥 */
Key privateKey = kp.getPrivate();
/** 用对象流将生成的密钥写入文件 */
ObjectOutputStream oos1 = new ObjectOutputStream(new FileOutputStream(
PUBLIC_KEY_FILE));
ObjectOutputStream oos2 = new ObjectOutputStream(new FileOutputStream(
PRIVATE_KEY_FILE));
oos1.writeObject(publicKey);
oos2.writeObject(privateKey);
/** 清空缓存,关闭文件输出流 */
oos1.close();
oos2.close();
}
/**
* 加密方法 source: 源数据
*/
public static byte[] encrypt(String source) throws Exception {
/** 将文件中的公钥对象读出 */
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
PUBLIC_KEY_FILE));
Key key = (Key) ois.readObject();
ois.close();
/** 得到Cipher对象来实现对源数据的RSA加密 */
Cipher cipher = Cipher.getInstance(ALGORITHM_MODEL);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] b = source.getBytes();
/** 执行加密操作 */
byte[] b1 = cipher.doFinal(b);
return b1;
}
/**
* 解密算法 cryptograph:密文
*/
public static String decrypt(byte[] cryptograph) throws Exception {
/** 将文件中的私钥对象读出 */
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
PRIVATE_KEY_FILE));
Key key = (Key) ois.readObject();
/** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
Cipher cipher = Cipher.getInstance(ALGORITHM_MODEL);
cipher.init(Cipher.DECRYPT_MODE, key);
/** 执行解密操作 */
byte[] b = cipher.doFinal(cryptograph);
return new String(b);
}
public static void main(String[] args) throws Exception {
generateKeyPair();//生成密钥对
String source = "邓鹏伟";// 要加密的字符串
System.out.println("加密的字符串为"+source);
byte[] cryptograph = encrypt(source);// 生成的密文
//可以将密文进行base64编码进行传输
System.out.println(new String(Base64.encode(cryptograph)));
String target = decrypt(cryptograph);// 解密密文
System.out.println(target);
}
}
------------------------------------------------------
输出:
加密的字符串为123
axejk/TwfbNQAB9dNlbu3x5bJl7l7bQmEvk1hbi+iV/ZseZOMEZdVpB2kgXYvACI9N8VMjW6+m13q14bRdhkrmwiP6fjVv85af+dc/gk5Jph1MB6nYey/8ZhWZI6VowH4OBncZX33kzomvwxycQfUXLM/yDGxM6neYt8PaIbtaQ=
123
判断方式
在网站中通常使用 JSEncrypt
库来实现,其最大的特征就是有一个设置公钥的过程,我们可以通过以下方法来快速初步判断是否为 RSA 算法
- 搜索关键词
new JSEncrypt()
,JSEncrypt
等,一般会使用 JSEncrypt 库,会有 new 一个实例对象的操作 - 搜索关键词
setPublicKey
、setKey
、setPrivateKey
、getPublicKey
等,一般实现的代码里都含有设置密钥的过程。
RAS的私匙 公匙 明文 密文 也有一一对应的关系