关于security_huks安全模块的知识总结
关于鸿蒙安全模块的代码和内容相关的知识分享总结
1.代码相关
1.1 do{}while(0)
为什么需要do{}while(0)的写法?
在阅读源码时,我们常常会发现这样的书写结构:
do{
……
}while(0)
我们都知道这样写同样是执行内部的代码一次,与最普通的顺序往下写并无结果上的差异,那么为什么工程师们要设计这样的书写结构呢?
这里简单的介绍它的四个作用——当然它的写法肯定不是用来做循环的,而是为了提高代码的健壮性
1.1.1 规范宏定义,实现局部作用域
我们都知道#define是内容的直接替换,当宏定义部分较为复杂时,使用时我们就需要非常小心,比如以下情况:
# define ADD print();out();
int main(){
if(false)
ADD
return 0;
}
由于宏定义的直接替换,out()函数仍会被执行
那不是加上{}就可以了?
——一般的代码规范我们在结尾都会写上;
# define ADD {print();out();};
int main(){
if(false)
ADD
return 0;
}
这样写是没有问题的
——但加上else呢?很容易将;多加或者漏加导致编译的错误,所以很多宏定义中会使用do……while(0)将宏定义的模块进行包装来,保证宏定义的使用者能够无编译错误的使用宏
1.2.2 避免使用goto对程序流进行统一的控制
在很多函数中,return之前我们需要进行中间变量空间的free操作,goto能够很好的控制流程
int exmaple{
struct* ptr = malloc(……);
int ret = do(……);
if(ret){
goto END;
}
ret = doSomething(……);
if(ret){
goto END;
}
return 1;
END:
free(ptr);
return 0;
}
但是goto虽然好用(在鸿蒙的代码中也可见到少量的goto代码),但是不符合软件工程的结构化,会使得代码结构比较松散,不容易理解,我们可以使用do……while(0)来达到同样的效果
int exmaple{
struct* ptr = malloc(……);
do{
int ret = do(……);
if(ret){
break;
}
ret = doSomething(……);
if(ret){
break;
}
}while(0);
free(ptr);
return 0;
}
1.1.3 避免空宏引起的warning
内核中存在不同的架构,空宏的定义在所难免。但是空宏在编译时会warning,为了避免warning,可以使用do{}while(0)来定义空宏
1.1.4 定义一个单独的函数块来实现复杂的操作
当函数比较复杂,变量较多时,不想增加新函数,可以使用do{}while(0)将代码写在里面,里面可以定义变量而不用考虑变量名会同之前或之后的重复
1.2为什么需要lite版本?
Lite使用运行于移动端,有些设备资源非常有限,因此在内存和解析方面必须尽可能减少开销,所以需要轻量版的安全模块功能提供核心功能即可
2.安全相关
2.1 salt的定义
维基百科中对salt的定义如下:
在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。
2.2 为什么需要salt
我们知道数据库中存储的都是加密后的密文,典型的加密算法MD5和SHA都是用于明文的加密的。
验证的时候,通过将输入的数据进行算法加密再与库中数据进行对比,来判断一致性
这就是单向散列函数——为什么说是单向,因为密文无法被解密,我们只能生成而无法反向破解——但是唯一的明文对应唯一的密文,所以用于验证是非常有效的
这样即使数据库中数据泄露,由于都是无法可逆运算的密文,损失也不会太严重。
但是使用单向散列函数就一定安全了吗?
并不是。
如果有人对你的网络行为进行监听,收集了很多你的信息和密码,做成字典对其进行MD5或者SHA运算,然后进行对比,那么破解的可能性还是很大的
这时候就需要加点盐了
Salt 可以是任意字母、数字、或是字母或数字的组合,但必须是随机产生的,存储时就是数据+salt的组合进行存储
这样即使数据库泄露,由于salt的随机性,添加的位置、顺序也可以进行灵活设计,密码被破解的概率也会大大降低
2.3 根据hks_type.h总结的各种算法和模式的类型
- 密钥类型分为公钥和私钥
- 按照算法和模式分类,密钥又分为:
RSA 支持变长密钥的公共密钥算法的密钥
ECC系列 椭圆曲线密码编码密钥
ED25519 数字签名算法密钥
X25519 密钥协商算法密钥
AES 对称密钥
CHACHA20系列 :
ChaCha系列流密码,作为salsa密码的改良版,具有更强的抵抗密码分析攻击的特性,“20”表示该算法有20轮的加密计算所需的密钥
HMAC 利用密码学中的散列函数来进行消息认证的机制所需的密钥
HKDF
密钥派生函数(KDF)是密码系统的基本组成部分。它的目标是获取一些初始的密钥材料,并从中派生出一个或多个安全强度很大的密钥。
基于HMAC的KDF,称之为HKDF,它可以应用于各种协议和应用程序的构建。HKDF在逻辑上由两个部分组成。第一个部分采用输入密钥材料和“提取”,它是一个固定长度的伪随机密钥K。第二部分则将密钥扩展为几个随机密钥,并以我们需要的长度输出
PBKDF2 将salted hash进行多次重复计算得到的密钥
- 密钥的功能:
加密
解密
数字签名
消息认证
WRAP 封装加密
UNWRAP 拆分解密
MAC信息摘要认证
- 生成摘要的方法:
单向散列函数
MD5
SHA224 SHA256 SHA384 SHA512
- Padding填充方法
OAEP
PSS
PKCS1_V1_5
PKCS5
PKCS7
- 加密模式:
ECB
CBC
CTR
OFB
CCM
GCM
- 加解密算法:
RSA
ECC
AES
HMAC
HKDF
PBKDF2
ECDH
X25519
ED25519
这里简单介绍一下padding
2.4 为什么使用Padding
使用padding的目的:对于特定类型的信息来说,大量相同内容的密文部分是容易推测的比如书信的开头敬语:尊敬的,为了防止攻击,我们使用随机长度的padding对数据进行填充,防止攻击者知道长度,展开攻击
2.5 Padding的类型
这里根据鸿蒙安全模块中出现的填充类型进行一个简单的介绍
2.5.1 OAEP
输入:RSA_size(rsa) – 41
输出:和modulus(RSA钥模长)一样长
2.5.2 PSS
2.5.3 PKCS1_V1_5
填充的规则:
EM = 0x00 || 0x02 || PS || 0x00 || M
其中:
EM是填充后的消息
M是原文
PS是随机数,长度为Len(RSA) - 3 - Len(M)
2.5.4 PKCS5
将数据填充到8的倍数,填充后数据长度的计算公式是 定于元数据长度为x, 填充后的长度是 x + (8 - (x % 8)), 填充的数据是 8 - (x % 8),块大小固定为8字节
2.5.5 PKCS7
假设数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都是n;如果数据本身就已经对齐了,则填充一块长度为块大小的数据,每个字节都是块大小;PKCS5只填充到8字节,而PKCS7可以在1-255之间任意填充。
还有前面两篇专门的知识讲解的博客供参考:
鸿蒙安全模块理论知识——MAC,SHA ,hash算法,安全证书相关
加密算法理论概述