SM3杂凑算法Python语言实现——第三部分
SM3杂凑算法实现——第三部分
一、SM3 密码概述
我们首先把需要用到的算法呈现出来,最后我们再考虑如何集合为一个库的方法,这一部分我们就开始编写一个新的算法:国家商用密码标准SM3密码算法。
首先要明白SM3是一个什么样的东西:单向加密算法。也可以称之为密码哈希算法、杂凑算法、摘要算法,都可以指这类算法。顾名思义,这类算法只能加密不能解密,所以不是为了直接保护数据的秘密性而存在的,不是让使用者解密这串密文得到原文而使用的。这类算法一般用于保护数据明文的完整性,抗篡改而产生。只要输入的是同样的明文,那么输出的密文(杂凑值/摘要值/哈希结果)就是一样的,而找到一个字符串与预期字符串的输出结果是一样的,这目前在理论上不可实现,也就是说在目前的技术前提下,还不能做到篡改原文还能保持摘要值不受影响的事情。这类算法比较出名的比如MD5,SHA-1代表的系列算法,但其中部分算法如MD5已经被证实并不安全,所以在实际使用过程中一定要使用当前核准的优秀加密算法!
密码杂凑算法在现代密码学中起着重要的作用,它将任意长度的消息压缩成固定长度的摘要。它是密码学3大基础算法之一(加密算法、数字签名算法和杂凑算法),用于数据的完整性校验、身份认证、数字签名、密钥推导、消息认证码和随机比特生成器等。
2012年,国家商用密码管理办公室发布了SM3密码杂凑算法为密码行业标准。2016年,国家标准化委员会公布了SM3密码杂凑算法为国家标准。目前SM3已经提交ISO国际标准化组织,进入DIS阶段。
二、SM3 详细设计
如所有的密码杂凑算法,SM3没有密钥这个概念,输入数据长度为任意,输出长度为32字节(256-bit)下面我们按步骤一点点看:
1.初始化常量
废话不多说,简单的定义:
IV = "\x73\x80\x16\x6f\x49\x14\xb2\xb9\x17\x24\x42\xd7\xda\x8a\x06\x00\xa9\x6f\x30\xbc\x16\x31\x38\xaa\xe3\x8d\xee\x4d\xb0\xfb\x0e\x4e"
T0_15 = "\x79\xcc\x45\x19"
T16_63 = "\x7a\x87\x9d\x8a"
其中T0_15表示CF模块中轮数0<=j<16时取用的值,T16_63表示轮数16<=j<64时取用的T值。IV为初始状态常量。
2.明文消息填充
对长度为l(l<2^64)比特的消息m,首先将比特'1'填充至消息末尾,再添加k个'0',其中k满足l+k+1===448 mod512,取最小非负整数。再添加一个64比特字符串,该比特串是长度l的二进制表示。这样,我们就把明文填充至512比特的倍数长度。
看不太明白?代码见!
3.迭代压缩结构
填充后的消息M就可以按照512bit进行分组啦!依次分为n个消息组,分别与初始常量IV按以下方式进行迭代:
FOR i=0 TO (n-1):
V[i+1] = CF( V[i] , B[i] );
ENDFOR
其中CF为压缩函数,V[0] = IV,B为填充后的消息分组,迭代的输出结果就是最后依次循环中被赋值的变量V[n]。
4.压缩函数
咱先不说那些复杂的公式,先看图理解一下,这个部分的结构比较庞大:
右半部分与序列密码中的部分很是相似,可以将原来的数据进行充分的混合,随着寄存器不停地进动,左端的信息会进入状态更新区内,与数据V进行混合运算,再次充分混淆。这样一来,每部分输出的信息V都是本段数据和之前所有数据共同运算的结果,可以代表这之前的数据是完整无修改的。公示详述如下:
将最后一轮产生的V进行输出,即得到杂凑值运算结果!
这里面显然有几个地方还没有定义,往下看:
5.布尔函数和置换函数
在CF压缩函数中涉及到的布尔函数和置换函数的详细定义描述为公式如下:
如此设计的布尔函数和置换函数让每个部分的数据都参与运算且运算效率极高,配合CF结构保证了运算的非线性特性明显。
至此,整个算法的介绍到此为止。
三、Python语言程序实现
# 数字格式转化
def int2str( num ) :
out = ""
out = out + chr( num//65536 ) + chr( (num%65536)//256 ) + chr( num%256 )
return out
def str2hex( string ):
out = ""
for i in range ( 0 , len(string) ):
out = out + " " + hex(ord( string[i] ))
return out
# 字符串异或运算,后面分别是字符串与、或、非运算
def strxor( message , key , len ):
out = ""
for i in range ( 0 , len ):
ch = ord(message[i]) ^ ord(key[i])
out = out + chr(ch)
return out
def strand( message , key , len ):
out = ""
for i in range ( 0 , len ):
ch = ord(message[i]) & ord(key[i])
out = out + chr(ch)
return out
def stror( message , key , len ):
out = ""
for i in range ( 0 , len ):
ch = ord(message[i]) | ord(key[i])
out = out + chr(ch)
return out
def strnot( string , len ) :
out = ""
for i in range ( 0 , len ) :
ch = ~ord(string[i])
out = out + chr(ch)
return out
# 字符串按比特向左移位
def strldc( string , bit ):
byte = bit // 8
bit = bit % 8
out = ""
if bit == 0 :
out = string[byte:] + string[:byte]
else :
reg = string[byte:] + string[:byte+1]
for i in range (0,len(reg)-1):
out = out + chr(((ord(reg[i])*(2**bit))+(ord(reg[i+1])//(2**(8-bit))))%256)
out = out[:len(string)]
return out
# 4字节模加运算
def stradd_4( str1 , str2 ) :
out = ""
num1 = ord(str1[0])*16777216+ord(str1[1])*65536+ord(str1[2])*256+ord(str1[3])
num2 = ord(str2[0])*16777216+ord(str2[1])*65536+ord(str2[2])*256+ord(str2[3])
add = (num1 + num2)%4294967296
out = out + chr(add//1677216) + chr((add%1677216)//65536) + chr((add%65536)//256) + chr(add%256)
return out
def functionFF( A , B , C , j ) :
if j < 16 :
FF = strxor( A , strxor( B , C , 4 ) , 4 )
if j > 15 :
FF = stror( stror( strand(A,B,4) , strand(A,C,4) , 4 ) , strand(B,C,4) , 4)
return FF
def functionGG( A , B , C , j ) :
if j<16 :
GG = strxor( A , strxor( B , C , 4 ) , 4 )
if j > 15 :
GG = stror( strand(A,B,4) , strand(strnot(A,4),C,4) , 4 )
return GG
def functionP( string , mode ) :
out = ''
if mode == 0 :
out = strxor( string , strxor( strldc(string,9) , strldc(string,17) , 4 ) , 4 )
if mode == 1 :
out = strxor( string , strxor( strldc(string,15) , strldc(string,23) , 4 ) , 4 )
return out
def functionCF( V , B ) :
for i in range (0,68) :
# 消息扩展过程
P = strxor( strxor( B[0:4] , B[28:32] , 4 ) , strldc( B[42:46] , 15 ) , 4)
Badd = strxor( P , strxor( B[40:44] , strldc(B[12:16],7) , 4 ) , 4 )
out1 = strxor( B[0:4] , B[16:20] , 4 )
out = B[0:4]
B = B[0:60] + Badd
# 状态更新过程
if i < 64 :
if i < 16 :
SS1 = strldc( stradd_4( strldc( V[0:4] , 12 ) , stradd_4( V[16:20] , strldc(T0_15,i%32) ) ) , 7 )
else :
SS1 = strldc( stradd_4( strldc( V[0:4] , 12 ) , stradd_4( V[16:20] , strldc(T16_63,i%32) ) ) , 7 )
SS2 = strxor( SS1 , strldc( V[0:4] , 12 ) , 4 )
TT1 = stradd_4( stradd_4( functionFF( V[0:4] , V[4:8] , V[8:12] , i ) , V[12:16] ) , stradd_4( SS2 , out1 ) )
TT2 = stradd_4( stradd_4( functionGG( V[16:20] , V[20:24] , V[24:28] , i ) , V[28:32] ) , stradd_4( SS1 , out ) )
V = strxor( V , TT1 + V[0:4] + strldc(V[4:8],9) + V[8:12] + functionP(TT2,0) + V[16:20] + strldc(V[20:24],19) + V[24:28] , 32 )
return V
IV = "\x73\x80\x16\x6f\x49\x14\xb2\xb9\x17\x24\x42\xd7\xda\x8a\x06\x00\xa9\x6f\x30\xbc\x16\x31\x38\xaa\xe3\x8d\xee\x4d\xb0\xfb\x0e\x4e"
T0_15 = "\x79\xcc\x45\x19"
T16_63 = "\x7a\x87\x9d\x8a"
plain = input( "请输入杂凑函数明文:" )
l = int2str( len(plain)*8 )
plain = plain + "\x80"
k = 56 - (len(plain)%64) - 1
plain = plain + "\x00"*k
plain = plain + l
print( "plain :" , str2hex(plain) )
for i in range ( 0 , len(plain)//64-1 ) :
IV = functionCF( IV , plain[64*l:64*l+64] )
hash_value = IV
print( " hash :" , str2hex(hash_value) )
下面附上程序运行的效果图:
由于SM3的功能不具备多样化特征,且代码长度短,这里暂不呈现SM3类的封装和使用过程,故代码方面的展示到此为止。
四、实现难点
杂凑算法一直以来没有尝试去实现过,也就是说这是作者第一次尝试去实现一个密码杂凑算法,刚开始做的时候压力还是很大的,但是随着算法步骤的一点点解读,才发现其中的内部结构并不复杂,都是由计算机基本运算组成的,但读懂文字解释的步骤还是相当有难度的。
论文依据:SM3密码杂凑算法——王小云、于红波。更多关于SM3密码的分析与设计细节详见论文。
SM3杂凑算法Python语言实现——第三部分的更多相关文章
- 毕业设计预习:SM3密码杂凑算法基础学习
SM3密码杂凑算法基础学习 术语与定义 1 比特串bit string 由0和1组成的二进制数字序列. 2 大端big-endian 数据在内存中的一种表示格式,规定左边为高有效位,右边为低有效位.数 ...
- 《数据结构与算法Python语言描述》习题第二章第三题(python版)
ADT Rational: #定义有理数的抽象数据类型 Rational(self, int num, int den) #构造有理数num/den +(self, Rational r2) #求出本 ...
- 《数据结构与算法Python语言描述》习题第二章第二题(python版)
ADT Date: #定义日期对象的抽象数据类型 Date(self, int year, int month, int day) #构造表示year/month/day的对象 difference( ...
- 《数据结构与算法Python语言描述》习题第二章第一题(python版)
题目:定义一个表示时间的类Timea)Time(hours,minutes,seconds)创建一个时间对象:b)t.hours(),t.minutes(),t.seconds()分别返回时间对象t的 ...
- 数据结构与算法 Python语言实现 第一章练习
说明:部分代码参考了Harrytsz的文章:https://blog.csdn.net/Harrytsz/article/details/86645857 巩固 R-1.1 编写一个Python函数 ...
- 数据结构算法C语言实现(三十二)--- 9.1静态查找表
一.简述 静态查找表又分为顺序表.有序表.静态树表和索引表.以下只是算法的简单实现及测试,不涉及性能分析. 二.头文件 /** author:zhaoyu date:2016-7-12 */ #inc ...
- 使用Python语言理解递归
递归 一个函数在执行过程中一次或多次调用其本身便是递归,就像是俄罗斯套娃一样,一个娃娃里包含另一个娃娃. 递归其实是程序设计语言学习过程中很快就会接触到的东西,但有关递归的理解可能还会有一些遗漏,下面 ...
- 数据结构与算法-Python/C(目录)
第一篇 基本概念 01 什么是数据结构 02 什么是算法 03 应用实例-最大子列和问题 第二篇 线性结构 01 线性表及其实现 02 堆栈 03 队列 04 应用实例-多项式加法运算 05 小白专场 ...
- 0.数据结构(python语言) 基本概念 算法的代价及度量!!!
先看思维导图: *思维导图有点简陋,本着循循渐进的思想,这小节的知识大多只做了解即可. *重点在于算法的代价及度量!!!查找资料务必弄清楚. 零.四个基本概念 问题:一个具体的需求 问题实例:针对问题 ...
随机推荐
- 近日测试发现所有Excel相关功能均会抛异常,查后发现与福昕阅读器不兼容
报这种错: System.Runtime.InteropServices.COMException (0x80010105): 服务器出现意外情况. (异常来自 HRESULT:0x80010105 ...
- java应用的优化【转】
XX银行网银系统是一套全新的对公业务渠道类系统,经过两年的建设,将逐步对外提供服务. 该系统融合了原来多个对公渠道系统,并发量是以前多个系统之和,吞吐量要求将大幅上升.为了使广大对公客户使用系统时获得 ...
- Java面试题复习笔记(Web方向)
1.Http中get和post请求的区别? 共同点:都是Http请求方式,用户可以通过不同的请求方式完成对资源(Url)的操作.具体来讲就是get一般用于获取/查询资源信息,post用于更新资源信息. ...
- 随机获取min和max之间的一个整数
// 随机获取min和max之间的一个整数 const randomNum = (Min, Max) => { let Range = Max - Min; let Rand = Math.ra ...
- Python内置函数之-property
property 是一个内置的装饰器函数,只在面向对象中使用 求一个圆的周长和面积 # 周长和面积都是通过类的方法得到from math import pi class Cricle: def __i ...
- CTeX入门出坑
终于出了入门坑.大致风格可以了.赶紧记下来. \documentclass{ctexbook} \usepackage{amsmath} \usepackage{amsfonts} \usepacka ...
- 一键配置高可用Hadoop集群(hdfs HA+zookeeper HA)
准备环境 3台节点,主节点 建议 2G 内存,两个从节点 1.5G内存, 桥接网络 关闭防火墙 配置ssh,让节点之间能够相互 ping 通 准备 软件放到 autoInstall 目录下,已存放 ...
- Cordova IOT Lesson002
hello index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"& ...
- python运算符——比较运算符
比较运算符的运算结果会得到一个bool类型,也就是逻辑判定,要么是真True,要不就是False 大于“>” 小于“<” 不说了,看看不等于,用“!=”表示.大于等于“>=”和小 ...
- Java设计模式之建造者模式(生成器模式)
建造者模式: 也叫生成器模式.用来隐藏复合对象的创建过程,他把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象. 总结一句就是封装一个对象的构造过程,并允许按步骤构造 ...