密码学4「消息摘要和非对称加密」
lipiwang 2024-10-25 15:55 6 浏览 0 评论
1消息摘要
- 消息摘要(Message Digest)又称为数字摘要(Digital Digest)
- 它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生
- 使用数字摘要生成的值是不可以篡改的,为了保证文件或者值的安全
无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。例如应用MD5算法摘要的消息有128个比特位,用SHA-1算法摘要的消息最终有160比特位的输出只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出消息摘要是单向、不可逆的
1.1 消息摘要特点
消息摘要算法的特点:
消息摘要是把任意长度的输入揉和而产生长度固定的伪随机输入的算法。消息摘要的主要特点有:
①无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。例如应用MD5算法摘要的消息有128个比特位,用SHA-1算法摘要的消息最终有160比特位的输出,SHA-1的变体可以产生192比特位和256比特位的消息摘要。一般认为,摘要的最终输出越长,该摘要算法就越安全。
②消息摘要看起来是“随机的”。这些比特看上去是胡乱的杂凑在一起的。可以用大量的输入来检验其输出是否相同,一般,不同的输入会有不同的输出,而且输出的摘要消息可以通过随机性检验。但是,一个摘要并不是真正随机的,因为用相同的算法对相同的消息求两次摘要,其结果必然相同;而若是真正随机的,则无论如何都是无法重现的。因此消息摘要是“伪随机的”。
③一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。这正是好的消息摘要算法所具有的性质:输入改变了,输出也就改变了;两条相似的消息的摘要确不相近,甚至会大相径庭。
④消息摘要函数是无陷门的单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。当然,可以采用强力攻击的方法,即尝试每一个可能的信息,计算其摘要,看看是否与已有的摘要相同,如果这样做,最终肯定会恢复出摘要的消息。但实际上,要得到的信息可能是无穷个消息之一,所以这种强力攻击几乎是无效的。
⑤好的摘要算法,没有人能从中找到“碰撞”,虽然“碰撞”是肯定存在的。即对于给定的一个摘要,不可能找到一条信息使其摘要正好是给定的。或者说,无法找到两条消息,使它们的摘要相同。
1.2 消息摘要的应用
一般地,把对一个信息的摘要称为该消息的指纹或数字签名。数字签名是保证信息的完整性和不可否认性的方法。数据的完整性是指信宿接收到的消息一定是信源发送的信息,而中间绝无任何更改;信息的不可否认性是指信源不能否认曾经发送过的信息。其实,通过数字签名还能实现对信源的身份识别(认证),即确定“信源”是否是信宿意定的通信伙伴。 数字签名应该具有唯一性,即不同的消息的签名是不一样的;同时还应具有不可伪造性,即不可能找到另一个消息,使其签名与已有的消息的签名一样;还应具有不可逆性,即无法根据签名还原被签名的消息的任何信息。这些特征恰恰都是消息摘要算法的特征,所以消息摘要算法适合作为数字签名算法。
数字签名
数字签名方案是一种以电子形式存储消息签名的方法。一个完整的数字签名方案应该由两部分组成:签名算法和验证算法。一般地说,任何一个公钥密码体制都可以单独地作为一种数字签名方案使用。如RSA作为数字签名方案使用时,可以定义如下:
这种签名实际上就是用信源的私钥加密消息,加密后的消息即成了签体;而用对应的公钥进行验证,若公钥解密后的消息与原来的消息相同,则消息是完整的,否则消息不完整。它正好和公钥密码用于消息保密是相反的过程。因为只有信源才拥有自己地私钥,别人无法重新加密源消息,所以即使有人截获且更改了源消息,也无法重新生成签体,因为只有用信源的私钥才能形成正确地签体。同样信宿只要验证用信源的公钥解密的消息是否与明文消息相同,就可以知道消息是否被更改过,而且可以认证消息是否是确实来自意定的信源,还可以使信源不能否认曾将发送的消息。所以这样可以完成数字签名的功能
但这种方案过于单纯,它仅可以保证消息的完整性,而无法确保消息的保密性。而且这种方案要对所有的消息进行加密操作,这在消息的长度比较大时,效率使非常低的,主要原因在于公钥体制的加解密过程的低效性。所以这种方案一般不可取。
摘要算法
几乎所有的数字签名方案都要和快速高效的摘要算法(Hash函数)一起使用,当公钥算法与摘要算法结合起来使用时,便构成了一种有效地数字签名方案。
这个过程是:首先用摘要算法对消息进行摘要,然后在把摘要值用信源的私钥加密;接收方先把接收的明文用同样的摘要算法摘要,形成“准签体”,然后再把准签体与用信源的公钥解密出的“签体”进行比较,如果相同就认为消息是完整的,否则消息不完整。
这种方法使公钥加密只对消息摘要进行操作,因为一种摘要算法的摘要消息长度是固定的,而且都比较“短”(相对于消息而言),正好符合公钥加密的要求。这样效率得到了提高,而其安全性也并未因为使用摘要算法而减弱。
常见算法 : MD5- SHA1- SHA256- SHA512
百度搜索 tomcat ,进入官网下载 ,会经常发现有 sha1,sha512 , 这些都是数字摘要
1.3用java程序获取数字摘要
package com.fire.Digest;
import com.sun.org.apache.xml.internal.security.utils.Base64;
import java.security.MessageDigest;
public class DigestDemo1 {
public static void main(String[] args) throws Exception{
//4124bc0a9335c27f086f24ba207a4912
//4124bc0a9335c27f086f24ba207a4912
String input="aa";
//算法
String algorithm="MD5";
String md5Digest=getDigest("aa",algorithm);
System.out.println(md5Digest);
// String algorithm1="SHA-1";
// String SHA1Digest=getDigest("aa",algorithm1);
// System.out.println(SHA1Digest);
//
// String algorithm2="SHA-256";
// String SHA256Digest=getDigest("aa",algorithm1);
// System.out.println(SHA256Digest);
}
private static String toHex(byte[] digest) throws Exception {
// System.out.println(new String(digest));
// base64编码
// System.out.println(Base64.encode(digest));
// 创建对象用来拼接
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
// 转成 16进制
String s = Integer.toHexString(b & 0xff);
if (s.length() == 1){
// 如果生成的字符只有一个,前面补0
s = "0"+s;
}
sb.append(s);
}
System.out.println("16进制数据的长度:" + sb.toString().getBytes().length);
return sb.toString();
}
private static String getDigest(String input, String algorithm) throws Exception {
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
// 消息数字摘要
byte[] digest = messageDigest.digest(input.getBytes());
System.out.println("密文的字节长度:" + digest.length);
return toHex(digest);
}
}
输出结果:密文的字节长度:16
16进制数据的长度:32
4124bc0a9335c27f086f24ba207a4912
总结
- MD5算法 : 摘要结果16个字节, 转16进制后32个字节
- SHA1算法 : 摘要结果20个字节, 转16进制后40个字节
- SHA256算法 : 摘要结果32个字节, 转16进制后64个字节
- SHA512算法 : 摘要结果64个字节, 转16进制后128个字节
2非对称加密
简介:
① 非对称加密算法又称现代加密算法。
② 非对称加密是计算机通信安全的基石,保证了加密数据不会被破解。
③ 与对称加密算法不同,非对称加密算法需要两个密钥:公开密钥(publickey) 和私有密(privatekey)
④ 公开密钥和私有密钥是一对
⑤ 如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密。
⑥ 如果用私有密钥对数据进行加密,只有用对应的公开密钥才能解密。
⑦ 因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
- 示例
- 首先生成密钥对, 公钥为(5,14), 私钥为(11,14)
- 现在A希望将原文2发送给B
- A使用公钥加密数据. 2的5次方mod 14 = 4 , 将密文4发送给B
- B使用私钥解密数据. 4的11次方mod14 = 2, 得到原文2
- 特点
- 加密和解密使用不同的密钥
- 如果使用私钥加密, 只能使用公钥解密
- 如果使用公钥加密, 只能使用私钥解密
- 处理数据的速度较慢, 因为安全级别高
- 常见算法
- RSA
- ECC
代码实现
package com.fire.RSA;
import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.apache.commons.io.FileUtils;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class RSAdemo {
public static void main(String[] args) throws Exception{
String input="张飞";
String algorithm="RSA";
//generateKeyToFile(algorithm, "a.pub","a.pri");
PrivateKey privateKey=getPrivateKey("a.pri",algorithm);
PublicKey publicKey=getPublicKey("a.pub",algorithm);
String s = encryptRSA(algorithm, privateKey, input);
System.out.println(s);
String s1 = decryptRSA(algorithm, publicKey, s);
System.out.println(s1);
}
public static PublicKey getPublicKey(String pulickPath,String algorithm) throws Exception{
// 将文件内容转为字符串
String publicKeyString = FileUtils.readFileToString(new File(pulickPath), Charset.defaultCharset());
// 获取密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
// 构建密钥规范 进行Base64解码
X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
// 生成公钥
return keyFactory.generatePublic(spec);
}
public static PrivateKey getPrivateKey(String priPath,String algorithm) throws Exception{
// 将文件内容转为字符串
String privateKeyString = FileUtils.readFileToString(new File(priPath), Charset.defaultCharset());
// 获取密钥工厂
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
// 构建密钥规范 进行Base64解码
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
// 生成私钥
return keyFactory.generatePrivate(spec);
}
private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {
// 获取密钥对生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
// 获取密钥对
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 获取公钥
PublicKey publicKey = keyPair.getPublic();
// 获取私钥
PrivateKey privateKey = keyPair.getPrivate();
// 获取byte数组
byte[] publicKeyEncoded = publicKey.getEncoded();
byte[] privateKeyEncoded = privateKey.getEncoded();
// 进行Base64编码
String publicKeyString = Base64.encode(publicKeyEncoded);
String privateKeyString = Base64.encode(privateKeyEncoded);
// 保存文件
FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));
}
/**
* 解密数据
*
* @param algorithm : 算法
* @param encrypted : 密文
* @param key : 密钥
* @return : 原文
* @throws Exception
*/
public static String decryptRSA(String algorithm,Key key,String encrypted) throws Exception{
// 创建加密对象
// 参数表示加密算法
Cipher cipher = Cipher.getInstance(algorithm);
// 私钥进行解密
cipher.init(Cipher.DECRYPT_MODE,key);
// 由于密文进行了Base64编码, 在这里需要进行解码
byte[] decode = Base64.decode(encrypted);
// 对密文进行解密,不需要使用base64,因为原文不会乱码
byte[] bytes1 = cipher.doFinal(decode);
// System.out.println(new String(bytes1));
return new String(bytes1);
}
/**
* 使用密钥加密数据
*
* @param algorithm : 算法
* @param input : 原文
* @param key : 密钥
* @return : 密文
* @throws Exception
*/
public static String encryptRSA(String algorithm,Key key,String input) throws Exception{
// 创建加密对象
// 参数表示加密算法
Cipher cipher = Cipher.getInstance(algorithm);
// 初始化加密
// 第一个参数:加密的模式
// 第二个参数:使用私钥进行加密
cipher.init(Cipher.ENCRYPT_MODE,key);
// 私钥加密
byte[] bytes = cipher.doFinal(input.getBytes());
// 对密文进行Base64编码
// System.out.println(Base64.encode(bytes));
return Base64.encode(bytes);
}
}
总结:学好代码还是要多敲多看多写,这样遇到问题才能知道自己哪里是不会的。
相关推荐
- 前端 JavaScript 字符串中提取数字
-
varstr="4500元";varnum=parseInt(str);alert(num);//4500如果字符串前面有非数字字符,上面这种方法就不行了:var...
- 使用JavaScript如何获取网站网址(js如何获取浏览器信息)
-
在做网站开发时,我们有时候会获取当前页面的完整路径。在网页前端如何实现呢?请在网页脚本代码段中粘贴如下代码。functiongetRootPath(){//获取当前网址,...
- java文本对比工具源码8(java比较文本相似度)
-
/***ParseatextualrepresentationofpatchesandreturnaListofPatch*objects.*@paramtextline...
- JavaScript实现的9大排序算法(js排序方法)
-
笔试面试经常涉及各种算法,本文简要介绍常用的一些算法,并用JavaScript实现。1、插入排序1)算法简介插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通...
- 使用函数化的Javascript代码编写方式
-
对于Javascript介绍想必大家都耳熟能详啦,基于函数化的编程语言,基于浏览器运行的编程语言,web开发语言,前端开发必备语言,blablabla...Javascript是一个非常灵...
- Js基础31:内置对象(js内置对象是什么意思)
-
js里面的对象分成三大类:内置对象ArrayDateMath宿主对象浏览器提供的对象(如bom、dom等等)自定义对象开发人员自己定义的对象内置对象——所谓内置对象,就是JavaScript自...
- js获取上传文件类型以及大小的方法
-
前端web上传文件时,需要在上传之前判断一下文件的类型以及文件的大小,HTML为前端的标记语言是无法做到这一点,只能使用javascript动态脚本代码来实现。js获取上传文件大小的方法示例代码:&...
- 黑客入门实践:如何绕过前端过滤上传文件
-
今天开始,我们就要开始学习具体的漏洞了,但是希望大家学完后,不要轻易"入侵"网站哦,当时测试环境下除外。今天的课程是关于“文件上传漏洞”,据安界网的老师介绍,文件上传漏洞仅次于命令执行...
- Java文件上传细讲(java文件夹上传)
-
什么是文件上传?文件上传就是把用户的信息保存起来。为什么需要文件上传?在用户注册的时候,可能需要用户提交照片。那么这张照片就应该要进行保存。免费学习资料获取方式上传组件(工具)为什么我们要使用上传工具...
- 鸿蒙上实现“翻译”功能(鸿蒙宴全文翻译)
-
本章节我们来制作中文翻译成英文的实例(运行在HarmonyOS上),通过HTTP去配合API进行实现。需求分析如下:文字输入HTTP协议使用文字翻译控件介绍①HTTP数据请求官方文档请求...
- JavaScript从入门到精通(javascript 入门教程)
-
前几天,我们学习了JavaScript的入门课程,但是要想做网站,仅仅学会入门是不够的,今后的几天,我将带领大家精通JavaScript,希望大家好好学习!JS内置对象String对象:字符串对象,提...
- 第15天|16天搞定前端,javascript语法篇(干货)
-
JavaScript是互联网上最流行的脚本语言,这门语言可用于HTML和web,可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备。它是一个脚本语言,它是一个轻量级,但功能强大的编程...
- 通过js来实现打字效果(js如何输入)
-
有时候浏览网页经常会看见一些页面出现一些打字的效果,那么是怎么实现的呢?逻辑确定目标容器,在哪个容器进行输出确定输出内容,当前直接根据目标容器确定输出内容即可需要控制输出频率,因此需要循环输出完毕代码...
- 手把手教你学会一键还原混淆js原理
-
1.短变量名在以下示例代码中,我们将变量“customerName”替换为“a”:vara="JohnSmith";console.log(a);2.随机变量名在以下示例代码...
- sql中常用的字符串函数详解(sql字符串函数有哪些)
-
在日常开发中遇到处理最多的可能字符串要算其中一个了,什么替换啊截取啊大小写转换啊、删除空格啊等等,这些操作我们可以在前端操作,也可以直接在数据库的sql中操作,那么我们来看一下sql中处理字符串的...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)