加密的原因:保证数据安全
加密必备要素:1、明文/密文 2、秘钥 3、算法
秘钥:在密码学中是一个定长的字符串、需要根据加密算法确定其长度
加密算法解密算法一般互逆、也可能相同
常用的两种加密方式:
对称加密:秘钥:加密解密使用同一个密钥、数据的机密性双向保证、加密效率高、适合加密于大数据大文件、加密强度不高(相对于非对称加密)
非对称加密:秘钥:加密解密使用的不同秘钥、有两个密钥、需要使用密钥生成算法生成两个秘钥、数据的机密性只能单向加密、如果想解决这个问题、双向都需要各自有一对秘钥、加密效率低、加密强度高
公钥:可以公开出来的密钥、公钥加密私钥解密
私钥:需要自己妥善保管、不能公开、私钥加密公钥解密
安全程度高:多次加密
按位异或运算
凯撒密码:加密方式 通过将铭文所使用的字母表按照一定的字数平移来进行加密
mod:取余
加密三要素:明文/密文(字母)、秘钥(3)、算法(向右平移3/-3)
安全常识:不要使用自己研发的算法、不要钻牛角尖、没必要研究底层实现、了解怎么应用;低强度的密码比不进行任何加密更危险;任何密码都会被破解;密码只是信息安全的一部分
保证数据的机密性、完整性、认证、不可否认性
计算机操作对象不是文字、而是由0或1排列而成的比特序列、程序存储在磁盘是二进制的字符串、为比特序列、将现实的东西映射为比特序列的操作称为编码、加密又称之为编码、解密称之为解码、根据ASCII对照表找到对应的数字、转换成二进制
三种对称加密算法:DES\3DES\ AES
DES:已经被破解、除了用它来解密以前的明文、不再使用
密钥长度为56bit/8、为7byte、每隔7个bit会设置一个用于错误检查的比特、因此实际上是64bit
分组密码(以组为单位进行处理):加密时是按照一个单位进行加密(8个字节/64bit为一组)、每一组结合秘钥通过加密算法得到密文、加密后的长度不变
3DES:三重DES为了增加DES的强度、将DES重复三次所得到的一种加密算法 密钥长度24byte、分成三份 加密--解密--加密 目的:为了兼容DES、秘钥1秘钥2相同==三个秘钥相同 ---加密一次 密钥1秘钥3相同--加密三次 三个密钥不相同最好、此时解密相当于加密、中间的一次解密是为了有三个密钥相同的情况
此时的解密操作与加密操作互逆,安全、效率低
数据先解密后加密可以么?可以、解密相当于加密、加密解密说的是算法
AES:(首选推荐)底层算法为Rijndael 分组长度为128bit、密钥长度为128bit到256bit范围内就可以 但是在AES中、密钥长度只有128bit\192bit\256bit 在go提供的接口中、只能是16字节(128bit)、其他语言中秘钥可以选择
目前为止最安全的、效率高
底层算法
分组密码的模式:
按位异或、对数据进行位运算、先将数据转换成二进制、按位异或操作符^、相同为真、不同为假、非0为假 按位异或一次为加密操作、按位异或两次为解密操作:a和b按位异或一次、结果再和b按位异或
ECB : 如果明文有规律、加密后的密文有规律不安全、go里不提供该接口、明文分组分成固定大小的块、如果最后一个分组不满足分组长度、则需要补位
CBC:密码链
问题:如何对字符串进行按位异或?解决了ECB的规律可查缺点、但是他不能并行处理、最后一个明文分组也需要填充 、初始化向量长度与分组长度相同
CFB:密文反馈模式
不需要填充最后一个分组、对密文进行加密
OFB:
不需要对最后一组进行填充
CTR计数器:
不需要对最后一组进行填充、不需要初始化向量
Go中的实现
官方文档中:
在创建aes或者是des接口时都是调用如下的方法、返回的block为一个接口
func NewCipher(key [] byte ) ( cipher . Block , error )
type Block interface {
// 返回加密字节块的大小
BlockSize() int
// 加密src的第一块数据并写入dst,src和dst可指向同一内存地址
Encrypt(dst, src []byte)
// 解密src的第一块数据并写入dst,src和dst可指向同一内存地址
Decrypt(dst, src []byte)
}
Block接口代表一个使用特定密钥的底层块加/解密器。它提供了加密和解密独立数据块的能力。
Block的Encrypt/Decrypt也能进行加密、但是只能加密第一组、因为aes的密钥长度为16、所以进行操作的第一组数据长度也是16
如果分组模式选择的是cbc
func NewCBCEncrypter(b Block, iv []byte) BlockMode 加密
func NewCBCDecrypter(b Block, iv []byte) BlockMode 解密
加密解密都调用同一个方法CryptBlocks()
并且cbc分组模式都会遇到明文最后一个分组的补充、所以会用到加密字节的大小
返回一个密码分组链接模式的、底层用b加密的BlockMode接口,初始向量iv的长度必须等于b的块尺寸。iv自己定义
返回的BlockMode同样也是一个接口类型
type BlockMode interface {
// 返回加密字节块的大小
BlockSize() int
// 加密或解密连续的数据块,src的尺寸必须是块大小的整数倍,src和dst可指向同一内存地址
CryptBlocks(dst, src []byte)
}
BlockMode接口代表一个工作在块模式(如CBC、ECB等)的加/解密器
返回的BlockMode其实是一个cbc的指针类型中的b和iv
# 加密流程:
1. 创建一个底层使用des/3des/aes的密码接口 "crypto/des" func NewCipher(key []byte) (cipher.Block, error) # -- des func NewTripleDESCipher(key []byte) (cipher.Block, error) # -- 3des "crypto/aes" func NewCipher(key []byte) (cipher.Block, error) # == aes
2. 如果使用的是cbc/ecb分组模式需要对明文分组进行填充
3. 创建一个密码分组模式的接口对象 - cbc func NewCBCEncrypter(b Block, iv []byte) BlockMode # 加密 - cfb func NewCFBEncrypter(block Block, iv []byte) Stream # 加密 - ofb - ctr
4. 加密, 得到密文
流程:
填充明文:
先求出最后一组中的字节数、创建新切片、长度为新切片、值也为切片的长度、然后利用bytes.Reapet将长度换成字节切片、追加到原明文中
//明文补充
func padPlaintText(plaintText []byte,blockSize int)[]byte{
//1、求出需要填充的个数
padNum := blockSize-len(plaintText) % blockSize
//2、对填充的个数进行操作、与原明文进行合并
newPadding := []byte{byte(padNum)}
newPlain := bytes.Repeat(newPadding,padNum)
plaintText = append(plaintText,newPlain...)
return plaintText
}
去掉填充数据:
拿去切片中的最后一个字节、得到尾部填充的字节个数、截取返回
//解密后的明文曲调补充的地方
func createPlaintText(plaintText []byte,blockSize int)[]byte{
//1、得到最后一个字节、并将字节转换成数字、去掉明文中此数字大小的字节
padNum := int(plaintText[len(plaintText)-1])
newPadding := plaintText[:len(plaintText)-padNum]
return newPadding
}
des加密:
1、创建一个底层使用des的密码接口、参数为秘钥、返回一个接口
2、对明文进行填充
3、创建一个cbc模式的接口、需要创建iv初始化向量、返回一个blockmode对象
4、加密、调用blockmode中的cryptBlock函数进行加密、参数为目标参数和源参数
//des利用分组模式cbc进行加密
func EncryptoText(plaintText []byte,key []byte)[]byte{
//1、创建des对象
cipherBlock,err := des.NewCipher(key)
if err != nil {
panic(err)
}
//2、对明文进行填充
newText := padPlaintText(plaintText,cipherBlock.BlockSize())
//3、选择分组模式、其中向量的长度必须与分组长度相同
iv := make([]byte,cipherBlock.BlockSize())
blockMode := cipher.NewCBCEncrypter(cipherBlock,iv)
//4、加密
blockMode.CryptBlocks(newText,newText)
return newText
}
des解密:
1、创建一个底层使用des的密码接口、参数为秘钥、返回一个接口
2、创建一个cbc模式的接口、需要创建iv初始化向量,返回一个blockmode对象
3、加密、调用blockmode中的cryptBlock函数进行解密、参数为目标参数和源参数
4、调用去掉填充数据的方法
//des利用分组模式cbc进行解密
func DecryptoText(cipherText []byte, key []byte)[]byte{
//1、创建des对象
cipherBlock,err := des.NewCipher(key)
if err != nil {
panic(err)
}
//2、创建cbc分组模式接口
iv := []byte("12345678")
blockMode := cipher.NewCBCDecrypter(cipherBlock,iv)
//3、解密
blockMode.CryptBlocks(cipherText,cipherText)
//4、将解密后的数据进行去除填充的数据
newText := clearPlaintText(cipherText,cipherBlock.BlockSize())
return newText
}
Main函数调用
func main(){
//需要进行加密的明文
plaintText := []byte("CBC--密文没有规律、经常使用的加密方式,最后一个分组需要填充,需要初始化向量" +
"(一个数组、数组的长度与明文分组相等、数据来源:负责加密的人提供,加解密使用的初始化向量必须相同)")
//密钥Key的长度需要与分组长度相同、且加密解密的密钥相同
key := []byte("1234abcd")
//调用加密函数
cipherText := EncryptoText(plaintText,key)
newPlaintText := DecryptoText(cipherText,key)
fmt.Println(string(newPlaintText))
}
AES加密解密相同、所以只需要调用一次方法就可以加密、调用两次则解密
推荐是用分组模式:cbc、ctr
aes利用分组模式cbc进行加密
//对明文进行补充
func paddingPlaintText(plaintText []byte , blockSize int ) []byte {
//1、求出分组余数
padNum := blockSize - len(plaintText) % blockSize
//2、将余数转换为字节切片、然后利用bytes.Repeat得出有该余数的大小的字节切片
padByte := bytes.Repeat([]byte{byte(padNum)},padNum)
//3、将补充的字节切片添加到原明文中
plaintText = append(plaintText,padByte...)
return plaintText
}
//aes加密
func encryptionText(plaintText []byte, key []byte) []byte {
//1、创建aes对象
block,err := aes.NewCipher(key)
if err != nil {
panic(err)
}
//2、明文补充
newText := paddingPlaintText(plaintText,block.BlockSize())
//3、创建cbc对象
iv := []byte("12345678abcdefgh")
blockMode := cipher.NewCBCEncrypter(block,iv)
//4、加密
blockMode.CryptBlocks(newText,newText)
return newText
}
//解密后的去尾
func clearplaintText(plaintText []byte, blockSize int) []byte {
//1、得到最后一个字节、并转换成整型数据
padNum := int(plaintText[len(plaintText)-1])
//2、截取明文字节中去掉得到的整型数据之前的数据、此处出错、没有用len-padNum
newText := plaintText[:len(plaintText)-padNum]
return newText
}
//aes解密
func deCryptionText(crypherText []byte, key []byte ) []byte {
//1、创建aes对象
block, err := aes.NewCipher(key)
if err != nil {
panic(err)
}
//2、创建cbc对象
iv := []byte("12345678abcdefgh")
blockMode := cipher.NewCBCDecrypter(block,iv)
//3、解密
blockMode.CryptBlocks(crypherText,crypherText)
//4、去尾
newText := clearplaintText(crypherText,block.BlockSize())
return newText
}
func main(){
//需要进行加密的明文
plaintText := []byte("CBC--密文没有规律、经常使用的加密方式,最后一个分组需要填充,需要初始化向量")
//密钥Key的长度需要与分组长度相同、且加密解密的密钥相同
key := []byte("12345678abcdefgh")
//调用加密函数
cipherText := encryptionText(plaintText,key)
//调用解密函数
newPlaintText := deCryptionText(cipherText,key)
fmt.Println("解密后",string(newPlaintText))
}
//aes--ctr加密
func encryptionCtrText(plaintText []byte, key []byte) []byte {
//1、创建aes对象
block,err := aes.NewCipher(key)
if err != nil {
panic(err)
}
//2、创建ctr对象,虽然ctr模式不需要iv,但是go中使用ctr时还是需要iv
iv := []byte("12345678abcdefgh")
stream := cipher.NewCTR(block,iv)
stream.XORKeyStream(plaintText,plaintText)
return plaintText
}
func main() {
//aes--ctr加密解密、调用两次即为解密、因为加密解密函数相同stream.XORKeyStream
ctrcipherText := encryptionCtrText(plaintText, key)
ctrPlaintText := encryptionCtrText(ctrcipherText,key)
fmt.Println("aes解密后", string(ctrPlaintText))
}
英文单词:
明文:plaintext 密文:ciphertext 填充:padding/fill 去掉clear 加密Encryption 解密Decryption
漫画:什么是加密算法?
非常朴素的加密方法,被称为 凯撒密码
加密算法可以归结为三大类: 哈希算法 、 对称加密算法 、 非对称加密算法 。
哈希算法
从严格意义上来说, 哈希算法并不属于加密算法 ,但它在信息安全领域起到了很重要的作用。(MD5是单向生成信息摘要的算法)
哈希算法能做什么用呢?其中一个重要的作用就是 生成信息摘要 ,用以验证原信息的完整性和来源的可靠性。
对称加密算法
哈希算法可以解决验签的问题,却无法解决明文加密的问题。这时候,就需要真正的加密算法出场了。
非对称加密算法
windows下查看文件的MD5码
或者使用 HashMyFiles.exe 工具可以生成文件md5.: Calculate MD5/SHA1/CRC32 hash of files
2020年6月15日,《自然》杂志发表了我国科研团队,用“墨子号”量子科学实验卫星,成功实现千公里级别的,纠缠态量子密钥分发的相关研究成果。
该项成果,意味着量子纠缠加密通信,这一“绝对无法被窃听”的技术,又被我国“修炼”的更加精进了。
那么
量子纠缠,是怎样确保己方信息绝对安全的?
又是怎样让己方信息,在被窃听的瞬间,自动作出反应的?
为什么说,量子纠缠加密过后的信息,从本质上就无法破解?
1935年,爱因斯坦,波多尔斯基,罗森,三位物理学家发表了后来被称为,EPR实验的论文,在该论文中,爱因斯坦根据量子力学的,叠加率和守恒率,认为如果把两个电子看成一个系统,那么这两个电子不论距离多远,就都还得满足守恒律。
也就是说,哪怕这两个电子相隔千万光年,他们之间的状态仍然会实时传递,要坍塌就一起坍塌。
且整个过程是无视光速的,而在当时以及今天的物理学界,真空光速,都是物质和信息传递速度的上限。
爱因斯坦在论文中指出的,这种鬼魅般的超距作用,被薛定谔看到之后,后者将这种理论现象,命名量子纠缠。
量子纠缠这种“瞬时”的特性,让它成为后来很多科幻作品中的常客,比如《三体》中的智子,就是利用量子纠缠,实现4.22光年外的比邻星,和地球的实时通信的。
但事实上,量子纠缠的“反应速度”虽然千万亿倍于光速,但处于纠缠态的量子之间,是不可能传递信息的,因为“纠缠”是一种特性,而不是一种可以被用来传输信息的规律。
今天的人类对量子纠缠的唯一应用,就是将它作为“最顶级的加密手段”
毕竟从最初的凯撒密码,到后来的恩尼格玛,加密技术都直接影响信息安全,而信息安全又影响着,人类之间一切竞争行为的胜负。
量子纠缠加密,就是将原来基于数学的加密密钥,替换为基于量子力学的“量子纠缠密钥”,这样一来信息的发送端和接收端,将共享同一个“稳定”的量子态,如果在信息的传送过程中出现窃听者,那么发送端和接收端的量子态,就将同时坍塌。
如此一来,信息的两端就都知道了窃听者的存在,并且量子状态崩溃之后,窃听者也无法再继续获取数据信息。
需要再次重申的是,在以上的整个过程中,量子纠缠仅仅是作为密钥存在的,它是一种加密手段,而不是承载信息的载体。
真正用来传递信息的,仍然是人类早已使用了数个世纪的无线电波。
量子纠缠加密的成功,归根结底,还是因为量子态的坍塌,毕竟在现有的理论体系中,量子态就是最敏感的状态,只要存在观察者,量子态就能马上做出反应。
在堪称《三体》前传的《球状闪电》结尾,人类曾在废弃的地下矿井中,进行过“没有人类观察者”的量子力学实验,但量子态依旧坍塌了,书中给出的结果是“存在非人类的观察者”,而不少科幻迷都认为,这个“非人类观察者”,就是三体文明派来的智子。
总体而言
量子力学作为目前微观世界的扛把子理论,在科学和科幻上都有很大的“戏份”,而且今天的各类芯片,本质上也都是以量子力学理论为基础的,就像人造卫星以相对论为基础一样。
在可以预见的未来,量子力学的蓬勃发展,以及关于它的各项应用,必将再次改变人类世界,就像曾经的世界,被计算机和芯片技术改变一样。
摘要:密码学从古至今的发展历史,发展过程成中各个阶段的发展情况。
以及各个阶段密码学的经典密码以及代表人物,与其在历史上的标志性成果。
关键词:古典密码;密码学发展;加密技术
随着信息化和数字化社会的发展,人们对信息安全和保密的重要性认识不断提高,而在信息安全中起着举足轻重作用的密码学也就成为信息安全课程中不可或缺的重要部分,密码学是以研究秘密通信为目的,即对所要传送的信息采取一种秘密保护,以防止 第三者对信息的窃取的一门学科。
密码学早在公元前400多年就已经产生,人类使用密码的历史几乎与使用文字的时间一样长。
密码学的发展过程可以分为四个阶段:1、古代加密方法。
2、古典密码。
3、近代密码 。
4、现代密码。
一、古代加密方法
源于应用的无穷需求总是推动技术发明和进步的直接动力。
存于石刻或史书中的记载表明,许多古代文明,包括埃及人、希伯来人、亚述人都在实践中逐步发明了密码系统。
从某种意义上说,战争是科学技术进步的催化剂。
人类自从有了战争,就面临着通信安全的需求,密码技术源远流长。
古代加密方法大约起源于公元前400年,斯巴达人发明了“塞塔式密码”,即把长条纸螺旋形地斜绕在一个多棱棒上,将文字沿棒的水平方向从左到右书写,写一个字旋转一下,写完一行再另起一行从左到右写,直到写完。
解下来后,纸条上的文字消息杂乱无章、无法理解,这就是密文,但将它绕在另一个同等尺寸的棒子上后,就能看到原始的消息。
这是最早的密码技术。
我国古代也早有以藏头诗、藏尾诗、漏格诗及绘画等形式,将要表达的真正意思或“密语”隐藏在诗文或画卷中特定位置的记载,一般人只注意诗或画的表面意境,而不会去注意或很难发现隐藏其中的“话外之音”。
如《水浒传》中梁山为了拉卢俊义入伙,“智多星”吴用和宋江便生出一段“吴用智赚玉麒麟”的故事来,利用卢俊义正为躲避“血光之灾”的惶恐心理,口占四句卦歌:
芦花丛中一扁舟, 俊杰俄从此地游。
义士若能知此理, 反躬难逃可无忧。
暗藏“卢俊义反”四字。
结果,成了官府治罪的证据,终于把卢俊义“逼”上了梁山。
更广为人知的是唐伯虎写的“我爱秋香”: 我画蓝江水悠悠, 爱晚亭上枫叶愁。
秋月溶溶照佛寺, 香烟袅袅绕经楼。
二、古典密码
古典密码的加密方法一般是文字置换,使用手工或机械变换的方式实现。
古典密码系统已经初步体现出近代密码系统的雏形,它比古代加密方法复杂,其变化较小。
下面我们举例说一些比较经典的古典密码。
1.滚桶密码
在古代为了确保他们的通信的机密,先是有意识的使用一些简单的方法对信息来加密。
如公元六年前的古希腊人通过使用一根叫scytale的棍子,将信息进行加密。
送信人先将一张羊皮条绕棍子螺旋形卷起来,然后把要写的信息按某种顺序写在上面,接着打开羊皮条卷,通过其他渠道将信送给收信人。
如果不知道棍子的粗细是不容易解密里面的内容的,但是收信人可以根据事先和写信人的约定,用同样的scytale的棍子将书信解密。
2.掩格密码
16世纪米兰的物理学和数学家Cardano发明的掩格密码,可以事先设计好方格的开孔,将所要传递的信息和一些其他无关的符号组合成无效的信息,使截获者难以分析出有效信息。
3. 棋盘密码
我们可以建立一张表,使每一个字符对应一数 , 是该字符所在行标号, 是列标号。
这样将明文变成形式为一串数字密文。
4.凯撒(Caesar)密码
据记载在罗马帝国时期,凯撒大帝曾经设计过一种简单的移位密码,用于战时通信。
这种加密方法就是将明文的字母按照字母顺序,往后依次递推相同的字母,就可以得到加密的密文,而解密的过程正好和加密的过程相反。