#加密

0 关注者 · 6 帖子

在密码学中,加密是一种对消息或信息进行编码的过程,以便只有授权方可以访问,而未经授权方不能访问。

文章 Yongfeng Hou · 十一月 23, 2023 3m read

        IRISHealth以其完备且系统化的安全特性在医疗行业的数据库中独树一帜,这些特性包括安全认证、安全授权、安全审计、数据加密以及安全配置。其中数据传输无疑是其中最重要的一环。为此,IRISHealth采用了SSL/TLS技术来对传输的数据进行加密,有效保障了从IRIS数据平台的超级服务数据传输、Telnet服务数据传输、java/.net/Studio客户端的访问数据传输、MIRROR与DB的数据传输,到DBServer和ECPApp之间的数据传输的安全性。


        本文是在两个IRISHealth2021实例之间进行ECP服务通信的示例,一个作为DBServer,一个作为ECPApp,两个实例之间通过使用SSL/TLS的ECP协议进行TCP的加密传输通信。

1.IRIS的DB和ECP环境:

DBServer 

ECPApp

10.1.30.231  10.1.30.232

 

2. CA证书的环境:

5
3 380
文章 shaosheng shengshao · 九月 14, 2022 3m read

 在AES的加密过程中,存在HEX和Base64的输出,目前在HEALTHSHARE自带有Base64的加解密规则,现在针对HEX的加解密进行对应的处理,实现和网上ASE加解密工具进行互相加解密。
在Ensemble的AES的CBC加密主要用到的是这俩个方法
$system.Encryption.AESCBCManagedKeyEncrypt(Plaintext,KeyID)
Plaintext是需要加密的字符串,需要进行$ZCONVERT(字符串,"O","UTF8")转换
KeyID是密钥的ID。
或者是
$SYSTEM.Encryption.AESCBCEncrypt(text,key,IV)
text是需要加密的字符串,需要进行$ZCONVERT(text,"O","UTF8")转换
Key 是密钥 键的长度必须为16、24或32个字符
IV  是偏移量 如果存在此参数,则必须为16个字符长。

第一个方法是在本地生成对应的密钥,暂时还不能和网站上的进行互相加解密的处理。
目前主要是针对第二个方法
$SYSTEM.Encryption.AESCBCEncrypt(text,key,IV)

8
1 637
文章 YuHao Wan · 十一月 5, 2022 7m read

0. 算法概述

SM4算法是一种分组密码算法。其分组长度为128bit,密钥长度也为128bit。加密算法与密钥扩展算法均采用32轮非线性迭代结构,以字(32位)为单位进行加密运算,每一次迭代运算均为一轮变换函数F。SM4算法加/解密算法的结构相同,只是使用轮密钥相反,其中解密轮密钥是加密轮密钥的逆序。

1. 密钥及轮密钥

密钥长度为128比特,表示为MK=(MK(0),MK(1),MK(2),MK(3)),其中MKi(i=0,1,2,3)为字。 轮密钥表示为(rk(0),rk(1),...,rk(31)),其中rk(i)(i=0,...,31)为32比特字。轮密钥由秘钥生成。

密钥及轮密钥

2. 消息填充分组

首先,将明文转化为字节,由于SM4加密算法按照128个位进行分组,所以很大几率会出现最后一个分组不够128位的情况,需要进行填充,填充方式有很多,比如ZeroPadding、PKCS7Padding、PKCS5Padding,不管使用哪种方式,最后每个分组都是128位。每个分组按照32位一个字分成四个字。

ECB模式与CBC模式

  • ECB模式 电子密码本模式,最古老,最简单的模式,将加密的数据分成若干组,每组的大小跟加密密钥相同。不足的部分进行填充。 按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。

    优点:简单,有利于并行计算,误差不会被传递。

    缺点:不能隐藏明文的模式,可能对明文进行主动攻击。

  • CBC模式

    密文分组链接模式,也需要进行分组,不足的部分按照指定的数据进行填充。

    需要一个初始化向量,每个分组数据与上一个分组数据加密的结果进行异或运算,最后再进行加密。将所有分组加密的结果连接起来就形成了最终的结果。

    优点:不容易进行主动攻击,安全性好于ECB。

    缺点:不利于并行计算,误差传递,需要初始化向量。

三种填充方式的比较

某些加密算法要求明文需要按一定长度对齐,叫做块大小(BlockSize),比如16字节,那么对于一段任意的数据,加密前需要对最后一个块填充到16 字节,解密后需要删除掉填充的数据。

  • ZeroPadding,数据长度不对齐时使用0填充,否则不填充。

  • PKCS7Padding,假设数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都是n;如果数据本身就已经对齐了,则填充一块长度为块大小的数据,每个字节都是块大小。

  • PKCS5Padding,PKCS7Padding的子集,块大小固定为8字节。

由于使用PKCS7Padding/PKCS5Padding填充时,最后一个字节肯定为填充数据的长度,所以在解密后可以准确删除填充的数据,而使用ZeroPadding填充时,没办法区分真实数据与填充数据,所以只适合以\0结尾的字符串加解密。

3. 迭代运算

本加解密算法由32次迭代运算和1次反序变换R组成。

迭代运算

3.1 轮函数F和合成置换T

轮函数和合成置换T

4. Caché实现

/// SM4算法是一种分组密码算法。其分组长度为128bit,密钥长度也为128bit。
/// 加密算法与密钥扩展算法均采用32轮非线性迭代结构,以字(32位)为单位进行加密运算,每一次迭代运算均为一轮变换函数F。
/// SM4算法加/解密算法的结构相同,只是使用轮密钥相反,其中解密轮密钥是加密轮密钥的逆序。
/// 本方法适用于 ECB模式,ZeroPadding填充模式
Class Utility.SM4 Extends %RegisteredObject
{

/// Creator:    wyh
/// CreatDate:  2022-11-03
/// Description:SM4加密
/// Input:  	 msg:原文 mk:128位密钥
/// Output:     密文
/// Debug: w ##class(Utility.SM4).Encrypt("342622199009262982", "F2D8D966CD3D47788449C19D5EF2081B")
ClassMethod Encrypt(msg, mk)
{
#;	1. 密钥及轮密钥
#;	a) 密钥长度为128比特,表示为MK=(MK(0),MK(1),MK(2),MK(3)),其中MKi(i=0,1,2,3)为字
#;	b) 轮密钥表示为(rk(0),rk(1),...,rk(31)),其中rk(i)(i=0,...,31)为32比特字。轮密钥由密钥生成。
#;	   密钥扩展算法:
#;	   (K(0),K(1),K(2),K(3))=(MK(0)^FK(0),MK(1)^FK(1),MK(2)^FK(2),MK(3)^FK(3))
#;	   rk(i)=K(i+4)=K(i)^T'(K(i+1)^K(i+2)^K(i+3)^CK(i)),i=0,1,...,31
#;	   系统参数FK(0)=(A3B1BAC6),FK(1)=(56AA3350),FK(2)=(677D9197),FK(3)=(B27022DC)
#;	   固定参数CK(i)(i=0,1,...,31)为:
#;	   00070E15, 1C232A31, 383F464D, 545B6269, 
#;	   70777E85, 8C939AA1, A8AfB6BD, C4CBD2D9, 
#;	   E0E7EEF5, FC030A11, 181F262D, 343B4249, 
#;	   50575E65, 6C737A81, 888F969D, A4ABB2B9, 
#;	   C0C7CED5, DCE3EAF1, F8FF060D, 141B2229, 
#;	   30373E45, 4C535A61, 686F767D, 848B9299, 
#;	   A0A7AEb5, BCC3CAD1, D8DFE6ED, F4FB0209, 
#;	   10171E25, 2C333A41, 484F565D, 646B7279.
	s mk = $zcvt(mk, "L")
	f i = 0 : 1 : 3 d
	.s MK(i) = $e(mk, 8 * i + 1, 8 * (i + 1))

	s FK = "a3b1bac656aa3350677d9197b27022dc"
	f i = 0 : 1 : 3 d
	.s FK(i) = $e(FK, 8 * i + 1, 8 * (i + 1))
	
	s CK = "00070e151c232a31383f464d545b626970777e858c939aa1a8afb6bdc4cbd2d9e0e7eef5fc030a11181f262d343b424950575e656c737a81888f969da4abb2b9c0c7ced5dce3eaf1f8ff060d141b222930373e454c535a61686f767d848b9299a0a7aeb5bcc3cad1d8dfe6edf4fb020910171e252c333a41484f565d646b7279"
	f i = 0 : 1 : 31 d
	.s CK(i) = $e(CK, 8 * i + 1, 8 * (i + 1))
	
	f i = 0 : 1 : 3 d
    .s K(i) = ..HexXOR(MK(i), FK(i))
   	f i = 4 : 1 : 35 d
   	.s K(i) = ..HexXOR(K(i - 4), ..T2(..HexXOR(..HexXOR(..HexXOR(K(i + 1 - 4), K(i + 2 - 4)),K(i + 3 - 4)), CK(i - 4))))
   	
   	f i = 0 : 1 : 31 d
   	.s rk(i) = K(i + 4)
	
#;	2. 消息填充分组
#;	每组128位,每组再分X(0),X(1),X(2),X(3)作为明文输入.
	s hex = ..s2hex(msg)
	s len = $l(hex)/32
	s rtn = ""
	f i = 0 : 1 : len-1 d
	.k X
	.s M(i) = $e(hex, 32 * i + 1, 32 * (i + 1))
	.f j = 0 : 1 : 3 d
	..s X(j) = $e(M(i), 8 * j + 1, 8 * (j + 1))
	
#;	3. 迭代运算,密文输出(Y(0),Y(1),Y(2),Y(3))
#;	a) 32次迭代运算
#;	X(i+4)=F(X(i),X(i+1),X(i+2),X(i+3),rk(i)),i=0,1,...,31
#;	F(X(i),X(i+1),X(i+2),X(i+3),rk(i))=X(i)^T(X(i+1)^X(i+2)^X(i+3)^rk(i)),i=0,1,...,31
#;	b)反序变换
#;	(Y(0),Y(1),Y(2),Y(3))=R(X(32),X(33),X(34),X(35))=(X(35),X(34),X(33),X(32))
	.f k = 0 : 1 : 31 d
	..s X(k + 4) = ..HexXOR(X(k), ..T(..HexXOR(..HexXOR(..HexXOR(X(k + 1), X(k + 2)), X(k + 3)), rk(k))))
	.s rtn = rtn_X(35)_X(34)_X(33)_X(32)

	q rtn
}

/// Creator:    wyh
/// CreatDate:  2022-11-03
/// Description:SM4解密
/// 解密变换与加密变换结构相同,不同的仅是轮密钥的使用顺序,解密时使用轮密钥序(rk(31),rk(32),...,rk(0)).
/// Input:  	 hex:密文 mk:128位密钥
/// Output:     明文
/// Debug: w ##class(Utility.SM4).Decrypt("5efcbbfdb7a326b340295acb1c0e20fe2622730932bdb5302b5a4ee308944ecc", "F2D8D966CD3D47788449C19D5EF2081B")
ClassMethod Decrypt(hex, mk)
{
	s mk = $zcvt(mk, "L")
	f i = 0 : 1 : 3 d
	.s MK(i) = $e(mk, 8 * i + 1, 8 * (i + 1))
	
	s FK = "a3b1bac656aa3350677d9197b27022dc"
	f i = 0 : 1 : 3 d
	.s FK(i) = $e(FK, 8 * i + 1, 8 * (i + 1))
	
	s CK = "00070e151c232a31383f464d545b626970777e858c939aa1a8afb6bdc4cbd2d9e0e7eef5fc030a11181f262d343b424950575e656c737a81888f969da4abb2b9c0c7ced5dce3eaf1f8ff060d141b222930373e454c535a61686f767d848b9299a0a7aeb5bcc3cad1d8dfe6edf4fb020910171e252c333a41484f565d646b7279"
	f i = 0 : 1 : 31 d
	.s CK(i) = $e(CK, 8 * i + 1, 8 * (i + 1))
	
	f i = 0 : 1 : 3 d
    .s K(i) = ..HexXOR(MK(i), FK(i))
   	f i = 4 : 1 : 35 d
   	.s K(i) = ..HexXOR(K(i - 4), ..T2(..HexXOR(..HexXOR(..HexXOR(K(i + 1 - 4), K(i + 2 - 4)),K(i + 3 - 4)), CK(i - 4))))
   	
   	f i = 0 : 1 : 31 d
   	.s rk(i) = K(35 - i)
	
	s len = $l(hex)/32
	s rtn = ""
	f i = 0 : 1 : len-1 d
	.k X
	.s M(i) = $e(hex, 32 * i + 1, 32 * (i + 1))
	.f j = 0 : 1 : 3 d
	..s X(j) = $e(M(i), 8 * j + 1, 8 * (j + 1))

	.f k = 0 : 1 : 31 d
	..s X(k + 4) = ..HexXOR(X(k), ..T(..HexXOR(..HexXOR(..HexXOR(X(k + 1), X(k + 2)), X(k + 3)), rk(k))))
	.s rtn = rtn_X(35)_X(34)_X(33)_X(32)
	
	q ..hex2str(rtn)
}

/// 非线性变换τ构成
/// τ由4个并行的S盒,设输入A=(a0,a1,a2,a3),输出为B=(b0,b1,b2,b3)
/// (b0,b1,b2,b3)=τ(A)=(Sbox(a0),Sbox(a1),Sbox(a2),Sbox(a3))
/// w ##class(Utility.SM4).tau("942600f0")
ClassMethod tau(a)
{
	f i = 0 : 1 : 7 d
	.s a(i) = $e(a, i + 1)
	
	s s(0) = "d690e9fecce13db716b614c228fb2c05"
	s s(1) = "2b679a762abe04c3aa44132649860699"
	s s(2) = "9c4250f491ef987a33540b43edcfac62"
	s s(3) = "e4b31ca9c908e89580df94fa758f3fa6"
	s s(4) = "4707a7fcf37317ba83593c19e6854fa8"
	s s(5) = "686b81b27164da8bf8eb0f4b70569d35"
	s s(6) = "1e240e5e6358d1a225227c3b01217887"
	s s(7) = "d40046579fd327524c3602e7a0c4c89e"
	s s(8) = "eabf8ad240c738b5a3f7f2cef96115a1"
	s s(9) = "e0ae5da49b341a55ad933230f58cb1e3"
	s s(10) = "1df6e22e8266ca60c02923ab0d534e6f"
	s s(11) = "d5db3745defd8e2f03ff6a726d6c5b51"
	s s(12) = "8d1baf92bbddbc7f11d95c411f105ad8"
	s s(13) = "0ac13188a5cd7bbd2d74d012b8e5b4b0"
	s s(14) = "8969974a0c96777e65b9f109c56ec684"
	s s(15) = "18f07dec3adc4d2079ee5f3ed7cb3948"
	
	f i = 0 : 1 : 15 d
	.f j = 0 : 1 : 15 d
	..s s(i, j) = $e(s(i), 2 * j + 1, 2 * (j + 1))
	
	s rtn = ""
	f i = 0 : 1 : 3 d
	.s r = ..hex2int(a(2 * i))
	.s c = ..hex2int(a(2 * i + 1))
	.s rtn = rtn _ s(r, c)
	
	return rtn
}

/// 线性变换L
/// 非线性变换τ的输出是线性变换L的输入.设输入为B,输出为C.
/// C=L(B)=B^(B<<2)^B(<<10)^B(<<18)^B(<<24)
ClassMethod L(b)
{
	s rtn = ""
	
	s rtn = ..HexXOR(..HexXOR(..HexXOR(..HexXOR(b ,..Hexleft(b, 2)), ..Hexleft(b, 10)), ..Hexleft(b, 18)), ..Hexleft(b, 24))

	return rtn
}

/// L'
/// L'(B)=B^(B<<13)^B(<<23)
ClassMethod L2(b)
{
	s rtn = ""
	
	s rtn = ..HexXOR(..HexXOR(b, ..Hexleft(b, 13)), ..Hexleft(b, 23))

	return rtn
}

/// 合成置换T
/// 是一个可逆变换,由非线性τ和线性变换L复合而成,即T(.)=L(τ(.)).
ClassMethod T(x)
{
	return ..L(..tau(x))
}

/// T'
/// 将合成置换T的线性变换L替换为L'
ClassMethod T2(x)
{
	return ..L2(..tau(x))
}

/// 消息填充
/// w ##class(Utility.SM4).s2hex("342622199009262982")
ClassMethod s2hex(msg)
{
	s len = $l(msg)
	s rtn = ""
	f i = 1 : 1 : len d
	.s num = $ascii($e(msg, i))
	.s hex = $ZHEX(num)
	.s rtn = rtn _ hex
	
	s k = 32 - ($l(rtn) # 32)
	f i = 1 : 1 : k d
	.s rtn = rtn _ "0"
	
	return rtn
}

/// 8位16进制异或
/// w ##class(Utility.SM4).HexXOR("9b977428", "e334500a")
ClassMethod HexXOR(a, b)
{
	s a = ..hex2b(a)
	s b = ..hex2b(b)
	
	s rtn = ""
	f i = 1 : 1 : 32 d
	.i $e(a, i) = $e(b, i) d
	..s rtn = rtn _ "0"
	.e  d
	..s rtn = rtn _ "1"
	
	s rtn = ..b2hex(rtn)
	return rtn
}

/// 8位16进制左移
/// w ##class(Utility.SM4).Hexleft("61610000","3")
ClassMethod Hexleft(a, k)
{
	s rtn = ""
	
	s a = ..hex2b(a)
	s k = k # 32
	s a1 = $e(a, k + 1, 32)
	s a2 = $e(a, 1, k)
	s rtn = a1 _ a2
	
	s rtn = ..b2hex(rtn)
	return rtn
}

/// 16进制转二进制
/// w ##class(Utility.SM4).hex2b("61610000")
ClassMethod hex2b(hex)
{
	s len = $l(hex)
	s rtn = ""
	f i = 1 : 1 : len d
	.s h = $e(hex, i)
	.i h = "0" d
	..s rtn = rtn _ "0000"
	.e  i h = "1" d
	..s rtn = rtn _ "0001"
	.e  i h = "2" d
	..s rtn = rtn _ "0010"
	.e  i h = "3" d
	..s rtn = rtn _ "0011"
	.e  i h = "4" d
	..s rtn = rtn _ "0100"
	.e  i h = "5" d
	..s rtn = rtn _ "0101"
	.e  i h = "6" d
	..s rtn = rtn _ "0110"
	.e  i h = "7" d
	..s rtn = rtn _ "0111"
	.e  i h = "8" d
	..s rtn = rtn _ "1000"
	.e  i h = "9" d
	..s rtn = rtn _ "1001"
	.e  i h = "a" d
	..s rtn = rtn _ "1010"
	.e  i h = "b" d
	..s rtn = rtn _ "1011"
	.e  i h = "c" d
	..s rtn = rtn _ "1100"
	.e  i h = "d" d
	..s rtn = rtn _ "1101"
	.e  i h = "e" d
	..s rtn = rtn _ "1110"
	.e  i h = "f" d
	..s rtn = rtn _ "1111"
	
	return rtn
}

/// 二进制转16进制
/// w ##class(Utility.SM4).b2hex("01100001011000010000000000000000")
ClassMethod b2hex(bit)
{
	s len = $l(bit)/4
	s rtn = ""
	f i = 1 : 1 : len d
	.s bs = $e(bit, 4 * (i - 1) + 1, 4 * i)
	.i bs = "0000" d
	..s rtn = rtn _ "0"
	.e  i bs = "0001" d
	..s rtn = rtn _ "1"
	.e  i bs = "0010" d
	..s rtn = rtn _ "2"
	.e  i bs = "0011" d
	..s rtn = rtn _ "3"
	.e  i bs = "0100" d
	..s rtn = rtn _ "4"
	.e  i bs = "0101" d
	..s rtn = rtn _ "5"
	.e  i bs = "0110" d
	..s rtn = rtn _ "6"
	.e  i bs = "0111" d
	..s rtn = rtn _ "7"
	.e  i bs = "1000" d
	..s rtn = rtn _ "8"
	.e  i bs = "1001" d
	..s rtn = rtn _ "9"
	.e  i bs = "1010" d
	..s rtn = rtn _ "a"
	.e  i bs = "1011" d
	..s rtn = rtn _ "b"
	.e  i bs = "1100" d
	..s rtn = rtn _ "c"
	.e  i bs = "1101" d
	..s rtn = rtn _ "d"
	.e  i bs = "1110" d
	..s rtn = rtn _ "e"
	.e  i bs = "1111" d
	..s rtn = rtn _ "f"
	
	return rtn
}

/// 16进制1位转十进制
/// w ##class(Utility.SM4).hex2int("")
ClassMethod hex2int(hex)
{
	s rtn = hex
	i rtn = "a" d
	.s rtn = 10
	e  i rtn = "b" d
	.s rtn = 11
	e  i rtn = "c" d
	.s rtn = 12
	e  i rtn = "d" d
	.s rtn = 13
	e  i rtn = "e" d
	.s rtn = 14
	e  i rtn = "f" d
	.s rtn = 15
		
	return rtn
}

/// 十六进制转字符
/// w ##class(Utility.SM4).hex2str("3334323632323139393030393236323938320000000000000000000000000000")
ClassMethod hex2str(msg)
{
	s len = $l(msg)/2
	s rtn = ""
	f i = 1 : 1 : len d
	.s hex = $e(msg, (i - 1) * 2 + 1 , i * 2)
	.s int = 16 * ..hex2int($e(hex, 1)) + ..hex2int($e(hex, 2))
	.s str = $char(int)
	.s rtn = rtn _ str
	
	return $p(rtn, $char(0))
}

}
0
0 575
文章 YuHao Wan · 十一月 1, 2022 4m read

0. 算法概述

SM3密码杂凑算法是中国国家密码管理局2010年公布的中国商用密码杂凑算法标准。该算法于2012年发布为密码行业标准(GM/T 0004-2012),2016年发布为国家密码杂凑算法标准(GB/T 32905-2016)。

SM3适用于商用密码应用中的数字签名和验证,是在[SHA-256]基础上改进实现的一种算法,其安全性和SHA-256相当。SM3和MD5的迭代过程类似,也采用Merkle-Damgard结构。消息分组长度为512位,摘要值长度为256位。

整个算法的执行过程可以概括成四个步骤:消息填充、消息扩展、迭代压缩、输出结果

1. 消息填充

SM3的消息扩展步骤是以512位的数据分组作为输入的。因此,我们需要在一开始就把数据长度填充至512位的倍数。具体步骤如下:

1、先填充一个“1”,后面加上k个“0”。其中k是满足(n+1+k) mod 512 = 448的最小正整数。

2、追加64位的数据长度。

消息填充

2. 消息分组扩展

将填充后的消息m′按512比特进行分组:m′ = B(0)B(1)...B(n−1) 其中n=(l+k+65)/512。

SM3的迭代压缩步骤没有直接使用数据分组进行运算,而是使用这个步骤产生的132个消息字。(一个消息字的长度为32位/4个字节/8个16进制数字)概括来说,先将一个512位数据分组划分为16个消息字,并且作为生成的132个消息字的前16个。再用这16个消息字递推生成剩余的116个消息字。

消息分组

3. 迭代压缩

SM3使用消息扩展得到的消息字进行迭代运算。

迭代运算

初值IV被放在A、B、C、D、E、F、G、H八个32位变量中,整个算法中最核心、也最复杂的地方就在于压缩函数。压缩函数将这八个变量进行64轮相同的计算。

压缩函数

4. 输出结果

将得到的A、B、C、D、E、F、G、H八个变量拼接输出,就是SM3算法的输出。

杂凑值输出

5. 附录

符号

常数与函数

6. Caché实现

/// SM3密码杂凑算法是中国国家密码管理局2010年公布的中国商用密码杂凑算法标准
/// 该算法于2012年发布为密码行业标准(GM/T 0004-2012),2016年发布为国家密码杂凑算法标准(GB/T 32905-2016)。
/// 对长度为l(l < 2^64)比特的消息m,SM3杂凑算法经过填充和迭代压缩,生成杂凑值,杂凑值长度为256比特。
Class Utility.SM3 Extends %RegisteredObject
{

/// Creator:    wyh
/// CreatDate:  2022-11-01
/// Description:SM3加密
/// Input:  	 msg:原文 
/// Output:     16进制密文
/// Debug: w ##class(Utility.SM3).Hashsm3("{""appId"":""60C90F3B796B41878B8D9C393E2B6329"",""nonceStr"":""1234567890"",""timestamp"":""60C90F3B796B41878B8D9C393E2B6329"",""version"":""V2.0.0""}F2D8D966CD3D47788449C19D5EF2081B")
ClassMethod Hashsm3(msg)
{
#;	初始值IV =7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e
	s V(0) = "01110011100000000001011001101111 01001001000101001011001010111001 00010111001001000100001011010111 11011010100010100000011000000000 10101001011011110011000010111100 00010110001100010011100010101010 11100011100011011110111001001101 10110000111110110000111001001110"
		
#;	1. 消息填充
	s m = ..s2m(msg)
	
#;	2. 消息分组
#;	将填充后的消息m′按512比特进行分组:m′ = B(0)B(1)...B(n−1)
#;	其中n=(l+k+65)/512。
	s n = $l(m)/512
	f i = 0 : 1 : n-1 d
	.s B(i) = $e(m, 512 * i + 1, 512 * (i + 1))
	
#;	3. 迭代压缩
#;	对m′按下列方式迭代:
#;	FOR i=0 TO n-1
#;		V(i+1) = CF(V(i),B(i))
#;	ENDFOR
#;	其中CF是压缩函数,V(0)为256比特初始值IV,B(i)为填充后的消息分组,迭代压缩的结果为V(n)。
	.s V(i+1) = ..CF(V(i) ,B(i))

#;	4. 杂凑输出
#;	ABCDEFGH = V(n)
#;	输出256比特的杂凑值y = ABCDEFGH。
	s rtn = ""
	f i = 1 : 1 : 8 d
	.s bit = $p(V(n), " ", i)
	.s num = ..bs2n(bit)
	.s hex = $ZHEX(num)
	.i $l(hex) < 8 d
	..f j = 1 : 1 : 8 - $l(hex)  d
	...s hex = "0" _ hex
	.s rtn = rtn _ hex
	
	s rtn = $zcvt(rtn, "L")
	return rtn
}

/// 1. 消息填充
/// 将填充后的消息m′按512比特进行分组:m′ = B(0)B(1)...B(n−1)
/// 其中n=(l+k+65)/512
ClassMethod s2m(msg)
{
	s len = $l(msg)
	s r = ""
	f i = 1 : 1 : len d
	.s num = $ascii($e(msg, i))
	.s bs = ..n2bs(num)
	.s r = r _ bs
	
	s rtn = r
	s rtn = rtn _ "1"
	
	s k = 512 - (64 + ($l(r) + 1)) # 512
	f i = 1 : 1 : k d
	.s rtn = rtn _ "0"
	
	s lenbs = ..n2bs($l(r))
	s t = 64 - $l(lenbs)
	f i = 1 : 1 : t d
	.s rtn = rtn _ "0"
	
	s rtn = rtn _ lenbs
	return rtn
}

/// 3. 迭代压缩
/// 令A,B,C,D,E,F,G,H为字寄存器,SS1,SS2,TT1,TT2为中间变量,压缩函数V(i+1) = CF(V(i),B(i)), 0<=i<=n-1。计算过程描述如下:
/// ABCDEFGH=V(i)
/// FOR j=0 TO 63
/// 	SS1 = ((A<<12) + E + (T(j)<<j))<<7
/// 	SS2 = SS1 ^	(A<<12)
/// 	TT1 = FF(j)(A,B,C) + D + SS2 +W′(j)
/// 	TT2 = GG(j)(E,F,G) + H + SS1 +W(j)
/// 	D = C
/// 	C = B<<9
/// 	B = A
/// 	A = TT1
/// 	H = G
/// 	G = F<<19
/// 	F = E
/// 	E = P0(TT2)
/// ENDFOR
/// V(i+1) = ABCDEFGH ^ V(i)
/// 其中,字的存储为大端(big-endian)格式。
ClassMethod CF(Vi, Bi)
{
	s A = $p(Vi," ",1), B = $p(Vi," ",2), C = $p(Vi," ",3), D = $p(Vi," ",4), E = $p(Vi," ",5), F = $p(Vi," ",6), G = $p(Vi," ",7), H = $p(Vi," ",8)

#;	常量
#;	T(j) = 79cc4519 0<=j<=15
#;		   7a879d8a 16<=j<=63
	f i = 0 : 1 : 15 d
	.s T(i) = "01111001110011000100010100011001"
	f i = 16 : 1 : 63 d
	.s T(i) = "01111010100001111001110110001010"
	
#;	3.1 消息扩展
#;	将消息分组B(i)按以下方法扩展生成132个字W(0),W(1),...,W(67),W′(0),W′(1),...,W′(63),用于压缩函数CF:
#;	a)将消息分组B(i)划分为16个字W(0),W(1),...,W(15)。
#;	b)FOR j=16 TO 67
#;		W(j) = P1(W(j−16)^W(j−9)^(W(j−3)≪15)) ^ (W(j−13)≪7) ^ W(j−6)
#;	  ENDFOR
#;	c)FOR j=0 TO 63
#;		W′(j) = W(j) ^ W(j+4)
#;	  ENDFOR
	f i = 0 : 1 : 15 d
	.s W(i) = $e(Bi, 32 * i + 1, 32 * (i + 1))
	f i = 16 : 1 : 67 d
	.s W(i) = ..XOR(..XOR(..P1(..XOR(..XOR(W(i-16), W(i-9)), ..rotateleft(W(i-3), 15))), ..rotateleft(W(i-13), 7)), W(i-6))
	f i = 0 : 1 : 63 d
	.s W2(i) = ..XOR(W(i), W(i+4))
	
	f i = 0 : 1 : 63 d
	.s SS1 = ..n232bs(..bs2n(..rotateleft(..n232bs((..bs2n(..rotateleft(A, 12)) + ..bs2n(E) + ..bs2n(..rotateleft(T(i), i))) # $zpower(2, 32)), 7)) # $zpower(2, 32))
	.s SS2 = ..n232bs(..bs2n(..XOR(SS1, ..rotateleft(A, 12))) # $zpower(2, 32))
	.s TT1 = ..n232bs((..bs2n(..FF(A, B, C, i)) + ..bs2n(D) + ..bs2n(SS2) + ..bs2n(W2(i))) # $zpower(2, 32))
	.s TT2 = ..n232bs((..bs2n(..GG(E, F, G, i)) + ..bs2n(H) + ..bs2n(SS1) +..bs2n(W(i))) # $zpower(2, 32))
	.s D = C
    .s C = ..rotateleft(B, 9)
    .s B = A
    .s A = TT1
    .s H = G
    .s G = ..rotateleft(F, 19)
    .s F = E
    .s E = ..P0(TT2)
    
    s A = ..XOR(A, $p(Vi," ",1))
    s B = ..XOR(B, $p(Vi," ",2))
    s C = ..XOR(C, $p(Vi," ",3))
    s D = ..XOR(D, $p(Vi," ",4))
    s E = ..XOR(E, $p(Vi," ",5))
    s F = ..XOR(F, $p(Vi," ",6))
    s G = ..XOR(G, $p(Vi," ",7))
    s H = ..XOR(H, $p(Vi," ",8))
    
    return A_" "_B_" "_C_" "_D_" "_E_" "_F_" "_G_" "_H
}

/// 布尔函数
/// FF(j)(X, Y, Z)= X ^ Y ^ Z 0<=j<=15
/// 			   (X & Y) | (X & Z) | (Y & Z) 16<=j<=63
ClassMethod FF(X, Y, Z, j)
{
	i j <= 15 d
	.s ret = ..XOR(..XOR(X, Y), Z)
	e  d
	.s ret = ..OR(..OR(..AND(X, Y), ..AND(X, Z)), ..AND(Y, Z))
	
	return ret
}

/// 布尔函数
/// GG(j)(X, Y, Z)= X ^ Y ^ Z 0<=j<=15
/// 			   (X & Y ) | (~X & Z) 16<=j<=63
ClassMethod GG(X, Y, Z, j)
{
	i j <= 15 d
	.s ret = ..XOR(..XOR(X, Y), Z)
	e  d
	.s ret = ..OR(..AND(X, Y), ..AND(..NOT(X), Z))
	
	return ret
}

/// 置换函数P0(X) = X ^ (X<<9) ^ (X<<17)
ClassMethod P0(X)
{
	return ..XOR(..XOR(X, ..rotateleft(X, 9)), ..rotateleft(X, 17))
}

/// 置换函数P1(X) = X ^ (X<<15) ^ (X<<23)
ClassMethod P1(X)
{
	return ..XOR(..XOR(X, ..rotateleft(X, 15)), ..rotateleft(X, 23))
}

/// 32比特循环左移k比特运算
ClassMethod rotateleft(a, k)
{
	s k = k # 32
	s a1 = $e(a, k + 1, 32)
	s a2 = $e(a, 1, k)
	return a1 _ a2
}

/// 32比特与运算
ClassMethod AND(a, b)
{
	s rtn = ""
	f i = 1 : 1 : 32 d
	.s bit = $e(a, i) && $e(b, i)
	.s rtn = rtn _ bit
	
	return rtn
}

/// 32比特或运算
ClassMethod OR(a, b)
{
	s rtn = ""
	f i = 1 : 1 : 32 d
	.s bit = $e(a, i) || $e(b, i)
	.s rtn = rtn _ bit
	
	return rtn
}

/// 32比特异或运算
ClassMethod XOR(a, b)
{
	s rtn = ""
	f i = 1 : 1 : 32 d
	.i $e(a, i) = $e(b, i) d
	..s rtn = rtn _ "0"
	.e  d
	..s rtn = rtn _ "1"
	
	return rtn
}

/// 32比特非运算
ClassMethod NOT(a)
{
	s rtn = ""
	f i = 1 : 1 : 32 d
	.i $e(a, i) = "0" d
	..s rtn = rtn _ "1"
	.e  d
	..s rtn = rtn _ "0"
	
	return rtn
}

/// 数字转二进制字符
ClassMethod n2bs(num)
{
	s bit = $factor(num)
	s count = $bitcount(bit)
	s bitstr = ""
 	f i = count : -1 : 1 {
  		s b = $bit(bit , i)
  		s bitstr = bitstr _ b
  	}
  	
 	s l = $l(bitstr,"00000000")
 	s bitstr = $p(bitstr ,"00000000", l)
 	
 	return bitstr
}

/// 数字转32位二进制字符
ClassMethod n232bs(num)
{
	s bit = $factor(num)
	s count = $bitcount(bit)
	s bitstr = ""
 	f i = count : -1 : 1 {
  		s b = $bit(bit , i)
  		s bitstr = bitstr _ b
  	}
  	
 	s l = $l(bitstr)
 	s bitstr = $e(bitstr ,* - 31, *)
 	
 	return bitstr
}

/// 二进制字符转数字
ClassMethod bs2n(bStr)
{
	s len = $l(bStr)
	s decimal = 0
	f i = len : -1 : 1 d
	.s bit = $e(bStr, i)
	.i bit = 1 d
	..s decimal = decimal + $zpower(2, len - i)
	
	return decimal
}

}

2
0 439
文章 Michael Lei · 六月 23, 2021 3m read

一位客户请求估计使用 cvencrypt 实用工具加密一个数据库需要多久。

这个问题有点像问一根绳子有多长 — 视情况而定。 但这是一个有趣的问题。 答案主要取决于客户使用的目标平台上的 CPU 和存储的性能,因此答案更关乎的是提出一个简单方法,可以在运行 cvencrypt 时使用该方法对 CPU 和存储进行基准测试。

0
0 154
问题 water huang · 四月 24, 2021

最近尝试使用 Set Ciphertext=##class(%SYSTEM.Encryption).RSAEncrypt(Plaintext,PublicKeyStr)来加密数据,但是加密失败,参考了以下资料https://community.intersystems.com/post/format-public-key-when-using-rs…

https://blog.ndpar.com/2017/04/17/p1-p8/

生成的公钥为

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvl8YRMOJMUOyK5NzWo+8FD8dG
R3DuPwn7M13If+rwYp18TEL58NneFdCL+Jjytx4axq+uhPuup5HtmEm22+PQTzFl
XuAhXf3oUm4LQl4zgSb14D6gfqac9DqbVhm+aUjDfItFapM35/DH2cvc+rbBhu4Q
5Y6kJwcUK0UbRv3swQIDAQAB
-----END PUBLIC KEY-----

转换为pkcs1后的内容为

2
0 217