关于加密解密,加签验签那些事
面对MD5、SHA、DES、AES、RSA等等这些名词你是否有很多问号?这些名词都是什么?还有什么公钥加密、私钥解密、私钥加签、公钥验签。这些都什么鬼?或许在你日常工作没有听说过这些名词,但是一旦你要设计一个对外访问的接口,或者安全性要求高的系统,那么必然会接触到这些名词。所以加解密、加签验签对于一个合格的程序员来说是必须要掌握的一个概念。那么加解密相关的密码学真的离我们很遥远吗?其实生活中有很多常见的场景其实都用到了密码学的相关知识,我们不要把它想得太难。
例如在《睡在我上铺的兄弟》这一段中作弊绕口令中,小瘪三代表A,小赤佬代表B,唉呀妈呀代表C,坑爹呀是D,这一段绕口令其实也是密码学的一种。有兴趣的小伙伴可以看一下这一片段绕口令片段。所以其实密码学与我们生活息息相关,接下来我们就一文彻底搞懂这些概念。
《睡在我上铺的兄弟》作弊绕口令片段:
https://www.bilibili.com/video/av3696396/
没有硝烟的战场——浅谈密码技术
没有根基也许可以建一座小屋,但绝对不能造一座坚固的大厦。
密码这个词有很多种的解释,在现代社会如果不接触编程的话,那么普遍的认为是我们设置的登录密码、或者是去银行取钱时输入的数字。都是我们在注册时实现给提供服务的一方存储一组数字,以后我们登录的时候就用这组数字相当于就证明了我们的身份。这个数字通常来说就是叫做密码。
而我们需要了解的不是上面说的密码,而是一种“密码术”,就是对于要传递的信息按照某种规则进行转换,从而隐藏信息的内容。这种方法可以使机密信息得以在公开的渠道传递而不泄密。使用这种方法,要经过加密过程。在加密过程中我们需要知道下面的这些概念:
-
原文:或者叫明文,就是被隐藏的文字。
-
加密法:指隐藏原文的法则。
-
密文:或者叫伪文,指对原文按照加密法处理过后生成的可公开传递的文字。
-
密钥:在加密法中起决定性的因素,可能是数字、词汇,也可能是一些字母,或者这些东西的组合。
加密的结果生成了密文,要想让接受者能够读懂这些密文,那么就要把加密法以及密钥告诉接受者,否者接受者无法对密文解密,也就无法读懂原文。
从历史的角度来看,密码学大概可以分为古典密码学和近现代密码学两个阶段。两者以现代信息技术的诞生为分界点,现在所讨论的密码学多指的是后者,建立在信息论和数学成果基础之上的。
古典密码学
古典密码学源自于数千年前,最早在公元前 1900 年左右的古埃及,就出现了通过使用特殊字符和简单替换式密码来保护信息。美索不达米亚平原上曾经出土一个公元前 1500 年左右的泥板,其上记录了加密描述的陶瓷器上釉的工艺配方。古希腊时期(公元前 800 ﹣前 146 年)还发明了通过物理手段来隐藏信息的“隐写术”,例如使用牛奶书写、用蜡覆盖文字等。后来在古罗马时期还出现了基于替换加密的凯撒密码,据称凯撒曾用此方法与其部下通信而得以命名。这些手段多数是采用简单的机械工具来保护秘密,在今天看来毫无疑问是十分简陋,很容易猜出来的。严格来看,可能都很难称为密码科学。
凯撒密码是当偏移量是 3 的时候,所有的字母都 A 都将被替换成 D,B 变成 E,以此类推。
凯撒密码
近代密码学
近代密码学的研究来自于第一、二次世界大战中对于军事通信进行保护和猜出来的需求。1901年12月,意大利的工程师 Guglielmo Marconi(奎里亚摩•马可尼)成功完成了跨越大西洋的无线电通信的实验,在全球范围内引发轰动,推动了无线电通信时代的到来。无线电大大提高了远程通信的能力,但是它有一个天然的缺陷——很难限制接收方,这就意味着你所传的信息有可能被拦截,因此就催生了加密技术的发展。
对于无线电信息进行加密和解密也直接促进了近现代密码学和计算机技术的出现。反过来这些科技进步也影响了时代的发展。一战时期德国外交部长 Arthur Zimmermann(阿瑟•齐默尔曼)拉拢墨西哥构成抗美军事同盟的电报(1917年1月16日)被英国情报机构— 40 号办公室破译,直接导致了美国的参战;二战时期德国使用的恩尼格玛(Enigma)密码机(当时最先进的加密设备)被盟军成功破译(1939年到1941年),导致大西洋战役德国失败。据称,二战时期光英国从事密码学研究的人员就达到 7000 人,而他们的成果使二战结束的时间至少提前了一到两年时间。
接下来就是可以称之为是密码学发展史上里程碑的事件了。1945年9月1日,Claude Elwood Shannon(克劳德•艾尔伍德•香农)完成了划时代的内部报告《A Mathematical Theory of Cryptography(密码术的一个数学理论)》,1949 年 10 月,该报告以《Communication Theory of Secrecy Systems(保密系统的通信理论)》为题在 Bell System Technical Journal(贝尔系统技术期刊)上正式发表。这篇论文首次将密码学和信息论联系到一起,为对称密码技术提供了数学基础。这也标志着近现代密码学的正式建立。这也是密码学发展史上的第一座里程碑性事件。
密码学发展史上的第二个里程碑性事件是 DES 的出现。DES 全称为 Data Encryption Standard,即数据加密标准,是一种使用密钥加密的分组密码算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。
密码学发展史上的第三个里程碑性事件就是我们区块链中广泛应用的公钥密码,也就是非对称密码算法的出现。1976年11月,Whitfield Diffie 和 Martin E.Hellman 在 IEEE Transactions on Information Theory 上发表了论文《New Directions in Cryptography(密码学的新方向)》,探讨了无需传输密钥的保密通信和签名认证体系问题,正式开创了现代公钥密码学体系的研究。在公钥密码发现以前,如果需要保密通信,通信双方事先要对加解密的算法以及要使用的密钥进行事先协商,包括送鸡毛信,实际上是在传送密钥。但自从有了公钥密码,需要进行秘密通信的双方不再需要进行事前的密钥协商了。公钥密码在理论上是不保密的,在实际上是保密的。也就是说,公钥密码是可以猜出来的,但需要极长的时间,等到猜出来了,这个秘密也没有保密的必要了。
上面我们说到了关于近现代的密码学相关的东西,基本上总结下来我们现在常用的就两个,一个是对称加密算法,一个是非对称加密算法。那么接下来我们就以介绍这两个概念为主线引出开题中我们提到的概念。
程序实现
对称加密算法
对称加密指的就是加密和解密使用同一个秘钥,所以叫做对称加密。对称加密只有一个秘钥,作为私钥。具体的算法有:DES、3DES、TDEA、Blowfish、RC5、IDEA。但是我们常见的有:DES、AES 等等。
那么对称加密的优点是什么呢?算法公开、计算量小、加密速度快、加密效率高。缺点就是秘钥的管理和分发是非常困难的,不够安全。在数据传送前,发送方和接收方必须商定好秘钥,然后双方都必须要保存好秘钥,如果一方的秘钥被泄露了,那么加密的信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的唯一秘钥,这会使得收、发双方所拥有的的钥匙数量巨大,秘钥管理也会成为双方的负担。
加密的过程我们可以理解为如下:
-
加密:原文+秘钥 = 密文
-
解密:密文-秘钥 = 原文
可以看到两次过程使用的都是一个秘钥。用图简单表示如下:
实战演练
既然我们知道关于对称加密算法的相关知识,那么我们日常用 Java 如何实现对称加密的加密和解密动作呢?常见的对称加密算法有:DES、AES 等。
DES
DES 加密算法是一种分组密码,以 64 位为分组对数据加密,它的密钥长度是 56 位,加密解密用同一算法。DES 加密算法是对密钥进行保密,而公开算法,包括加密和解密算法。这样,只有掌握了和发送方相同密钥的人才能解读由 DES 加密算法加密的密文数据。因此,破译 DES 加密算法实际上就是搜索密钥的编码。对于 56 位长度的密钥来说,如果用穷举法来进行搜索的话,其运算次数为 2 的 56 次方。
接下来用 Java 实现 DES 加密
private final static String DES = "DES";
public static void main(String[] args) throws Exception {
String data = "123 456";
String key = "wang!@#$";
System.err.println(encrypt(data, key));
System.err.println(decrypt(encrypt(data, key), key));
}
/**
* Description 根据键值进行加密
* @param data
* @param key 加密键byte数组
* @return
* @throws Exception
*/
public static String encrypt(String data, String key) throws Exception {
byte[] bt = encrypt(data.getBytes(), key.getBytes());
String strs = new BASE64Encoder().encode(bt);
return strs;
}
/**
* Description 根据键值进行解密
* @param data
* @param key 加密键byte数组
* @return
* @throws IOException
* @throws Exception
*/
public static String decrypt(String data, String key) throws IOException,
Exception
{
if (data == null)
return null;
BASE64Decoder decoder = new BASE64Decoder();
byte[] buf = decoder.decodeBuffer(data);
byte[] bt = decrypt(buf,key.getBytes());
return new String(bt);
}
/**
* Description 根据键值进行加密
* @param data
* @param key 加密键byte数组
* @return
* @throws Exception
*/
private static byte[] encrypt(byte[] data, byte[] key) throws Exception {
// 生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从原始密钥数据创建DESKeySpec对象
DESKeySpec dks = new DESKeySpec(key);
// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
SecretKey securekey = keyFactory.generateSecret(dks);
// Cipher对象实际完成加密操作
Cipher cipher = Cipher.getInstance(DES);
// 用密钥初始化Cipher对象
cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
return cipher.doFinal(data);
}
/**
* Description 根据键值进行解密
* @param data
* @param key 加密键byte数组
* @return
* @throws Exception
*/
private static byte[] decrypt(byte[] data, byte[] key) throws Exception {
// 生成一个可信任的随机数源
SecureRandom sr = new SecureRandom();
// 从原始密钥数据创建DESKeySpec对象
DESKeySpec dks = new DESKeySpec(key);
// 创建一个密钥工厂,然后用它把DESKeySpec转换成SecretKey对象
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
SecretKey securekey = keyFactory.generateSecret(dks);
// Cipher对象实际完成解密操作
Cipher cipher = Cipher.getInstance(DES);
// 用密钥初始化Cipher对象
cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
return cipher.doFinal(data);
}
输出以后可以看到数据被加密了:
5fiw/XhRJ0E=
123 456
在 Java 中用 DES 加密有一个特殊的地方:
-
秘钥设置的长度必须大于等于 8。
-
秘钥设置的长度如果大于 8 的话,那么只会取前 8 个字节作为秘钥。
为什么呢,我们可以看到在初始化 DESKeySpec 类的时候有下面一段,其中 var1 是我们传的秘钥。可以看到它进行了截取,只截取前八个字节。
public DESKeySpec(byte[] var1, int var2) throws InvalidKeyException {
if (var1.length - var2 < 8) {
throw new InvalidKeyException("Wrong key size");
} else {
this.key = new byte[8];
System.arraycopy(var1, var2, this.key, 0, 8);
}
}
AES
AES 加密算法是密码学中的高级加密标准,该加密算法采用对称分组密码体制,密钥长度的最少支持为 128、192、256,分组长度 128 位,算法应易于各种硬件和软件实现。这种加密算法是美国联邦政府采用的区块加密标准,AES 标准用来替代原先的 DES,已经被多方分析且广为全世界所使用。
JCE(Java Cryptography Extension)在早期JDK版本中,由于受美国的密码出口条例约束,Java 中涉及加解密功能的 API 被限制出口,所以 Java 中安全组件被分成了两部分: 不含加密功能的 JCA(Java Cryptography Architecture )和含加密功能的 JCE(Java Cryptography Extension)。
JCE 的 API 都在 javax.crypto 包下,核心功能包括:加解密、密钥生成(对称)、MAC 生成、密钥协商。
加解密功能由 Cipher 组件提供,其也是 JCE 中最核心的组件。
在设置 Cipher 类的时候有几个注意点:
-
Cipher 在使用时需以参数方式指定 transformation。
-
transformation 的格式为 algorithm/mode/padding,其中 algorithm 为必输项,如: AES/DES/CBC/PKCS5Padding,具体有哪些可看下表。
-
缺省的 mode 为 ECB,缺省的 padding 为 PKCS5Padding。
-
在 block 算法与流加密模式组合时, 需在 mode 后面指定每次处理的 bit 数, 如 DES/CFB8/NoPadding, 如未指定则使用缺省值, SunJCE 缺省值为 64bits。
-
Cipher 有 4 种操作模式:ENCRYPT_MODE(加密)、DECRYPT_MODE(解密)、WRAP_MODE(导出Key)、UNWRAP_MODE(导入Key),初始化时需指定某种操作模式。
算法/模式/填充 | 16字节加密后数据长度 | 不满16字节加密后长度 |
---|---|---|
AES/CBC/NoPadding | 16 | 不支持 |
AES/CBC/PKCS5Padding | 32 | 16 |
AES/CBC/ISO10126Padding | 32 | 16 |
AES/CFB/NoPadding | 16 | 原始数据长度 |
AES/CFB/PKCS5Padding | 32 | 16 |
AES/CFB/ISO10126Padding | 32 | 16 |
AES/ECB/NoPadding | 16 | 不支持 |
AES/ECB/PKCS5Padding | 32 | 16 |
AES/ECB/ISO10126Padding | 32 | 16 |
AES/OFB/NoPadding | 16 | 原始数据长度 |
AES/OFB/PKCS5Padding | 32 | 16 |
AES/OFB/ISO10126Padding | 32 | 16 |
AES/PCBC/NoPadding | 16 | 不支持 |
AES/PCBC/PKCS5Padding | 32 | 16 |
AES/PCBC/ISO10126Padding | 32 | 16 |
秘钥的可以由我们自己定义,也可以是由AES自己生成,当自己定义是需要是要注意:
-
根据 AES 规范,可以是 16 字节、24 字节和32 字节长,分别对应 128 位、192 位和 256 位;
-
为便于传输,一般对加密后的数据进行 base64 编码:
public static void main(String[] args) throws Exception {
/*
* 此处使用AES-128-ECB加密模式,key需要为16位。
*/
String cKey = "1234567890123456";
// 需要加密的字串
String cSrc = "buxuewushu";
System.out.println(cSrc);
// 加密
String enString = Encrypt(cSrc, cKey);
System.out.println("加密后的字串是:" + enString);
// 解密
String DeString = Decrypt(enString, cKey);
System.out.println("解密后的字串是:" + DeString);
}
// 加密
public static String Encrypt(String sSrc, String sKey) throws Exception {
if (sKey == null) {
System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
if (sKey.length() != 16) {
System.out.print("Key长度不是16位");
return null;
}
byte[] raw = sKey.getBytes("utf-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");//"算法/模式/补码方式"
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(sSrc.getBytes("utf-8"));
return new Base64().encodeToString(encrypted);//此处使用BASE64做转码功能,同时能起到2次加密的作用。
}
// 解密
public static String Decrypt(String sSrc, String sKey) throws Exception {
try {
// 判断Key是否正确
if (sKey == null) {
System.out.print("Key为空null");
return null;
}
// 判断Key是否为16位
if (sKey.length() != 16) {
System.out.print("Key长度不是16位");
return null;
}
byte[] raw = sKey.getBytes("utf-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] encrypted1 = new Base64().decode(sSrc);//先用base64解密
try {
byte[] original = cipher.doFinal(encrypted1);
String originalString = new String(original,"utf-8");
return originalString;
} catch (Exception e) {
System.out.println(e.toString());
return null;
}
} catch (Exception ex) {
System.out.println(ex.toString());
return null;
}
}
非对称加密算法
非对称加密算法中加密和解密用的不是同一个秘钥,所以叫作非对称加密算法。在非对称加密算法每个用户都有两把钥匙,一把公钥一把私钥。公钥是对外发布的,所有人都看的到所有人的公钥,私钥是自己保存,每个人都只知道自己的私钥而不知道别人的。而也正是在非对称加密算法中有加密和解密、加签和验签的概念。接下来我们解释一下这几个概念是什么意思。
加密和解密
用该用户的公钥加密后只能该用户的私钥才能解密。这种情况下,公钥是用来加密信息的,确保只有特定的人(用谁的公钥就是谁)才能解密该信息。所以这种我们称之为加密和解密。
下面我拿 A 银行和小明来举例子吧。假设这2者之间是用不对称的加密算法来保证信息传输的安全性(不被第三人知道信息的含义及篡改信息)。大致流程如下:首先小明发了一条信息给A银行“我要存500元”。这条信息小明会根据A银行的对外发布的公钥把这条信息加密了,加密之后,变成“XXXXXXX”发给A银行。中间被第三者截获,由于没有A银行的私钥无法解密,不能知道信息的含义,也无法按正确的方式篡改。所以拿这条加密信息是没办法的。最后被 A 银行接受,A银行用自己的私钥去解密这条信息,解密成功,读取内容,执行操作。然后得知消息是小明发来的,便去拿小明的公钥,把“操作成功(或失败)”这条信息用小明的公钥加密,发给小明。同理最后小明用自己的私钥解开,得知知乎发来的信息内容。其他人截获因为没有小明的私钥所以也没有用。
加签和验签
还有第二种情况,公钥是用来解密信息的,确保让别人知道这条信息是真的由我发布的,是完整正确的。接收者由此可知这条信息确实来自于拥有私钥的某人,这被称作数字签名,公钥的形式就是数字证书。所以这种我们称之为加签和验签。
继续拿小明和银行 A 举例子。银行 A 发布了一个银行客户端的补丁供所有用户更新,那为了确保人家下载的是正确完整的客户端,银行A会为这个程序打上一个数字签名(就是用银行A的私钥对这个程序加密然后发布),你需要在你的电脑里装上银行 A 的数字证书(就是银行对外发布的公钥),然后下载好这个程序,数字证书会去解密这个程序的数字签名,解密成功,补丁得以使用。同时你能知道这个补丁确实是来自这个银行 A,是由他发布的,而不是其他人发布的。
实战演练
我们在开发过程中经常使用的非对称加密算法就是 RSA 算法。接下来我们使用 Java 实现 RSA 算法。
生成密钥
首先是生成 key 的部分。生成 key 有好多种做法,这里我介绍三种:
1. 命令行:可以使用openssl进行生成公钥和私钥。
-- 生成公钥和私钥
openssl genrsa -out key.pem 1024
-out 指定生成文件,此文件包含公钥和私钥两部分,所以即可以加密,也可以解密
1024 生成密钥的长度
2.使用网站:生成密钥的网站。
http://web.chacuo.net/netrsakeypair
3.使用代码:可以指定生成密钥的长度,最低是 512。
public static KeyPair buildKeyPair() throws NoSuchAlgorithmException {
final int keySize = 2048;
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
keyPairGenerator.initialize(keySize);
return keyPairGenerator.genKeyPair();
}
加密
有了密钥,就可以进行加密的操作了,接下来就介绍关于 RSA 的加密操作,非常简单只要传进来公钥和需要加密的数据即可。
public static byte[] encrypt(PublicKey publicKey, String message) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(message.getBytes(UTF8));
}
解密
public static byte[] decrypt(PrivateKey privateKey, byte [] encrypted) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(encrypted);
}
加签
/**
* 使用RSA签名
*/
private static String signWithRSA(String content, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initSign(privateKey);
signature.update(content.getBytes("utf-8"));
byte[] signed = signature.sign();
return base64Encode(signed);
}
验签
/**
* 使用RSA验签
*/
private static boolean checkSignWithRSA(String content, PublicKey publicKey,String sign) throws Exception {
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(publicKey);
signature.update(content.getBytes("utf-8"));
return signature.verify(base64Decode(sign));
}
在加签验签的时候需要传入一个数字签名标准,我们这里填的是 SHA1WithRSA,它的意思是用 SHA 算法进行签名,用 RSA 算法进行加密。
算法说明:在对进行 SHA1 算法进行摘要计算后,要求对计算出的摘要进行处理,而不是直接进行 RSA算 法进行加密。要求把 SHA1 摘要的数据进行压缩到 20 个字节。在前面插入 15 个字节标示数据。所以结构如下:
30(数据类型结构)21(总长度)30(数据类型)09(长度)06 05 2B 0E 03 02 1A 0500【数据具体类型不清楚-请专家指正】 04 (数据类型) 14 (长度) + SHA1签名数据
最后进行RSA加密。所以我们填写的 XXXWithRSA,这个 XXX 代表的就是使用什么摘要算法进行加签,至于摘要算法是什么,随后会有详细的说明。
调用实验一下
public static void main(String[] args) throws Exception {
KeyPair keyPair = buildKeyPair();
byte[] encryptData = encrypt(keyPair.getPublic(), "不学无数");
System.out.println(String.format("加密后的数据:%s",base64Encode(encryptData)));
System.out.println(String.format("解密后的数据:%s",new String(decrypt(keyPair.getPrivate(),encryptData),UTF8)));
String context = "加签的字符串";
String sign = signWithRSA(context, keyPair.getPrivate());
System.out.println(String.format("生成的签名:%s",sign));
Boolean checkSignWithRSA = checkSignWithRSA(context, keyPair.getPublic(), sign);
System.out.println(String.format("校验的结果:%s",checkSignWithRSA.toString()));
}
输出为:
加密后的数据:Bi8b4eqEp+rNRhDaij8vVlNwKuICbPJfFmyzmEXKuAgEgzMPb8hAmYiGN+rbUKWeZYJKJd0fiOXv
6YrYqd7fdast/m443qQreRLxdQFScwvCvj9g1YnPzbU2Q/jIwqAPopTyPHNNngBmFki+R/6V4DYt
HA5gniaUMYzynHdD+/W+x8ZYmwiuuS63+7wXqL36aLKe0H50wELOpSn45Gvni8u+5zPIoHV7PBiz
trCnQvne5LxFKDprrS3td1/76qyupFd+Ul3hsd+gjbAyN2MlXcAFMrGVaRkopWwc9hP1BsPvS52q
/8jOVdbeyU9BziVhViz1V0TtGW8bfbEnIStc3Q==
解密后的数据:不学无数
生成的签名:wvUXtr2UI0tUXmyMTTUBft8oc1dhvtXSBrFFetI5ZoxMm91TbXRWD31Pgqkg72ADxx9TEOAM3Bm1
kyzfBCZZpoq6Y9SM4+jdJ4sMTVtw0wACPglnPDAGs8sG7nnLhXWNQ1Y4pl4ziY6uLxF1TzQLFTxu
NAS7nyljbG69wrb9R3Sv5t8r1I54rYCVGSVFmTrGf+dSCjxABZv6mH8nygVif7zN1vU1+nSDKcON
Vtrpv0xCQHVBqnHPA6OiDm5GzBQxjD5aQt8mfgv8JJrB52TEa4JPYoC5Zw4JHlL++OvPwMpJgnuG
yg5vnWhxE2ncTzM+/pZ+CnXF2Dqv/JMQOfX6tA==
校验的结果:true
摘要算法
数据摘要算法是密码学算法中非常重要的一个分支,它通过对所有数据提取指纹信息以实现数据签名、数据完整性校验等功能,由于其不可逆性,有时候会被用做敏感信息的加密。数据摘要算法也被称为哈希(Hash)算法或散列算法。
消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文(摘要可以比方为指纹,消息摘要算法就是要得到文件的唯一职位)。
特点
无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息(不可逆性)。
好的摘要算法,没有人能从中找到“碰撞”或者说极度难找到,虽然“碰撞”是肯定存在的(碰撞即不同的内容产生相同的摘要)。
应用
一般地,把对一个信息的摘要称为该消息的指纹或数字签名。数字签名是保证信息的完整性和不可否认性的方法。数据的完整性是指信宿接收到的消息一定是信源发送的信息,而中间绝无任何更改;信息的不可否认性是指信源不能否认曾经发送过的信息。其实,通过数字签名还能实现对信源的身份识别(认证),即确定“信源”是否是信宿意定的通信伙伴。数字签名应该具有唯一性,即不同的消息的签名是不一样的;同时还应具有不可伪造性,即不可能找到另一个消息,使其签名与已有的消息的签名一样;还应具有不可逆性,即无法根据签名还原被签名的消息的任何信息。这些特征恰恰都是消息摘要算法的特征,所以消息摘要算法适合作为数字签名算法。
有哪些具体的消息摘要算法?
-
CRC8、CRC16、CRC32:CRC(Cyclic Redundancy Check,循环冗余校验)算法出现时间较长,应用也十分广泛,尤其是通讯领域。现在应用最多的就是 CRC32 算法,它产生一个 4 字节(32位)的校验值,一般是以 8 位十六进制数,如FA 12 CD 45等。CRC 算法的优点在于简便、速度快。严格的来说,CRC 更应该被称为数据校验算法,但其功能与数据摘要算法类似,因此也作为测试的可选算法。
-
MD2 、MD4、MD5:这是应用非常广泛的一个算法家族,尤其是 MD5(Message-Digest Algorithm 5,消息摘要算法版本5),它由 MD2、MD3、MD4 发展而来,由 Ron Rivest(RSA公司)在 1992 年提出,目前被广泛应用于数据完整性校验、数据(消息)摘要、数据加密等。MD2、MD4、MD5 都产生 16 字节(128位)的校验值,一般用32位十六进制数表示。MD2的算法较慢但相对安全,MD4 速度很快,但安全性下降,MD5 比 MD4 更安全、速度更快。
-
SHA1、SHA256、SHA384、SHA512:SHA(Secure Hash Algorithm)是由美国专门制定密码算法的标准机构——美国国家标准技术研究院(NIST)制定的,SHA系列算法的摘要长度分别为:SHA 为 20 字节(160位)、SHA256 为 32 字节(256位)、 SHA384 为 48 字节(384位)、SHA512 为 64 字节(512位),由于它产生的数据摘要的长度更长,因此更难以发生碰撞,因此也更为安全,它是未来数据摘要算法的发展方向。由于SHA系列算法的数据摘要长度较长,因此其运算速度与 MD5 相比,也相对较慢。
-
RIPEMD、PANAMA、TIGER、ADLER32 等:RIPEMD 是 Hans Dobbertin 等 3 人在对 MD4、MD5 缺陷分析基础上,于 1996 年提出来的,有 4 个标准 128、160、256 和 320,其对应输出长度分别为 16 字节、20 字节、32 字节和 40 字节。TIGER 由 Ross 在 1995 年提出。Tiger 号称是最快的 Hash 算法,专门为 64位机器做了优化。
实战演练
在单独的使用摘要算法时我们通常使用的 MD5 算法,所以我们这里就单独说明使用 Java 实现 MD5 算法。
public static String getMD5Str(String str) throws Exception {
try {
// 生成一个MD5加密计算摘要
MessageDigest md = MessageDigest.getInstance("MD5");
// 计算md5函数
md.update(str.getBytes());
// digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
return new BigInteger(1, md .digest()).toString(16);
} catch (Exception e) {
throw new Exception("MD5加密出现错误,"+e.toString());
}
}
相关文章:

关于加密解密,加签验签那些事
面对MD5、SHA、DES、AES、RSA等等这些名词你是否有很多问号?这些名词都是什么?还有什么公钥加密、私钥解密、私钥加签、公钥验签。这些都什么鬼?或许在你日常工作没有听说过这些名词,但是一旦你要设计一个对外访问的接口ÿ…...

容器重启后,Conda文件完整保存(虚拟环境、库包),如何重新安装conda并迁移之前的虚拟环境
Vim安装 容器重启后默认是vi,升级vim,执行命令 apt install -y vim安装 Anaconda 1. 下载Anaconda 其他版本请查看Anaconda官方库 wget https://mirrors.bfsu.edu.cn/anaconda/archive/Anaconda3-2023.03-1-Linux-x86_64.sh --no-check-certificate…...

gitee对接使用
1.创建一个文件夹 2.进入Gitee接受对方项目编辑 3.打开终端初始化一开始创建的文件夹 git init 3.1打开终端 3.2输入git.init 4.克隆对方的项目 4.1进入Gitee复制对方项目的路径 4.2在编辑器终端内克隆对方项目 git clone 网址 如此你的编辑器就会出现对方的项目 …...

C语言中的一维数组与二维数组
目录 一维数组数组的创建初始化使用在内存中的存储 二维数组创建初始化使用在内存中的存储 数组越界 一维数组 数组的创建 数组是一组相同类型元素的集合。 int arr1[10]; char arr3[10]; float arr4[10]; double arr5[10];下面这个数组能否成功创建? int count…...

【Linux】地址空间
本片博客将重点回答三个问题 什么是地址空间? 地址空间是如何设计的? 为什么要有地址空间? 程序地址空间排布图 在32位下,一个进程的地址空间,取值范围是0x0000 0000~ 0xFFFF FFFF 回答三个问题之前我们先来证明地址空…...

作为一个产品经理带你了解Axure的安装和基本使用
1.Axure的简介 Axure是一种强大的原型设计工具,它允许用户创建交互式的、高保真度的原型,以及进行用户体验设计和界面设计。Axure可以帮助设计师和产品经理快速创建和共享原型,以便团队成员之间进行沟通和反馈。Axure提供了丰富的交互组件和功…...

接口测试总结及其用例设计方法
接口测试的总结文档 第一部分:主要从问题出发,引入接口测试的相关内容并与前端测试进行简单对比,总结两者之前的区别与联系。但该部分只交代了怎么做和如何做?并没有解释为什么要做? 第二部分:主要介绍…...

2023团体程序设计天梯赛——模拟赛和总决赛题
M-L1-1 嫑废话上代码 Linux 之父 Linus Torvalds 的名言是:“Talk is cheap. Show me the code.”(嫑废话,上代码)。本题就请你直接在屏幕上输出这句话。 输入格式: 本题没有输入。 输出格式: 在一行中输出…...

智能优化算法应用:基于人工蜂鸟算法无线传感器网络(WSN)覆盖优化 - 附代码
智能优化算法应用:基于人工蜂鸟算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于人工蜂鸟算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.人工蜂鸟算法4.实验参数设定5.算法结果6.参考…...

视频中自监督学习:「我的世界」下指令理解与跟随
本文介绍了北京大学人工智能研究院梁一韬助理教授所带领的 CraftJarvis 团队在「我的世界」环境下探索通用智能体设计的新进展,题为“GROOT: Learning to Follow Instructions by Watching Gameplay Videos”。 GROOT 该研究的核心目标是探索能否摆脱文本数据的标…...

Spring基于xml半注解开发
目录 Component的使用 依赖注解的使用 非自定义Bean的注解开发 Component的使用 基本Bean注解,主要是使用注解的方式替代原有的xml的<bean>标签及其标签属性的配置,使用Component注解替代<bean>标签中的id以及class属性,而对…...

功能测试,接口测试,自动化测试,压力测试,性能测试,渗透测试,安全测试,具体是干嘛的?
软件测试是一个广义的概念,他包括了多领域的测试内容,比如,很多新手可能都听说:功能测试,接口测试,自动化测试,压力测试,性能测试,渗透测试,安全测试等&#…...

oracle 下载java之前版本
登录oracle官网:Oracle | Cloud Applications and Cloud Platform 点击resource 进入该页面 点击这个 出现之前版本...

LLM之Agent(四)| AgentGPT:一个在浏览器运行的Agent
AgentGPT是一个自主人工智能Agent平台,用户只需要为Agent指定一个名称和目标,就可以在浏览器中链接大型语言模型(如GPT-4)来创建和部署Agent平台。 PS:目前agentGPT仅支持chatgpt模型,暂时不支持本地llm模…...

AGM离线下载器使用说明
AGM专用离线下载器示意图: 供电方式: 通过 USB 接口给下载器供电,跳线 JP 断开。如果客户 PCB 的 JTAG 口不能提供 3.3V 电源,或仅需烧写下载器,尚未连接用户 PCB 时,采用此种方式供电。 或者:…...

viple与物理机器人(一):线控模拟
为了检测viple程序与物理机器人是否能顺利连接上 如果能顺利连接上,那么,可以通过内建事件从而控制物理机器人的前进、后退、左转、右转以及暂停。 如果不能连接上,首先,程序无法控制物理机器人,其次,当vip…...

Appium 并行测试多个设备
一、前置说明 在自动化测试中,经常需要验证多台设备的兼容性,Appium可以用同一套测试运例并行测试多个设备,以达到验证兼容性的目的。 解决思路: 查找已连接的所有设备;为每台设备启动相应的Appium Server;…...

高防IP是什么? 防护CC 对抗DDOS
什么是DDoS高防IP? DDoS(分布式拒绝服务)攻击是指攻击者通过利用大量恶意流量向目标服务器发送请求,导致目标服务器无法正常处理合法用户的请求。DDoS高防IP是一种通过技术手段来应对DDoS攻击的解决方案。它能够过滤掉恶意流量&a…...

使用消息队列遇到的问题—kafka
目录 1 分区2 消费者3 Kafka 如何保证消息的消费顺序?3.1 方案一3.2 方案二 4 消息积压 在项目中使用kafka作为消息队列,核心工作是创建生产者—包装数据;创建消费者----包装数据。 欠缺一些思考,特此梳理项目中使用kafka遇到的一…...

Linux系统---基于Pipe实现一个简单Client-Server system
顾得泉:个人主页 个人专栏:《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂,年薪百万! 一、题目要求 Server是一个服务器进程,只能进行整数平方运算。Client要计算一个整数的平方的平方的平方,即…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
CSS | transition 和 transform的用处和区别
省流总结: transform用于变换/变形,transition是动画控制器 transform 用来对元素进行变形,常见的操作如下,它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
Spring Security 认证流程——补充
一、认证流程概述 Spring Security 的认证流程基于 过滤器链(Filter Chain),核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤: 用户提交登录请求拦…...