1. 密钥的重要性


我们还是先说故事。话说2006年有一个柳云龙的电视连续剧《暗算》分为三部曲《听风》、《看风》、《捕风》。很有意思的是三个故事里都有个“风”字。你看过风吗?我没看到,只看见树叶飘动,才知道风来过。风,来无影,去无踪,无孔不入,又无处不在。三部曲分别对应:侦听、破译和谍报。故事描述了老一辈情报人员(一群与风打交道的人),与敌斗智斗勇的故事,信仰的力量让他们无所畏惧、勇往直前,看得人荡气回肠,催人泪下。

由于平时很少看电视,去年正在为一个算法发愁,偶然看到这个剧,感同身受,便一口气看完了,里面一些对加密算法逻辑的一些看法,还是给了当时的我很大的启发,让我完成了当时的算法,还特意发了微博纪念。 个人比较喜欢《看风》破译密码这个章节,里面有句经典的台词:风是看不见的,破译密码就是看见了风,密码是兵器,是兵器中的暗器。


密码学有一个重要的产物——密钥。密钥作为信息在传播时用来加密的工具起着非常重要的作用。主流的六种密码技术,就是围绕密钥展开的:对称密码、非对称密码、单向散列函数、消息认证码、数字签名、伪随机数生成器。


送你一首小诗:

我画蓝江水悠悠,
爱晚亭上枫叶愁。
秋月溶溶照佛寺,
香烟袅袅绕经楼。

如果不告诉你这是首藏头诗,你还真的很难猜到唐伯虎对秋香的表白:“我爱秋香”。 藏头诗就是加密算法的一种。

由于西方文字是由字母组成,字母又是有序的字符集。所以在对文字加密时,密码算法很容易想到采用:替代密码、置换密码或替代与置换密码的组合,来完成完成信息的加密。公元前1世纪古罗马的凯撒密码,就是对文字中的字母,采用它在字母表中之后的第k个字母来代换,从而变成密文。在解密时,反向移动k个字母进行还原。

这个时代将密码发展到巅峰的,要算二战时期德军用机械实现的转轮机(RotorMachine)ENIGMA密码,很多的谍战片都是围绕这个机器展开的。

这个时期的密码存在很多的问题:

奥古斯特·柯克霍夫在19世纪提出了密码学上的柯克霍夫原则(Kerckhoffs’s principle)由:即使密码系统的任何细节已为人悉知,只要密钥(key)未泄漏,它也应是安全的。 这个原则指导了以后的密码学算法的发展。

香农在20世纪40年代末发表的一系列论文,特别是1949年的《保密系统通信理论》,把密码学推向了基于信息论的科学轨道。
这阶段的发展主要是对称加密算法。对称加密是发送方使用某种公开的算法使用密钥对明文进行加密,接收方使用之前发送方给予的密钥对密文进行解密得到明文。近代密码发展中一个重要突破是“数据加密标准”(DES)的出现。

公钥密码使得发送端和接收端无密钥传输的保密通信成为可能。

1976 年 Diffie 和 Hellman 的公钥密码的思想提出,标志着现代密码学的诞生。这是密码学发展史上具有里程碑意义的大事件,自此提出了许多种公钥密码体制 ,如基于分解大整数的困难性的密码体制——RSA 密码体制及其变种、基于离散对数问题的公钥密码体制。


影响密码系统安全性的基本因素:密码算法复杂度、密钥机密性、密钥长度。其中密钥机密性与主要与密钥的管理相关。如何保护好密钥的安全就成了信息安全的非常重要的一个部分。

在现在的应用系统中,密码、密钥往往被作为一种访问密钥(access key)或凭证(Credentials),用于系统之间建立链接,避免了用户密码的明文传输。很多时候访问密钥等同于密码。

例如我们熟悉的GitHub的访问密钥。当我们获得Github某个库的地址访问密钥,就可以在Windows的凭证管理或本地Git的凭证管理里添加这个访问密钥,本地git和远端的访问库地址就建立了信任链接,不再需要每次都输入密码。

但密钥本地化,也会导致密钥分散在代码、配置文件中。一旦缺乏对密钥的统一管理, 就容易导致密钥泄露。员工不慎将密钥泄漏到开源网站导致重要数据丢失事件时有发生。

2018年某酒店集团共140G约5亿条个人信息遭泄露,被发现泄露的信息在境外黑市中售卖。究其原因,是该集团对员工的安全意识缺乏足够的教育培训,导致开发人员在无意识的情况下将公司测试平台的账号密码发到 GitHub上,使得黑客下载了整个数据。

我们从Verizon(美国最大的有线通信和语音通信提供商),每年发布的《数据泄露调查报告(Data Breach Investigations Report(DBIR))》,来看下密码密钥在信息泄露中被黑客利用的情况。

2. 密码密钥硬编码的检查

接下来我们看下如何防范密码密钥在带码中由于硬编码导致的泄露。

先来看些如何鉴别密码密钥。


密钥的长度决定了密钥空间(keyspace),通常以位为单位。密钥空间越大,密钥被攻破的难度就越大。

密钥是由密钥空间的随机值构成。对于任意一个随机变量 X,它的熵定义如下:

H(X) = - sum_{x=1}^nP(x_i)log_2[P(x_i)]∑x=1nP(xi)log2[P(xi)]

变量的不确定性越大,熵也就越大,把它搞清楚所需要的信息量也就越大。

举例:数据data有六个值,分为别为:[a,b,c,a,b,a];

样本总个数是6,变量种类数3;分别为[a:3, b:2, c:1]

所以对应的pi分别为[a:1/2, b:1/3, c:1/6]

公式计算log以2为底数的pi的对数值,然后再乘以pi的负数,再计算其加和,得到的便是香农熵的值:1.4591479170272448。

/** *Baseonshannonentropyreturnbitsofentropyrepresentedinstring. * *@paramstrinputstring *@returnentropy */ publicstaticdoublegetShannonEntropy(Stringstr){ intnum=0; Map<Character,Integer>pi=newHashMap<Character,Integer>(); //countcharinstring charcx; for(intl=0;l<str.length(); l){ cx=str.charAt(l); if(pi.containsKey(cx)){ pi.put(cx,pi.get(cx) 1); }else{ pi.put(cx,1); }num=num 1; } doubleentropy=0.0; for(Map.Entry<Character,Integer>entry:pi.entrySet()){cx=entry.getKey(); doublep=(double)entry.getValue()/num; entropy=entropy p*(Math.log(p)/Math.log(2)); } return-entropy;}


对于密码密钥的硬编码检查可以采用静态分析工具来完成。工具的检查过程通常包含四个过程:输入文件准备、检查、过滤和报告输出。

密钥加密和密钥解密(密码密钥硬编码检查)(6)


分类的目的是为了更好的识别文件中的字符串常量,充分利用字符串常量的上下文关联,以便在分析中最大程度的减少误报。


在我们得到大量的变量名和字符串常量后,主要通过正则表达式匹配的方式完成目标的筛选。
由于检查密码密钥的种类和类型不同,可以通过配置文件来提高检查能力的可扩展性。

信息描述选项检查类型可分为:变量名、字符串常量、或两个都检查必选密码密钥的类型用于区分不同类型的密码密钥;同时用于告警时区分具体检测到的密码密钥类型必选正则表达式主要设定匹配的长度,每个字符的可选类型必选熵值的阈值用于精确的识别密码密钥的类型,降低误报可选

例如:


静态分析能很大程度上减少了人工审核的工作量,但由于检查模式的不确定性,也会带来不少的误报。误报会给用户在审核过程中带来很多的负面情绪,从而不愿继续使用工具。为了进一步降低误报,我们可以通过下面的方式来降低误报:


将经过过滤后的结果,输出告警,给出可能泄露的文件名和变量或可能为密码密钥的常量字符串位置,便于人工的排查。


,