关于加密解密,加签验签那些事

面对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 加密有一个特殊的地方

  1. 秘钥设置的长度必须大于等于 8。

  2. 秘钥设置的长度如果大于 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 类的时候有几个注意点

  1. Cipher 在使用时需以参数方式指定 transformation。

  2. transformation 的格式为 algorithm/mode/padding,其中 algorithm 为必输项,如: AES/DES/CBC/PKCS5Padding,具体有哪些可看下表。

  3. 缺省的 mode 为 ECB,缺省的 padding 为 PKCS5Padding。

  4. 在 block 算法与流加密模式组合时, 需在 mode 后面指定每次处理的 bit 数, 如 DES/CFB8/NoPadding, 如未指定则使用缺省值, SunJCE 缺省值为 64bits。

  5. Cipher 有 4 种操作模式:ENCRYPT_MODE(加密)、DECRYPT_MODE(解密)、WRAP_MODE(导出Key)、UNWRAP_MODE(导入Key),初始化时需指定某种操作模式。

算法/模式/填充16字节加密后数据长度不满16字节加密后长度
AES/CBC/NoPadding16不支持
AES/CBC/PKCS5Padding3216
AES/CBC/ISO10126Padding3216
AES/CFB/NoPadding16原始数据长度
AES/CFB/PKCS5Padding3216
AES/CFB/ISO10126Padding3216
AES/ECB/NoPadding16不支持
AES/ECB/PKCS5Padding3216
AES/ECB/ISO10126Padding3216
AES/OFB/NoPadding16原始数据长度
AES/OFB/PKCS5Padding3216
AES/OFB/ISO10126Padding3216
AES/PCBC/NoPadding16不支持
AES/PCBC/PKCS5Padding3216
AES/PCBC/ISO10126Padding3216

秘钥的可以由我们自己定义,也可以是由AES自己生成,当自己定义是需要是要注意:

  1. 根据 AES 规范,可以是 16 字节、24 字节和32 字节长,分别对应 128 位、192 位和 256 位;

  2. 为便于传输,一般对加密后的数据进行 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+rbUKWeZYJKJd0fiOXv6YrYqd7fdast/m443qQreRLxdQFScwvCvj9g1YnPzbU2Q/jIwqAPopTyPHNNngBmFki+R/6V4DYtHA5gniaUMYzynHdD+/W+x8ZYmwiuuS63+7wXqL36aLKe0H50wELOpSn45Gvni8u+5zPIoHV7PBiztrCnQvne5LxFKDprrS3td1/76qyupFd+Ul3hsd+gjbAyN2MlXcAFMrGVaRkopWwc9hP1BsPvS52q/8jOVdbeyU9BziVhViz1V0TtGW8bfbEnIStc3Q==解密后的数据:不学无数生成的签名:wvUXtr2UI0tUXmyMTTUBft8oc1dhvtXSBrFFetI5ZoxMm91TbXRWD31Pgqkg72ADxx9TEOAM3Bm1kyzfBCZZpoq6Y9SM4+jdJ4sMTVtw0wACPglnPDAGs8sG7nnLhXWNQ1Y4pl4ziY6uLxF1TzQLFTxuNAS7nyljbG69wrb9R3Sv5t8r1I54rYCVGSVFmTrGf+dSCjxABZv6mH8nygVif7zN1vU1+nSDKcONVtrpv0xCQHVBqnHPA6OiDm5GzBQxjD5aQt8mfgv8JJrB52TEa4JPYoC5Zw4JHlL++OvPwMpJgnuGyg5vnWhxE2ncTzM+/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());    }}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/214298.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

聚焦中国—东盟大健康产业峰会 点靓广西“长寿福地”品牌

12月8-10日2023中国—东盟大健康产业峰会暨大健康产业博览会在南宁国际会展中心成功举办&#xff0c;本次峰会由国家中医药管理局、广西壮族自治区人民政府联合主办&#xff0c;中国老年学和老年医学学会、自治区党委宣传部、自治区民政厅、广西壮族自治区外事办公室、广西壮族…

MySQL使用窗口函数ROW_NUMBER()、DENSE_RANK()查询每组第一名或每组前几名,窗口函数使用详解

MySQL数据表结构 创建 tbl_class_info 表&#xff0c;表中有四个字段 id、username、score、group_name 使用 ROW_NUMBER()、DENSE_RANK() 查询每组前三名 -- 查询每组前3名 SELECT username, score, group_name FROM ( SELECT username, score, group_name, ROW_NUMBER()…

目标检测——R-FCN算法解读

论文&#xff1a;R-FCN: Object Detection via Region-based Fully Convolutional Networks 作者&#xff1a;Jifeng Dai, Yi Li, Kaiming He and Jian Sun 链接&#xff1a;https://arxiv.org/pdf/1605.06409v2.pdf 代码&#xff1a;https://github.com/daijifeng001/r-fcn 文…

5.鸿蒙hap可以直接点击包安装吗?

5.鸿蒙hap可以直接点击包安装吗&#xff1f; hap与apk不同&#xff0c;获取的hap不能直接安装 安装方法1&#xff1a; DevEco studio打开项目源文件&#xff0c;打开手机USB调试&#xff0c;DevEco识别到手机后&#xff0c;点击播放按钮安装到手机 https://txwtech.blog.cs…

Rust 通用代码生成器莲花发布红莲尝鲜版十八介绍视频,初学者指南

Rust 通用代码生成器莲花发布红莲尝鲜版十八介绍视频&#xff0c;初学者指南 Rust 通用代码生成器莲花发布深度修复版红莲尝鲜版十八介绍视频&#xff0c;初学者指南&#xff0c;详细介绍代码生成器环境搭建&#xff0c;编译&#xff0c;运行和使用代码生成物&#xff0c;欢迎…

nginx中的正则表达式及location和rewrite

目录 常用的Nginx 正则表达式 location和rewrite的区别 location location 大致可以分为三类 location 常用的匹配规则 location 优先级 location 示例说明 location优先级的总结 rewrite rewrite的功能 rewrite实现跳转的条件 rewrite的执行顺序 rewrite的语法格式…

ARM day3

题目&#xff1a;实现3盏灯的流水 代码&#xff1a; .text .global _start _start: 设置RCC寄存器使能 LDR R0,0X50000A28 LDR R1,[R0] ORR R1,R1,#(0X1<<4) ORR R1,R1,#(0X1<<5) STR R1,[R0]设置PE10管脚为输出模式 LDR R0,0X50006000 LDR R1,[R0] BIC R1,R1,…

文心ERNIE Bot SDK+LangChain:基于文档、网页的个性化问答系统

现在各行各业纷纷选择接入大模型&#xff0c;其中最火且可行性最高的形式无异于智能文档问答助手&#xff0c;而LangChain是其中主流技术实现工具&#xff0c;能够轻松让大语言模型与外部数据相结合&#xff0c;从而构建智能问答系统。ERNIE Bot SDK已接入文心大模型4.0能力&am…

如何使用Imagewheel本地搭建一个简单的的私人图床公网可访问?

文章目录 1.前言2. Imagewheel网站搭建2.1. Imagewheel下载和安装2.2. Imagewheel网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar临时数据隧道3.2.Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

Java:字符流 文件输出 与 读入 方法

Java&#xff1a;字节流 文件输出与读入方法 并 实现文件拷贝 文章目录 字符流FileReaderFileWrite 字符流 字符流底层就是字节流。 字符流 字节流 字符集 特点&#xff1a; 输入流&#xff1a;一次读入一个字节&#xff0c;遇到中文时&#xff0c;一次读多个字节。 输出流…

POJ-2777 Count Color

经典区间染色板子题 #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N 1e610; struct Segment{int l,r,id; }tr[N<<2]; int n,color,m;void pushdown(int u){if(tr[u].id){tr[u<<1].id tr[u<&l…

计算机视觉之手势、面部、姿势捕捉以Python Mediapipe为工具

计算机视觉之手势、面部、姿势捕捉以 Python Mediapipe为工具 文章目录 1.Mediapipe库概述2.手势捕捉(hands)3.面部捕捉(face)4.姿势捕捉(pose) 1.Mediapipe库概述 Mediapipe是一个开源且强大的Python库&#xff0c;由Google开发和维护。它提供了丰富的工具和功能&#xff0c…

stm32学习总结:3、Proteus8+STM32CubeMX+MDK很有搞头

stm32学习总结&#xff1a;3、Proteus8STM32CubeMXMDK很有搞头 文章目录 stm32学习总结&#xff1a;3、Proteus8STM32CubeMXMDK很有搞头一、前言二、资料收集三、实际案例-点灯1、Proteus8安装2、Proteus创建stm32F013C6项目并添加外围LED电路3、STM32CubeMX配置F103C6引脚生成…

12.10_黑马数据结构与算法笔记Java

目录 058 链表 e10 判环算法1 thinking&#xff1a;什么是空指针&#xff1f; 058 链表 e10 判环算法2 059 数组 e01 合并有序数组1 059 数组 e01 合并有序数组2 060 队列 链表实现1 061 队列 链表实现2 062 队列 环形数组实现 方法1-1 063 队列 环形数组实现 方法1-2…

带有 RaspiCam 的 Raspberry Pi 监控和延时摄影摄像机

一、说明 一段时间以来&#xff0c;我一直想构建一个运动激活且具有延时功能的树莓派相机&#xff0c;但从未真正找到我喜欢的案例。我在thingiverse上找到了这个适合树莓派和相机的好案例。它是为特定的鱼眼相机设计的&#xff0c;但从模型来看&#xff0c;我拥有的廉价中国鱼…

【Vulnhub 靶场】【Hackable: III】【简单 - 中等】【20210602】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/hackable-iii,720/ 靶场下载&#xff1a;https://download.vulnhub.com/hackable/hackable3.ova 靶场难度&#xff1a;简单 - 中等 发布日期&#xff1a;2021年06月02日 文件大小&#xff1a;1.6 GB 靶场作者&…

Docker | 自定义网络

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏:Docker系列 ✨特色专栏: MySQL学习 🥭本文内容: Docker | 自定义网络 📚个人知识库: 知识库,欢迎大家访问 1.前言 大家好,我是Leo哥…

当视觉遇到毫米波雷达:自动驾驶的三维目标感知基准

​ 文章&#xff1a;Vision meets mmWave Radar: 3D Object Perception Benchmark for Autonomous Driving 作者: Yizhou Wang, Jen-Hao Cheng, Jui-Te Huang , Sheng-Yao Kuan , Qiqian Fu , Chiming Ni 编辑&#xff1a;点云PCL 欢迎各位加入知识星球&#xff0c;获取PDF…

vector类

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟悉vector库 > 毒鸡汤&#xff1a;从人生低谷…